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