source: GPL/alsa-kernel/pci/als4000.c@ 18

Last change on this file since 18 was 18, checked in by vladest, 20 years ago

initial import

File size: 27.1 KB
Line 
1/*
2 * card-als4000.c - driver for Avance Logic ALS4000 based soundcards.
3 * Copyright (C) 2000 by Bart Hartgers <bart@etpmod.phys.tue.nl>,
4 * Jaroslav Kysela <perex@suse.cz>
5 * Copyright (C) 2002 by Andreas Mohr <hw7oshyuv3001@sneakemail.com>
6 *
7 * Framework borrowed from Massimo Piccioni's card-als100.c.
8 *
9 * NOTES
10 *
11 * Since Avance does not provide any meaningful documentation, and I
12 * bought an ALS4000 based soundcard, I was forced to base this driver
13 * on reverse engineering.
14 *
15 * Note: this is no longer true. Pretty verbose chip docu (ALS4000a.PDF)
16 * can be found on the ALSA web site.
17 *
18 * The ALS4000 seems to be the PCI-cousin of the ALS100. It contains an
19 * ALS100-like SB DSP/mixer, an OPL3 synth, a MPU401 and a gameport
20 * interface. These subsystems can be mapped into ISA io-port space,
21 * using the PCI-interface. In addition, the PCI-bit provides DMA and IRQ
22 * services to the subsystems.
23 *
24 * While ALS4000 is very similar to a SoundBlaster, the differences in
25 * DMA and capturing require more changes to the SoundBlaster than
26 * desirable, so I made this separate driver.
27 *
28 * The ALS4000 can do real full duplex playback/capture.
29 *
30 * FMDAC:
31 * - 0x4f -> port 0x14
32 * - port 0x15 |= 1
33 *
34 * Enable/disable 3D sound:
35 * - 0x50 -> port 0x14
36 * - change bit 6 (0x40) of port 0x15
37 *
38 * Set QSound:
39 * - 0xdb -> port 0x14
40 * - set port 0x15:
41 * 0x3e (mode 3), 0x3c (mode 2), 0x3a (mode 1), 0x38 (mode 0)
42 *
43 * Set KSound:
44 * - value -> some port 0x0c0d
45 *
46 * This program is free software; you can redistribute it and/or modify
47 * it under the terms of the GNU General Public License as published by
48 * the Free Software Foundation; either version 2 of the License, or
49 * (at your option) any later version.
50 *
51 * This program is distributed in the hope that it will be useful,
52 * but WITHOUT ANY WARRANTY; without even the implied warranty of
53 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54 * GNU General Public License for more details.
55
56 * You should have received a copy of the GNU General Public License
57 * along with this program; if not, write to the Free Software
58 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
59 */
60
61#include <sound/driver.h>
62#include <sound/pcm.h>
63#include <sound/rawmidi.h>
64#include <sound/mpu401.h>
65#include <sound/opl3.h>
66#include <sound/sb.h>
67#define SNDRV_GET_ID
68#include <sound/initval.h>
69
70EXPORT_NO_SYMBOLS;
71MODULE_DESCRIPTION("Avance Logic ALS4000");
72MODULE_CLASSES("{sound}");
73MODULE_DEVICES("{{Avance Logic,ALS4000}}");
74
75static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
76static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
77static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
78static int joystick_port[SNDRV_CARDS] =
79#ifdef CONFIG_ISA
80{0x200}; /* enable as default */
81#else
82{0}; /* disabled */
83#endif
84
85MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
86MODULE_PARM_DESC(index, "Index value for ALS4000 soundcard.");
87MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
88MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
89MODULE_PARM_DESC(id, "ID string for ALS4000 soundcard.");
90MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
91MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
92MODULE_PARM_DESC(enable, "Enable ALS4000 soundcard.");
93MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC);
94MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
95MODULE_PARM_DESC(joystick_port, "Joystick port address for ALS4000 soundcard. (0 = disabled)");
96MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED);
97
98typedef struct {
99 struct pci_dev *pci;
100 unsigned long gcr;
101#ifdef SUPPORT_JOYSTICK
102 struct gameport gameport;
103 struct resource *res_joystick;
104#endif
105} snd_card_als4000_t;
106
107static struct pci_device_id snd_als4000_ids[] = {
108 { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */
109 { 0, }
110};
111
112MODULE_DEVICE_TABLE(pci, snd_als4000_ids);
113
114static inline void snd_als4000_gcr_write_addr(unsigned long port, u32 reg, u32 val)
115{
116 outb(reg, port+0x0c);
117 outl(val, port+0x08);
118}
119
120static inline void snd_als4000_gcr_write(sb_t *sb, u32 reg, u32 val)
121{
122 snd_als4000_gcr_write_addr(sb->alt_port, reg, val);
123}
124
125static inline u32 snd_als4000_gcr_read_addr(unsigned long port, u32 reg)
126{
127 outb(reg, port+0x0c);
128 return inl(port+0x08);
129}
130
131static inline u32 snd_als4000_gcr_read(sb_t *sb, u32 reg)
132{
133 return snd_als4000_gcr_read_addr(sb->alt_port, reg);
134}
135
136static void snd_als4000_set_rate(sb_t *chip, unsigned int rate)
137{
138 if (!(chip->mode & SB_RATE_LOCK)) {
139 snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_OUT);
140 snd_sbdsp_command(chip, rate>>8);
141 snd_sbdsp_command(chip, rate);
142 }
143}
144
145static void snd_als4000_set_capture_dma(sb_t *chip, dma_addr_t addr, unsigned size)
146{
147 snd_als4000_gcr_write(chip, 0xa2, addr);
148 snd_als4000_gcr_write(chip, 0xa3, (size-1));
149}
150
151static void snd_als4000_set_playback_dma(sb_t *chip, dma_addr_t addr, unsigned size)
152{
153 snd_als4000_gcr_write(chip, 0x91, addr);
154 snd_als4000_gcr_write(chip, 0x92, (size-1)|0x180000);
155}
156
157#define ALS4000_FORMAT_SIGNED (1<<0)
158#define ALS4000_FORMAT_16BIT (1<<1)
159#define ALS4000_FORMAT_STEREO (1<<2)
160
161static int snd_als4000_get_format(snd_pcm_runtime_t *runtime)
162{
163 int result;
164
165 result = 0;
166 if (snd_pcm_format_signed(runtime->format))
167 result |= ALS4000_FORMAT_SIGNED;
168 if (snd_pcm_format_physical_width(runtime->format) == 16)
169 result |= ALS4000_FORMAT_16BIT;
170 if (runtime->channels > 1)
171 result |= ALS4000_FORMAT_STEREO;
172 return result;
173}
174
175/* structure for setting up playback */
176static struct {
177 unsigned char dsp_cmd, dma_on, dma_off, format;
178} playback_cmd_vals[]={
179 /* ALS4000_FORMAT_U8_MONO */
180 { SB_DSP4_OUT8_AI, SB_DSP_DMA8_ON, SB_DSP_DMA8_OFF, SB_DSP4_MODE_UNS_MONO },
181 /* ALS4000_FORMAT_S8_MONO */
182 { SB_DSP4_OUT8_AI, SB_DSP_DMA8_ON, SB_DSP_DMA8_OFF, SB_DSP4_MODE_SIGN_MONO },
183 /* ALS4000_FORMAT_U16L_MONO */
184 { SB_DSP4_OUT16_AI, SB_DSP_DMA16_ON, SB_DSP_DMA16_OFF, SB_DSP4_MODE_UNS_MONO },
185 /* ALS4000_FORMAT_S16L_MONO */
186 { SB_DSP4_OUT16_AI, SB_DSP_DMA16_ON, SB_DSP_DMA16_OFF, SB_DSP4_MODE_SIGN_MONO },
187 /* ALS4000_FORMAT_U8_STEREO */
188 { SB_DSP4_OUT8_AI, SB_DSP_DMA8_ON, SB_DSP_DMA8_OFF, SB_DSP4_MODE_UNS_STEREO },
189 /* ALS4000_FORMAT_S8_STEREO */
190 { SB_DSP4_OUT8_AI, SB_DSP_DMA8_ON, SB_DSP_DMA8_OFF, SB_DSP4_MODE_SIGN_STEREO },
191 /* ALS4000_FORMAT_U16L_STEREO */
192 { SB_DSP4_OUT16_AI, SB_DSP_DMA16_ON, SB_DSP_DMA16_OFF, SB_DSP4_MODE_UNS_STEREO },
193 /* ALS4000_FORMAT_S16L_STEREO */
194 { SB_DSP4_OUT16_AI, SB_DSP_DMA16_ON, SB_DSP_DMA16_OFF, SB_DSP4_MODE_SIGN_STEREO },
195};
196#define playback_cmd(chip) (playback_cmd_vals[(chip)->playback_format])
197
198/* structure for setting up capture */
199enum { CMD_WIDTH8=0x04, CMD_SIGNED=0x10, CMD_MONO=0x80, CMD_STEREO=0xA0 };
200static unsigned char capture_cmd_vals[]=
201{
202 CMD_WIDTH8|CMD_MONO, /* ALS4000_FORMAT_U8_MONO */
203 CMD_WIDTH8|CMD_SIGNED|CMD_MONO, /* ALS4000_FORMAT_S8_MONO */
204 CMD_MONO, /* ALS4000_FORMAT_U16L_MONO */
205 CMD_SIGNED|CMD_MONO, /* ALS4000_FORMAT_S16L_MONO */
206 CMD_WIDTH8|CMD_STEREO, /* ALS4000_FORMAT_U8_STEREO */
207 CMD_WIDTH8|CMD_SIGNED|CMD_STEREO, /* ALS4000_FORMAT_S8_STEREO */
208 CMD_STEREO, /* ALS4000_FORMAT_U16L_STEREO */
209 CMD_SIGNED|CMD_STEREO, /* ALS4000_FORMAT_S16L_STEREO */
210};
211#define capture_cmd(chip) (capture_cmd_vals[(chip)->capture_format])
212
213static int snd_als4000_hw_params(snd_pcm_substream_t * substream,
214 snd_pcm_hw_params_t * hw_params)
215{
216 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
217}
218
219static int snd_als4000_hw_free(snd_pcm_substream_t * substream)
220{
221 snd_pcm_lib_free_pages(substream);
222 return 0;
223}
224
225static int snd_als4000_capture_prepare(snd_pcm_substream_t * substream)
226{
227 unsigned long flags;
228 sb_t *chip = snd_pcm_substream_chip(substream);
229 snd_pcm_runtime_t *runtime = substream->runtime;
230 unsigned long size;
231 unsigned count;
232
233 chip->capture_format = snd_als4000_get_format(runtime);
234
235 size = snd_pcm_lib_buffer_bytes(substream);
236 count = snd_pcm_lib_period_bytes(substream);
237
238 if (chip->capture_format & ALS4000_FORMAT_16BIT)
239 count >>=1;
240 count--;
241
242 spin_lock_irqsave(&chip->reg_lock, flags);
243 snd_als4000_set_rate(chip, runtime->rate);
244 snd_als4000_set_capture_dma(chip, runtime->dma_addr, size);
245 spin_unlock_irqrestore(&chip->reg_lock, flags);
246 spin_lock_irqsave(&chip->mixer_lock, flags );
247 snd_sbmixer_write(chip, 0xdc, count);
248 snd_sbmixer_write(chip, 0xdd, count>>8);
249 spin_unlock_irqrestore(&chip->mixer_lock, flags );
250 return 0;
251}
252
253static int snd_als4000_playback_prepare(snd_pcm_substream_t *substream)
254{
255 unsigned long flags;
256 sb_t *chip = snd_pcm_substream_chip(substream);
257 snd_pcm_runtime_t *runtime = substream->runtime;
258 unsigned long size;
259 unsigned count;
260
261 chip->playback_format = snd_als4000_get_format(runtime);
262
263 size = snd_pcm_lib_buffer_bytes(substream);
264 count = snd_pcm_lib_period_bytes(substream);
265
266 if (chip->playback_format & ALS4000_FORMAT_16BIT)
267 count >>=1;
268 count--;
269
270 /* FIXME: from second playback on, there's a lot more clicks and pops
271 * involved here than on first playback. Fiddling with
272 * tons of different settings didn't help (DMA, speaker on/off,
273 * reordering, ...). Something seems to get enabled on playback
274 * that I haven't found out how to disable again, which then causes
275 * the switching pops to reach the speakers the next time here. */
276 spin_lock_irqsave(&chip->reg_lock, flags);
277 snd_als4000_set_rate(chip, runtime->rate);
278 snd_als4000_set_playback_dma(chip, runtime->dma_addr, size);
279
280 /* SPEAKER_ON not needed, since dma_on seems to also enable speaker */
281 /* snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); */
282 snd_sbdsp_command(chip, playback_cmd(chip).dsp_cmd);
283 snd_sbdsp_command(chip, playback_cmd(chip).format);
284 snd_sbdsp_command(chip, count);
285 snd_sbdsp_command(chip, count>>8);
286 snd_sbdsp_command(chip, playback_cmd(chip).dma_off);
287 spin_unlock_irqrestore(&chip->reg_lock, flags);
288
289 return 0;
290}
291
292static int snd_als4000_capture_trigger(snd_pcm_substream_t * substream, int cmd)
293{
294 sb_t *chip = snd_pcm_substream_chip(substream);
295 int result = 0;
296
297 spin_lock(&chip->mixer_lock);
298 if (cmd == SNDRV_PCM_TRIGGER_START) {
299 chip->mode |= SB_RATE_LOCK_CAPTURE;
300 snd_sbmixer_write(chip, 0xde, capture_cmd(chip));
301 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
302 chip->mode &= ~SB_RATE_LOCK_CAPTURE;
303 snd_sbmixer_write(chip, 0xde, 0);
304 } else {
305 result = -EINVAL;
306 }
307 spin_unlock(&chip->mixer_lock);
308 return result;
309}
310
311static int snd_als4000_playback_trigger(snd_pcm_substream_t * substream, int cmd)
312{
313 sb_t *chip = snd_pcm_substream_chip(substream);
314 int result = 0;
315
316 spin_lock(&chip->reg_lock);
317 if (cmd == SNDRV_PCM_TRIGGER_START) {
318 chip->mode |= SB_RATE_LOCK_PLAYBACK;
319 snd_sbdsp_command(chip, playback_cmd(chip).dma_on);
320 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
321 snd_sbdsp_command(chip, playback_cmd(chip).dma_off);
322 chip->mode &= ~SB_RATE_LOCK_PLAYBACK;
323 } else {
324 result = -EINVAL;
325 }
326 spin_unlock(&chip->reg_lock);
327 return result;
328}
329
330static snd_pcm_uframes_t snd_als4000_capture_pointer(snd_pcm_substream_t * substream)
331{
332 sb_t *chip = snd_pcm_substream_chip(substream);
333 unsigned int result;
334
335 spin_lock(&chip->reg_lock);
336 result = snd_als4000_gcr_read(chip, 0xa4) & 0xffff;
337 spin_unlock(&chip->reg_lock);
338 return bytes_to_frames( substream->runtime, result );
339}
340
341static snd_pcm_uframes_t snd_als4000_playback_pointer(snd_pcm_substream_t * substream)
342{
343 sb_t *chip = snd_pcm_substream_chip(substream);
344 unsigned result;
345
346 spin_lock(&chip->reg_lock);
347 result = snd_als4000_gcr_read(chip, 0xa0) & 0xffff;
348 spin_unlock(&chip->reg_lock);
349 return bytes_to_frames( substream->runtime, result );
350}
351
352static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
353{
354 sb_t *chip = dev_id;
355 unsigned gcr_status;
356 unsigned sb_status;
357#ifdef TARGET_OS2
358 int fOurIrq = FALSE;
359#endif
360
361 /* find out which bit of the ALS4000 produced the interrupt */
362 gcr_status = inb(chip->alt_port + 0xe);
363
364#ifdef TARGET_OS2
365 if(gcr_status & (0x80|0x40|0x10)) fOurIrq = TRUE;
366#endif
367
368 if ((gcr_status & 0x80) && (chip->playback_substream)) /* playback */
369 snd_pcm_period_elapsed(chip->playback_substream);
370 if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */
371 snd_pcm_period_elapsed(chip->capture_substream);
372 if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */
373 snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
374 /* release the gcr */
375 outb(gcr_status, chip->alt_port + 0xe);
376
377 spin_lock(&chip->mixer_lock);
378 sb_status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
379 spin_unlock(&chip->mixer_lock);
380
381 if (sb_status & SB_IRQTYPE_8BIT)
382 snd_sb_ack_8bit(chip);
383 if (sb_status & SB_IRQTYPE_16BIT)
384 snd_sb_ack_16bit(chip);
385 if (sb_status & SB_IRQTYPE_MPUIN)
386 inb(chip->mpu_port);
387 if (sb_status & 0x20)
388 inb(SBP(chip, RESET));
389
390#ifdef TARGET_OS2
391 if (fOurIrq) {
392 eoi_irq(irq);
393 }
394#endif //TARGET_OS2
395 return IRQ_HANDLED;
396}
397
398/*****************************************************************/
399
400#ifdef TARGET_OS2
401static snd_pcm_hardware_t snd_als4000_playback =
402{
403 /* info: */ (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
404 SNDRV_PCM_INFO_MMAP_VALID),
405 /* formats: */ SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
406 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE, /* formats */
407 /* rates: */ SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
408 /* rate_min: */ 4000,
409 /* rate_max: */ 48000,
410 /* channels_min: */ 1,
411 /* channels_max: */ 2,
412 /* buffer_bytes_max: */ 65536,
413 /* period_bytes_min: */ 64,
414 /* period_bytes_max: */ 65536,
415 /* periods_min: */ 1,
416 /* periods_max: */ 1024,
417 /* fifo_size: */ 0
418};
419
420static snd_pcm_hardware_t snd_als4000_capture =
421{
422 /* info: */ (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
423 SNDRV_PCM_INFO_MMAP_VALID),
424 /* formats: */ SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
425 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE, /* formats */
426 /* rates: */ SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
427 /* rate_min: */ 4000,
428 /* rate_max: */ 48000,
429 /* channels_min: */ 1,
430 /* channels_max: */ 2,
431 /* buffer_bytes_max: */ 65536,
432 /* period_bytes_min: */ 64,
433 /* period_bytes_max: */ 65536,
434 /* periods_min: */ 1,
435 /* periods_max: */ 1024,
436 /* fifo_size: */ 0
437};
438#else
439static snd_pcm_hardware_t snd_als4000_playback =
440{
441info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
442 SNDRV_PCM_INFO_MMAP_VALID),
443 formats: SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
444 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE, /* formats */
445 rates: SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
446 rate_min: 4000,
447 rate_max: 48000,
448 channels_min: 1,
449 channels_max: 2,
450 buffer_bytes_max: 65536,
451 period_bytes_min: 64,
452 period_bytes_max: 65536,
453 periods_min: 1,
454 periods_max: 1024,
455 fifo_size: 0
456};
457
458static snd_pcm_hardware_t snd_als4000_capture =
459{
460info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
461 SNDRV_PCM_INFO_MMAP_VALID),
462 formats: SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
463 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE, /* formats */
464 rates: SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
465 rate_min: 4000,
466 rate_max: 48000,
467 channels_min: 1,
468 channels_max: 2,
469 buffer_bytes_max: 65536,
470 period_bytes_min: 64,
471 period_bytes_max: 65536,
472 periods_min: 1,
473 periods_max: 1024,
474 fifo_size: 0
475};
476#endif
477
478/*****************************************************************/
479
480static int snd_als4000_playback_open(snd_pcm_substream_t * substream)
481{
482 sb_t *chip = snd_pcm_substream_chip(substream);
483 snd_pcm_runtime_t *runtime = substream->runtime;
484
485 chip->playback_substream = substream;
486 runtime->hw = snd_als4000_playback;
487 return 0;
488}
489
490static int snd_als4000_playback_close(snd_pcm_substream_t * substream)
491{
492 sb_t *chip = snd_pcm_substream_chip(substream);
493
494 chip->playback_substream = NULL;
495 snd_pcm_lib_free_pages(substream);
496 return 0;
497}
498
499static int snd_als4000_capture_open(snd_pcm_substream_t * substream)
500{
501 sb_t *chip = snd_pcm_substream_chip(substream);
502 snd_pcm_runtime_t *runtime = substream->runtime;
503
504 chip->capture_substream = substream;
505 runtime->hw = snd_als4000_capture;
506 return 0;
507}
508
509static int snd_als4000_capture_close(snd_pcm_substream_t * substream)
510{
511 sb_t *chip = snd_pcm_substream_chip(substream);
512
513 chip->capture_substream = NULL;
514 snd_pcm_lib_free_pages(substream);
515 return 0;
516}
517
518/******************************************************************/
519
520#ifdef TARGET_OS2
521static snd_pcm_ops_t snd_als4000_playback_ops = {
522 snd_als4000_playback_open,
523 snd_als4000_playback_close,
524 snd_pcm_lib_ioctl,
525 snd_als4000_hw_params,
526 snd_als4000_hw_free,
527 snd_als4000_playback_prepare,
528 snd_als4000_playback_trigger,
529 snd_als4000_playback_pointer,0,0
530};
531
532static snd_pcm_ops_t snd_als4000_capture_ops = {
533 snd_als4000_capture_open,
534 snd_als4000_capture_close,
535 snd_pcm_lib_ioctl,
536 snd_als4000_hw_params,
537 snd_als4000_hw_free,
538 snd_als4000_capture_prepare,
539 snd_als4000_capture_trigger,
540 snd_als4000_capture_pointer,0,0
541};
542#else
543static snd_pcm_ops_t snd_als4000_playback_ops = {
544open: snd_als4000_playback_open,
545 close: snd_als4000_playback_close,
546 ioctl: snd_pcm_lib_ioctl,
547 hw_params: snd_als4000_hw_params,
548 hw_free: snd_als4000_hw_free,
549 prepare: snd_als4000_playback_prepare,
550 trigger: snd_als4000_playback_trigger,
551 pointer: snd_als4000_playback_pointer
552};
553
554static snd_pcm_ops_t snd_als4000_capture_ops = {
555open: snd_als4000_capture_open,
556 close: snd_als4000_capture_close,
557 ioctl: snd_pcm_lib_ioctl,
558 hw_params: snd_als4000_hw_params,
559 hw_free: snd_als4000_hw_free,
560 prepare: snd_als4000_capture_prepare,
561 trigger: snd_als4000_capture_trigger,
562 pointer: snd_als4000_capture_pointer
563};
564#endif
565
566static void snd_als4000_pcm_free(snd_pcm_t *pcm)
567{
568 sb_t *chip = pcm->private_data;
569 chip->pcm = NULL;
570 snd_pcm_lib_preallocate_free_for_all(pcm);
571}
572
573static int __devinit snd_als4000_pcm(sb_t *chip, int device)
574{
575 snd_pcm_t *pcm;
576 int err;
577
578 if ((err = snd_pcm_new(chip->card, "ALS4000 DSP", device, 1, 1, &pcm)) < 0)
579 return err;
580 pcm->private_free = snd_als4000_pcm_free;
581 pcm->private_data = chip;
582 pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
583 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_als4000_playback_ops);
584 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_als4000_capture_ops);
585
586 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
587 64*1024, 64*1024);
588
589 chip->pcm = pcm;
590
591 return 0;
592}
593
594/******************************************************************/
595
596static void __devinit snd_als4000_set_addr(unsigned long gcr,
597 unsigned int sb,
598 unsigned int mpu,
599 unsigned int opl,
600 unsigned int game)
601{
602 u32 confA = 0;
603 u32 confB = 0;
604
605 if (mpu > 0)
606 confB |= (mpu | 1) << 16;
607 if (sb > 0)
608 confB |= (sb | 1);
609 if (game > 0)
610 confA |= (game | 1) << 16;
611 if (opl > 0)
612 confA |= (opl | 1);
613 snd_als4000_gcr_write_addr(gcr, 0xa8, confA);
614 snd_als4000_gcr_write_addr(gcr, 0xa9, confB);
615}
616
617static void __devinit snd_als4000_configure(sb_t *chip)
618{
619 unsigned tmp;
620 int i;
621
622 /* do some more configuration */
623 spin_lock_irq(&chip->mixer_lock);
624 tmp = snd_sbmixer_read(chip, 0xc0);
625 snd_sbmixer_write(chip, 0xc0, tmp|0x80);
626 /* always select DMA channel 0, since we do not actually use DMA */
627 snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0);
628 snd_sbmixer_write(chip, 0xc0, tmp&0x7f);
629 spin_unlock_irq(&chip->mixer_lock);
630
631 spin_lock_irq(&chip->reg_lock);
632 /* magic number. Enables interrupts(?) */
633 snd_als4000_gcr_write(chip, 0x8c, 0x28000);
634 for(i = 0x91; i <= 0x96; ++i)
635 snd_als4000_gcr_write(chip, i, 0);
636
637 snd_als4000_gcr_write(chip, 0x99, snd_als4000_gcr_read(chip, 0x99));
638 spin_unlock_irq(&chip->reg_lock);
639}
640
641static void snd_card_als4000_free( snd_card_t *card )
642{
643 snd_card_als4000_t * acard = (snd_card_als4000_t *)card->private_data;
644 /* make sure that interrupts are disabled */
645 snd_als4000_gcr_write_addr( acard->gcr, 0x8c, 0);
646 /* free resources */
647#ifdef SUPPORT_JOYSTICK
648 if (acard->res_joystick) {
649 if (acard->gameport.io)
650 gameport_unregister_port(&acard->gameport);
651 snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */
652 release_resource(acard->res_joystick);
653 kfree_nocheck(acard->res_joystick);
654 }
655#endif
656 pci_release_regions(acard->pci);
657}
658
659static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
660 const struct pci_device_id *pci_id)
661{
662 static int dev;
663 snd_card_t *card;
664 snd_card_als4000_t *acard;
665 unsigned long gcr;
666 sb_t *chip;
667 opl3_t *opl3;
668 unsigned short word;
669 int err;
670
671 if (dev >= SNDRV_CARDS)
672 return -ENODEV;
673 if (!enable[dev]) {
674 dev++;
675 return -ENOENT;
676 }
677
678 /* enable PCI device */
679 if ((err = pci_enable_device(pci)) < 0) {
680 return err;
681 }
682 /* check, if we can restrict PCI DMA transfers to 24 bits */
683 if (!pci_dma_supported(pci, 0x00ffffff)) {
684 snd_printk("architecture does not support 24bit PCI busmaster DMA\n");
685 return -ENXIO;
686 }
687 pci_set_dma_mask(pci, 0x00ffffff);
688
689 if ((err = pci_request_regions(pci, "ALS4000")) < 0)
690 return err;
691 gcr = pci_resource_start(pci, 0);
692
693 pci_read_config_word(pci, PCI_COMMAND, &word);
694 pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO);
695 pci_set_master(pci);
696
697 /* disable all legacy ISA stuff except for joystick */
698 snd_als4000_set_addr(gcr, 0, 0, 0, joystick_port[dev]);
699
700 card = snd_card_new(index[dev], id[dev], THIS_MODULE,
701 sizeof( snd_card_als4000_t ) );
702 if (card == NULL) {
703 pci_release_regions(pci);
704 return -ENOMEM;
705 }
706
707 acard = (snd_card_als4000_t *)card->private_data;
708 acard->pci = pci;
709 acard->gcr = gcr;
710 card->private_free = snd_card_als4000_free;
711
712 if ((err = snd_sbdsp_create(card,
713 gcr + 0x10,
714 pci->irq,
715 snd_als4000_interrupt,
716 -1,
717 -1,
718 SB_HW_ALS4000,
719 &chip)) < 0) {
720 snd_card_free(card);
721 return err;
722 }
723
724 chip->pci = pci;
725 chip->alt_port = gcr;
726
727 snd_als4000_configure(chip);
728
729 if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000,
730 gcr+0x30, 1, pci->irq, 0,
731 &chip->rmidi)) < 0) {
732 snd_card_free(card);
733 snd_printk("no MPU-401device at 0x%lx ?\n", gcr+0x30);
734 return err;
735 }
736
737 if ((err = snd_als4000_pcm(chip, 0)) < 0) {
738 snd_card_free(card);
739 return err;
740 }
741 if ((err = snd_sbmixer_new(chip)) < 0) {
742 snd_card_free(card);
743 return err;
744 }
745
746 if (snd_opl3_create(card, gcr+0x10, gcr+0x12,
747 OPL3_HW_AUTO, 1, &opl3) < 0) {
748 snd_printk("no OPL device at 0x%lx-0x%lx ?\n",
749 gcr+0x10, gcr+0x12 );
750 } else {
751 if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
752 snd_card_free(card);
753 return err;
754 }
755 }
756
757 strcpy(card->driver, "ALS4000");
758 strcpy(card->shortname, "Avance Logic ALS4000");
759 sprintf(card->longname, "%s at 0x%lx, irq %i",
760 card->shortname, chip->alt_port, chip->irq);
761
762 if ((err = snd_card_register(card)) < 0) {
763 snd_card_free(card);
764 return err;
765 }
766 pci_set_drvdata(pci, card);
767 dev++;
768 return 0;
769}
770
771static void __devexit snd_card_als4000_remove(struct pci_dev *pci)
772{
773 snd_card_free(pci_get_drvdata(pci));
774 pci_set_drvdata(pci, NULL);
775}
776
777#ifdef TARGET_OS2
778static struct pci_driver driver = {
779 0,0,0,"ALS4000",
780 snd_als4000_ids,
781 snd_card_als4000_probe,
782 snd_card_als4000_remove,0,0
783};
784#else
785static struct pci_driver driver = {
786name: "ALS4000",
787 id_table: snd_als4000_ids,
788 probe: snd_card_als4k_probe,
789 remove: snd_card_als4k_remove,
790};
791#endif
792
793static int __init alsa_card_als4000_init(void)
794{
795 int err;
796
797 if ((err = pci_module_init(&driver)) < 0) {
798#ifdef MODULE
799 // snd_printk("no ALS4000 based soundcards found or device busy\n");
800#endif
801 return err;
802 }
803 return 0;
804}
805
806static void __exit alsa_card_als4000_exit(void)
807{
808 pci_unregister_driver(&driver);
809}
810
811module_init(alsa_card_als4000_init)
812module_exit(alsa_card_als4000_exit)
813
814#ifndef MODULE
815
816/* format is: snd-als4000=enable,index,id */
817
818static int __init alsa_card_als4000_setup(char *str)
819{
820 static unsigned __initdata nr_dev = 0;
821
822 if (nr_dev >= SNDRV_CARDS)
823 return 0;
824 (void)(get_option(&str,&enable[nr_dev]) == 2 &&
825 get_option(&str,&index[nr_dev]) == 2 &&
826 get_id(&str,&id[nr_dev]) == 2);
827 nr_dev++;
828 return 1;
829}
830
831__setup("snd-als4000=", alsa_card_als4000_setup);
832
833#endif /* ifndef MODULE */
Note: See TracBrowser for help on using the repository browser.