Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / dev / sound / isa / i386 / sscape / sscape.c
1 /*
2  * sound/sscape.c
3  * 
4  * Low level driver for Ensoniq Soundscape
5  * 
6  * Copyright by Hannu Savolainen 1994
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met: 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer. 2.
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  * 
28  * $FreeBSD: src/sys/i386/isa/sound/sscape.c,v 1.9 1999/12/20 18:05:01 eivind Exp $
29  * $DragonFly: src/sys/dev/sound/isa/i386/sscape/Attic/sscape.c,v 1.2 2003/06/17 04:28:38 dillon Exp $
30  */
31
32 #include <i386/isa/sound/sound_config.h>
33
34 #if NSSCAPE > 0
35
36 #include <i386/isa/sound/coproc.h>
37
38 #define EXCLUDE_NATIVE_PCM
39
40 /*
41  * I/O ports
42  */
43 #define MIDI_DATA        0
44 #define MIDI_CTRL        1
45 #define HOST_CTRL        2
46 #define TX_READY                0x02
47 #define RX_READY                0x01
48 #define HOST_DATA        3
49 #define ODIE_ADDR        4
50 #define ODIE_DATA        5
51
52 /*
53  * Indirect registers
54  */
55 #define GA_INTSTAT_REG   0
56 #define GA_INTENA_REG    1
57 #define GA_DMAA_REG      2
58 #define GA_DMAB_REG      3
59 #define GA_INTCFG_REG    4
60 #define GA_DMACFG_REG    5
61 #define GA_CDCFG_REG     6
62 #define GA_SMCFGA_REG    7
63 #define GA_SMCFGB_REG    8
64 #define GA_HMCTL_REG     9
65
66 /*
67  * DMA channel identifiers (A and B)
68  */
69 #define SSCAPE_DMA_A            0
70 #define SSCAPE_DMA_B            1
71
72 #define PORT(name)      (devc->base+name)
73
74 /*
75  * Host commands recognized by the OBP microcode
76  */
77 #define CMD_GEN_HOST_ACK        0x80
78 #define CMD_GEN_MPU_ACK         0x81
79 #define CMD_GET_BOARD_TYPE      0x82
80 #define CMD_SET_CONTROL         0x88
81 #define CMD_GET_CONTROL         0x89
82 #define         CTL_MASTER_VOL          0
83 #define         CTL_MIC_MODE            2
84 #define         CTL_SYNTH_VOL           4
85 #define         CTL_WAVE_VOL            7
86 #define CMD_SET_MT32            0x96
87 #define CMD_GET_MT32            0x97
88 #define CMD_SET_EXTMIDI         0x9b
89 #define CMD_GET_EXTMIDI         0x9c
90
91 #define CMD_ACK                 0x80
92
93 typedef struct sscape_info {
94         int             base, irq, dma;
95         int             ok;     /* Properly detected */
96         int             failed;
97         int             dma_allocated;
98         int             my_audiodev;
99         int             opened;
100         sound_os_info  *osp;
101 }
102
103                 sscape_info;
104 static struct sscape_info dev_info =
105 {0};
106 static struct sscape_info *devc = &dev_info;
107
108 static int     *sscape_sleeper = NULL;
109 static volatile struct snd_wait sscape_sleep_flag =
110 {0};
111
112 /* Some older cards have assigned interrupt bits differently than new ones */
113 static char     valid_interrupts_old[] =
114 {9, 7, 5, 15};
115
116 static char     valid_interrupts_new[] =
117 {9, 5, 7, 10};
118
119 static char    *valid_interrupts = valid_interrupts_new;
120
121 #ifdef REVEAL_SPEA
122 static char     old_hardware = 1;
123
124 #else
125 static char     old_hardware = 0;
126
127 #endif
128
129 static u_char
130 sscape_read(struct sscape_info * devc, int reg)
131 {
132         u_long   flags;
133         u_char   val;
134
135         flags = splhigh();
136         outb(PORT(ODIE_ADDR), reg);
137         val = inb(PORT(ODIE_DATA));
138         splx(flags);
139         return val;
140 }
141
142 static void
143 sscape_write(struct sscape_info * devc, int reg, int data)
144 {
145         u_long   flags;
146
147         flags = splhigh();
148         outb(PORT(ODIE_ADDR), reg);
149         outb(PORT(ODIE_DATA), data);
150         splx(flags);
151 }
152
153 static void
154 host_open(struct sscape_info * devc)
155 {
156         outb(PORT(HOST_CTRL), 0x00);    /* Put the board to the host mode */
157 }
158
159 static void
160 host_close(struct sscape_info * devc)
161 {
162         outb(PORT(HOST_CTRL), 0x03);    /* Put the board to the MIDI mode */
163 }
164
165 static int
166 host_write(struct sscape_info * devc, u_char *data, int count)
167 {
168         u_long   flags;
169         int             i, timeout_val;
170
171         flags = splhigh();
172
173         /*
174          * Send the command and data bytes
175          */
176
177         for (i = 0; i < count; i++) {
178                 for (timeout_val = 10000; timeout_val > 0; timeout_val--)
179                         if (inb(PORT(HOST_CTRL)) & TX_READY)
180                                 break;
181
182                 if (timeout_val <= 0) {
183                         splx(flags);
184                         return 0;
185                 }
186                 outb(PORT(HOST_DATA), data[i]);
187         }
188
189
190         splx(flags);
191
192         return 1;
193 }
194
195 static int
196 host_read(struct sscape_info * devc)
197 {
198         u_long   flags;
199         int             timeout_val;
200         u_char   data;
201
202         flags = splhigh();
203
204         /*
205          * Read a byte
206          */
207
208         for (timeout_val = 10000; timeout_val > 0; timeout_val--)
209                 if (inb(PORT(HOST_CTRL)) & RX_READY)
210                         break;
211
212         if (timeout_val <= 0) {
213                 splx(flags);
214                 return -1;
215         }
216         data = inb(PORT(HOST_DATA));
217
218         splx(flags);
219
220         return data;
221 }
222
223 static int
224 host_command1(struct sscape_info * devc, int cmd)
225 {
226         u_char   buf[10];
227
228         buf[0] = (u_char) (cmd & 0xff);
229
230         return host_write(devc, buf, 1);
231 }
232
233 static int
234 host_command2(struct sscape_info * devc, int cmd, int parm1)
235 {
236         u_char   buf[10];
237
238         buf[0] = (u_char) (cmd & 0xff);
239         buf[1] = (u_char) (parm1 & 0xff);
240
241         return host_write(devc, buf, 2);
242 }
243
244 static int
245 host_command3(struct sscape_info * devc, int cmd, int parm1, int parm2)
246 {
247         u_char   buf[10];
248
249         buf[0] = (u_char) (cmd & 0xff);
250         buf[1] = (u_char) (parm1 & 0xff);
251         buf[2] = (u_char) (parm2 & 0xff);
252
253         return host_write(devc, buf, 3);
254 }
255
256 static void
257 set_mt32(struct sscape_info * devc, int value)
258 {
259         host_open(devc);
260         host_command2(devc, CMD_SET_MT32,
261                       value ? 1 : 0);
262         if (host_read(devc) != CMD_ACK) {
263                 printf("SNDSCAPE: Setting MT32 mode failed\n");
264         }
265         host_close(devc);
266 }
267
268 static void
269 set_control(struct sscape_info * devc, int ctrl, int value)
270 {
271         host_open(devc);
272         host_command3(devc, CMD_SET_CONTROL, ctrl, value);
273         if (host_read(devc) != CMD_ACK) {
274                 printf("SNDSCAPE: Setting control (%d) failed\n", ctrl);
275         }
276         host_close(devc);
277 }
278
279 static int
280 get_board_type(struct sscape_info * devc)
281 {
282         int             tmp;
283
284         host_open(devc);
285         if (!host_command1(devc, CMD_GET_BOARD_TYPE))
286                 tmp = -1;
287         else
288                 tmp = host_read(devc);
289         host_close(devc);
290         return tmp;
291 }
292
293 void
294 sscapeintr(int irq)
295 {
296     u_char   bits, tmp;
297
298     bits = sscape_read(devc, GA_INTSTAT_REG);
299     DEB(printf("sscapeintr(0x%02x)\n", bits));
300     if ((sscape_sleep_flag.mode & WK_SLEEP)) {
301         sscape_sleep_flag.mode = WK_WAKEUP;
302         wakeup(sscape_sleeper);
303     }
304     if (bits & 0x02) {  /* Host interface interrupt */
305         printf("SSCAPE: Host interrupt, data=%02x\n", host_read(devc));
306     }
307 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
308     if (bits & 0x01) {
309         static int debug = 0;
310
311         mpuintr(irq);
312         if (debug++ > 10) {     /* Temporary debugging hack */
313             sscape_write(devc, GA_INTENA_REG, 0x00); /* Disable all interr. */
314         }
315     }
316 #endif
317
318     /*
319      * Acknowledge interrupts (toggle the interrupt bits)
320      */
321
322     tmp = sscape_read(devc, GA_INTENA_REG);
323     sscape_write(devc, GA_INTENA_REG, (~bits & 0x0e) | (tmp & 0xf1));
324 }
325
326
327 static void
328 do_dma(struct sscape_info * devc, int dma_chan, u_long buf, int blk_size, int mode)
329 {
330     u_char   temp;
331
332     if (dma_chan != SSCAPE_DMA_A) {
333         printf("SSCAPE: Tried to use DMA channel  != A. Why?\n");
334         return;
335     }
336     DMAbuf_start_dma(devc->my_audiodev, buf, blk_size, mode);
337
338     temp = devc->dma << 4;      /* Setup DMA channel select bits */
339     if (devc->dma <= 3)
340         temp |= 0x80;   /* 8 bit DMA channel */
341
342     temp |= 1;          /* Trigger DMA */
343     sscape_write(devc, GA_DMAA_REG, temp);
344     temp &= 0xfe;               /* Clear DMA trigger */
345     sscape_write(devc, GA_DMAA_REG, temp);
346 }
347
348 static int
349 verify_mpu(struct sscape_info * devc)
350 {
351     /*
352      * The SoundScape board could be in three modes (MPU, 8250 and host).
353      * If the card is not in the MPU mode, enabling the MPU driver will
354      * cause infinite loop (the driver believes that there is always some
355      * received data in the buffer.
356      * 
357      * Detect this by looking if there are more than 10 received MIDI bytes
358      * (0x00) in the buffer.
359      */
360
361     int             i;
362
363     for (i = 0; i < 10; i++) {
364         if (inb(devc->base + HOST_CTRL) & 0x80)
365             return 1;
366
367         if (inb(devc->base) != 0x00)
368             return 1;
369     }
370
371     printf("SoundScape: The device is not in the MPU-401 mode\n");
372     return 0;
373 }
374
375 static int
376 sscape_coproc_open(void *dev_info, int sub_device)
377 {
378     if (sub_device == COPR_MIDI) {
379         set_mt32(devc, 0);
380         if (!verify_mpu(devc))
381             return -(EIO);
382     }
383     sscape_sleep_flag.aborting = 0;
384     sscape_sleep_flag.mode = WK_NONE;
385     return 0;
386 }
387
388 static void
389 sscape_coproc_close(void *dev_info, int sub_device)
390 {
391     struct sscape_info *devc = dev_info;
392     u_long   flags;
393
394     flags = splhigh();
395     if (devc->dma_allocated) {
396         sscape_write(devc, GA_DMAA_REG, 0x20);  /* DMA channel disabled */
397 #ifdef CONFIG_NATIVE_PCM
398 #endif
399         devc->dma_allocated = 0;
400     }
401     sscape_sleep_flag.aborting = 0;
402     sscape_sleep_flag.mode = WK_NONE;
403     splx(flags);
404
405     return;
406 }
407
408 static void
409 sscape_coproc_reset(void *dev_info)
410 {
411 }
412
413 static int
414 sscape_download_boot(struct sscape_info * devc, u_char *block, int size, int flag)
415 {
416     u_long   flags;
417     u_char   temp;
418     int             done, timeout_val;
419
420     if (flag & CPF_FIRST) {
421         /*
422          * First block. Have to allocate DMA and to reset the board
423          * before continuing.
424          */
425
426         flags = splhigh();
427         if (devc->dma_allocated == 0) {
428             devc->dma_allocated = 1;
429         }
430         splx(flags);
431
432         sscape_write(devc, GA_HMCTL_REG,
433            (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f);    /* Reset */
434
435         for (timeout_val = 10000; timeout_val > 0; timeout_val--)
436             sscape_read(devc, GA_HMCTL_REG);    /* Delay */
437
438         /* Take board out of reset */
439         sscape_write(devc, GA_HMCTL_REG,
440                    (temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80);
441     }
442     /*
443      * Transfer one code block using DMA
444      */
445     bcopy(block, audio_devs[devc->my_audiodev]->dmap_out->raw_buf, size);
446
447     flags = splhigh();
448     /******** INTERRUPTS DISABLED NOW ********/
449     do_dma(devc, SSCAPE_DMA_A,
450                audio_devs[devc->my_audiodev]->dmap_out->raw_buf_phys,
451                size, 1);
452
453     /*
454      * Wait until transfer completes.
455      */
456     sscape_sleep_flag.aborting = 0;
457     sscape_sleep_flag.mode = WK_NONE;
458     done = 0;
459     timeout_val = 100;
460     while (!done && timeout_val-- > 0) {
461         int   chn;
462         sscape_sleeper = &chn;
463         DO_SLEEP(chn, sscape_sleep_flag, 1);
464
465         done = 1;
466     }
467
468     splx(flags);
469     if (!done)
470         return 0;
471
472     if (flag & CPF_LAST) {
473         /*
474          * Take the board out of reset
475          */
476         outb(PORT(HOST_CTRL), 0x00);
477         outb(PORT(MIDI_CTRL), 0x00);
478
479         temp = sscape_read(devc, GA_HMCTL_REG);
480         temp |= 0x40;
481         sscape_write(devc, GA_HMCTL_REG, temp); /* Kickstart the board */
482
483         /*
484          * Wait until the ODB wakes up
485          */
486
487         flags = splhigh();
488         done = 0;
489         timeout_val = 5 * hz;
490         while (!done && timeout_val-- > 0) {
491           int   chn;
492
493           sscape_sleeper = &chn;
494           DO_SLEEP(chn, sscape_sleep_flag, 1);
495
496           if (inb(PORT(HOST_DATA)) == 0xff)     /* OBP startup acknowledge */
497             done = 1;
498         }
499         splx(flags);
500         if (!done) {
501             printf("SoundScape: The OBP didn't respond after code download\n");
502             return 0;
503         }
504         flags = splhigh();
505         done = 0;
506         timeout_val = 5 * hz;
507         while (!done && timeout_val-- > 0) {
508           int   chn;
509
510           sscape_sleeper = &chn;
511           DO_SLEEP(chn, sscape_sleep_flag, 1);
512
513           if (inb(PORT(HOST_DATA)) == 0xfe)     /* Host startup acknowledge */
514             done = 1;
515         }
516         splx(flags);
517         if (!done) {
518             printf("SoundScape: OBP Initialization failed.\n");
519             return 0;
520         }
521         printf("SoundScape board of type %d initialized OK\n",
522                get_board_type(devc));
523
524         set_control(devc, CTL_MASTER_VOL, 100);
525         set_control(devc, CTL_SYNTH_VOL, 100);
526
527 #ifdef SSCAPE_DEBUG3
528         /*
529          * Temporary debugging aid. Print contents of the registers
530          * after downloading the code.
531          */
532         {
533             int             i;
534
535             for (i = 0; i < 13; i++)
536                 printf("I%d = %02x (new value)\n", i, sscape_read(devc, i));
537         }
538 #endif
539
540     }
541     return 1;
542 }
543
544 static int
545 download_boot_block(void *dev_info, copr_buffer * buf)
546 {
547     if (buf->len <= 0 || buf->len > sizeof(buf->data))
548         return -(EINVAL);
549
550     if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags)) {
551         printf("SSCAPE: Unable to load microcode block to the OBP.\n");
552         return -(EIO);
553     }
554     return 0;
555 }
556
557 static int
558 sscape_coproc_ioctl(void *dev_info, u_int cmd, ioctl_arg arg, int local)
559 {
560
561     switch (cmd) {
562     case SNDCTL_COPR_RESET:
563         sscape_coproc_reset(dev_info);
564         return 0;
565         break;
566
567     case SNDCTL_COPR_LOAD:
568         {
569             copr_buffer    *buf;
570             int             err;
571
572             buf = (copr_buffer *) malloc(sizeof(copr_buffer), M_TEMP, M_WAITOK);
573             if (buf == NULL)
574                 return -(ENOSPC);
575             bcopy(&(((char *) arg)[0]), (char *) buf, sizeof(*buf));
576             err = download_boot_block(dev_info, buf);
577             free(buf, M_TEMP);
578             return err;
579         }
580         break;
581
582     default:
583         return -(EINVAL);
584     }
585
586 }
587
588 static coproc_operations sscape_coproc_operations =
589 {
590         "SoundScape M68K",
591         sscape_coproc_open,
592         sscape_coproc_close,
593         sscape_coproc_ioctl,
594         sscape_coproc_reset,
595         &dev_info
596 };
597
598 #if !defined(EXCLUDE_NATIVE_PCM) && defined(CONFIG_AUDIO)
599 static struct audio_operations sscape_audio_operations =
600 {
601         "Not functional",
602         0,
603         AFMT_U8 | AFMT_S16_LE,
604         NULL,
605         sscape_audio_open,
606         sscape_audio_close,
607         sscape_audio_output_block,
608         sscape_audio_start_input,
609         sscape_audio_ioctl,
610         sscape_audio_prepare_for_input,
611         sscape_audio_prepare_for_output,
612         sscape_audio_reset,
613         sscape_audio_halt,
614         NULL,
615         NULL
616 };
617 #endif /* !defined(EXCLUDE_NATIVE_PCM) && defined(CONFIG_AUDIO) */
618
619 static int      sscape_detected = 0;
620
621 void
622 attach_sscape(struct address_info * hw_config)
623 {
624 #ifndef SSCAPE_REGS
625     /*
626      * Config register values for Spea/V7 Media FX and Ensoniq S-2000.
627      * These values are card dependent. If you have another SoundScape
628      * based card, you have to find the correct values. Do the following:
629      * - Compile this driver with SSCAPE_DEBUG1 defined. - Shut down and
630      * power off your machine. - Boot with DOS so that the SSINIT.EXE
631      * program is run. - Warm boot to {Linux|SYSV|BSD} and write down the
632      * lines displayed when detecting the SoundScape. - Modify the
633      * following list to use the values printed during boot. Undefine the
634      * SSCAPE_DEBUG1
635      */
636 #define SSCAPE_REGS { \
637 /* I0 */        0x00, \
638                 0xf0, /* Note! Ignored. Set always to 0xf0 */ \
639                 0x20, /* Note! Ignored. Set always to 0x20 */ \
640                 0x20, /* Note! Ignored. Set always to 0x20 */ \
641                 0xf5, /* Ignored */ \
642                 0x10, \
643                 0x00, \
644                 0x2e, /* I7 MEM config A. Likely to vary between models */ \
645                 0x00, /* I8 MEM config B. Likely to vary between models */ \
646 /* I9 */        0x40 /* Ignored */ \
647         }
648 #endif
649
650     u_long   flags;
651     static u_char regs[10] = SSCAPE_REGS;
652
653     int             i, irq_bits = 0xff;
654
655     if (sscape_detected != hw_config->io_base)
656         return;
657
658     if (old_hardware) {
659         valid_interrupts = valid_interrupts_old;
660         conf_printf("Ensoniq Soundscape (old)", hw_config);
661     } else
662         conf_printf("Ensoniq Soundscape", hw_config);
663
664     for (i = 0; i < sizeof(valid_interrupts); i++)
665         if (hw_config->irq == valid_interrupts[i]) {
666             irq_bits = i;
667             break;
668         }
669     if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) {
670         printf("Invalid IRQ%d\n", hw_config->irq);
671         return;
672     }
673     flags = splhigh();
674
675     for (i = 1; i < 10; i++)
676         switch (i) {
677         case 1: /* Host interrupt enable */
678             sscape_write(devc, i, 0xf0);        /* All interrupts enabled */
679             break;
680
681         case 2: /* DMA A status/trigger register */
682         case 3: /* DMA B status/trigger register */
683             sscape_write(devc, i, 0x20);        /* DMA channel disabled */
684             break;
685
686         case 4: /* Host interrupt config reg */
687             sscape_write(devc, i, 0xf0 | (irq_bits << 2) | irq_bits);
688             break;
689
690         case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */
691             sscape_write(devc, i, (regs[i] & 0x3f) |
692                          (sscape_read(devc, i) & 0xc0));
693             break;
694
695         case 6: /* CD-ROM config. Don't touch. */
696             break;
697
698         case 9: /* Master control reg. Don't modify CR-ROM
699                  * bits. Disable SB emul */
700             sscape_write(devc, i, (sscape_read(devc, i) & 0xf0) | 0x00);
701             break;
702
703         default:
704             sscape_write(devc, i, regs[i]);
705         }
706
707     splx(flags);
708
709 #ifdef SSCAPE_DEBUG2
710     /*
711      * Temporary debugging aid. Print contents of the registers after
712      * changing them.
713      */
714     {
715         int             i;
716
717         for (i = 0; i < 13; i++)
718             printf("I%d = %02x (new value)\n", i, sscape_read(devc, i));
719     }
720 #endif
721
722 #if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU)
723     if (probe_mpu401(hw_config))
724         hw_config->always_detect = 1;
725     {
726         int             prev_devs;
727
728         prev_devs = num_midis;
729         attach_mpu401(hw_config);
730
731         if (num_midis == (prev_devs + 1))       /* The MPU driver
732                                                  * installed itself */
733             midi_devs[prev_devs]->coproc = &sscape_coproc_operations;
734     }
735 #endif
736
737 #ifndef EXCLUDE_NATIVE_PCM
738     /* Not supported yet */
739
740 #ifdef CONFIG_AUDIO
741     if (num_audiodevs < MAX_AUDIO_DEV) {
742         int my_dev;
743
744         audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations;
745         audio_devs[my_dev]->dmachan1 = hw_config->dma;
746         audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
747         audio_devs[my_dev]->devc = devc;
748         devc->my_audiodev = my_dev;
749         devc->opened = 0;
750         audio_devs[my_dev]->coproc = &sscape_coproc_operations;
751         if (snd_set_irq_handler(hw_config->irq, sscapeintr, devc->osp) < 0)
752             printf("Error: Can't allocate IRQ for SoundScape\n");
753         sscape_write(devc, GA_INTENA_REG, 0x80);        /* Master IRQ enable */
754     } else
755         printf("SoundScape: More than enough audio devices detected\n");
756 #endif
757 #endif
758     devc->ok = 1;
759     devc->failed = 0;
760     return;
761 }
762
763 int
764 probe_sscape(struct address_info * hw_config)
765 {
766     u_char   save;
767
768     devc->failed = 1;
769     devc->base = hw_config->io_base;
770     devc->irq = hw_config->irq;
771     devc->dma = hw_config->dma;
772     devc->osp = hw_config->osp;
773
774     if (sscape_detected != 0 && sscape_detected != hw_config->io_base)
775         return 0;
776
777     /*
778      * First check that the address register of "ODIE" is there and that
779      * it has exactly 4 writeable bits. First 4 bits
780      */
781     if ((save = inb(PORT(ODIE_ADDR))) & 0xf0)
782         return 0;
783
784     outb(PORT(ODIE_ADDR), 0x00);
785     if (inb(PORT(ODIE_ADDR)) != 0x00)
786         return 0;
787
788     outb(PORT(ODIE_ADDR), 0xff);
789     if (inb(PORT(ODIE_ADDR)) != 0x0f)
790         return 0;
791
792     outb(PORT(ODIE_ADDR), save);
793
794     /*
795      * Now verify that some indirect registers return zero on some bits.
796      * This may break the driver with some future revisions of "ODIE"
797      * but...
798      */
799
800     if (sscape_read(devc, 0) & 0x0c)
801         return 0;
802
803     if (sscape_read(devc, 1) & 0x0f)
804         return 0;
805
806     if (sscape_read(devc, 5) & 0x0f)
807         return 0;
808
809 #ifdef SSCAPE_DEBUG1
810     /*
811      * Temporary debugging aid. Print contents of the registers before
812      * changing them.
813      */
814     {
815         int             i;
816
817         for (i = 0; i < 13; i++)
818             printf("I%d = %02x (old value)\n", i, sscape_read(devc, i));
819     }
820 #endif
821
822     if (old_hardware) { /* Check that it's really an old Spea/Reveal card. */
823         u_char   tmp;
824         int             cc;
825
826         if (!((tmp = sscape_read(devc, GA_HMCTL_REG)) & 0xc0)) {
827             sscape_write(devc, GA_HMCTL_REG, tmp | 0x80);
828             for (cc = 0; cc < 200000; ++cc)
829                 inb(devc->base + ODIE_ADDR);
830         } else
831             old_hardware = 0;
832     }
833     if (0) {
834         printf("sscape.c: Can't allocate DMA channel\n");
835         return 0;
836     }
837     sscape_detected = hw_config->io_base;
838
839     return 1;
840 }
841
842 int
843 probe_ss_mss(struct address_info * hw_config)
844 {
845     int             i, irq_bits = 0xff;
846
847     if (devc->failed)
848         return 0;
849
850     if (devc->ok == 0) {
851         printf("SoundScape: Invalid initialization order.\n");
852         return 0;
853     }
854     for (i = 0; i < sizeof(valid_interrupts); i++)
855         if (hw_config->irq == valid_interrupts[i]) {
856             irq_bits = i;
857             break;
858         }
859     if (hw_config->irq > 15 || irq_bits == 0xff) {
860         printf("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq);
861         return 0;
862     }
863     return ad1848_detect(hw_config->io_base, NULL, hw_config->osp);
864 }
865
866 void
867 attach_ss_mss(struct address_info * hw_config)
868 {
869     /*
870      * This routine configures the SoundScape card for use with the Win
871      * Sound System driver. The AD1848 codec interface uses the CD-ROM
872      * config registers of the "ODIE".
873      */
874
875     int             i, irq_bits = 0xff;
876
877 #ifndef CONFIG_NATIVE_PCM
878     int             prev_devs = num_audiodevs;
879 #endif
880
881     /*
882      * Setup the DMA polarity.
883      */
884     sscape_write(devc, GA_DMACFG_REG, 0x50);
885
886     /*
887      * Take the gate-arry off of the DMA channel.
888      */
889     sscape_write(devc, GA_DMAB_REG, 0x20);
890
891     /*
892      * Init the AD1848 (CD-ROM) config reg.
893      */
894
895     for (i = 0; i < sizeof(valid_interrupts); i++)
896         if (hw_config->irq == valid_interrupts[i]) {
897             irq_bits = i;
898             break;
899         }
900     sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) |
901              (irq_bits << 1));
902
903     if (hw_config->irq == devc->irq)
904         printf("SoundScape: Warning! WSS mode can't share IRQ with MIDI\n");
905
906     ad1848_init("SoundScape", hw_config->io_base,
907                     hw_config->irq,
908                     hw_config->dma,
909                     hw_config->dma,
910                     0,
911                     devc->osp);
912
913 #ifndef CONFIG_NATIVE_PCM
914     /* Check if the AD1848 driver installed itself */
915     if (num_audiodevs == (prev_devs + 1))
916         audio_devs[prev_devs]->coproc = &sscape_coproc_operations;
917 #endif
918
919     return;
920 }
921
922 #endif