Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / platform / pc32 / isa / sound / mad16.c
1 /*
2  * sound/mad16.c
3  * 
4  * Initialization code for OPTi MAD16 compatible audio chips. Including
5  * 
6  * OPTi 82C928     MAD16           (replaced by C929) OAK OTI-601D    Mozart
7  * OPTi 82C929     MAD16 Pro
8  * 
9  * These audio interface chips don't prduce sound themselves. They just connect
10  * some other components (OPL-[234] and a WSS compatible codec) to the PC bus
11  * and perform I/O, DMA and IRQ address decoding. There is also a UART for
12  * the MPU-401 mode (not 82C928/Mozart). The Mozart chip appears to be
13  * compatible with the 82C928 (can anybody confirm this?).
14  * 
15  * NOTE! If you want to set CD-ROM address and/or joystick enable, define
16  * MAD16_CONF in local.h as combination of the following bits:
17  * 
18  * 0x01    - joystick disabled
19  * 
20  * CD-ROM type selection (select just one): 0x00    - none 0x02    - Sony 31A
21  * 0x04    - Mitsumi 0x06    - Panasonic (type "LaserMate", not
22  * "SoundBlaster") 0x08    - Secondary IDE (address 0x170) 0x0a    - Primary
23  * IDE (address 0x1F0)
24  * 
25  * For example Mitsumi with joystick disabled = 0x04|0x01 = 0x05 For example
26  * LaserMate (for use with sbpcd) plus joystick = 0x06
27  * 
28  * MAD16_CDSEL: This defaults to CD I/O 0x340, no IRQ and DMA3 (DMA5 with
29  * Mitsumi or IDE). If you like to change these, define MAD16_CDSEL with the
30  * following bits:
31  * 
32  * CD-ROM port: 0x00=340, 0x40=330, 0x80=360 or 0xc0=320 OPL4 select: 0x20=OPL4,
33  * 0x00=OPL3 CD-ROM irq: 0x00=disabled, 0x04=IRQ5, 0x08=IRQ7, 0x0a=IRQ3,
34  * 0x10=IRQ9, 0x14=IRQ10 and 0x18=IRQ11.
35  * 
36  * CD-ROM DMA (Sony or Panasonic): 0x00=DMA3, 0x01=DMA2, 0x02=DMA1 or
37  * 0x03=disabled or CD-ROM DMA (Mitsumi or IDE):    0x00=DMA5, 0x01=DMA6,
38  * 0x02=DMA7 or 0x03=disabled
39  * 
40  * For use with sbpcd, address 0x340, set MAD16_CDSEL to 0x03 or 0x23.
41  * 
42  * Copyright by Hannu Savolainen 1995
43  * 
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted provided that the following conditions are
46  * met: 1. Redistributions of source code must retain the above copyright
47  * notice, this list of conditions and the following disclaimer. 2.
48  * Redistributions in binary form must reproduce the above copyright notice,
49  * this list of conditions and the following disclaimer in the documentation
50  * and/or other materials provided with the distribution.
51  * 
52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
53  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
56  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
58  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
59  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  * 
64  */
65
66 #include <i386/isa/sound/sound_config.h>
67
68 #if defined(CONFIG_MAD16)
69
70 static int      already_initialized = 0;
71
72 #define C928    1
73 #define MOZART  2
74 #define C929    3
75
76 /*
77  * Registers
78  * 
79  * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations). All ports are
80  * inactive by default. They can be activated by writing 0xE2 or 0xE3 to the
81  * password register. The password is valid only until the next I/O read or
82  * write.
83  */
84
85 #define MC1_PORT        0xf8d   /* SB address, CDROM interface type, joystick */
86 #define MC2_PORT        0xf8e   /* CDROM address, IRQ, DMA, plus OPL4 bit */
87 #define MC3_PORT        0xf8f
88 #define PASSWD_REG      0xf8f
89 #define MC4_PORT        0xf90
90 #define MC5_PORT        0xf91
91 #define MC6_PORT        0xf92
92 #define MC7_PORT        0xf93
93
94 static int      board_type = C928;
95
96 static sound_os_info *mad16_osp;
97
98 #ifndef DDB
99 #define DDB(x)
100 #endif
101
102 static unsigned char
103 mad_read(int port)
104 {
105         unsigned long   flags;
106         unsigned char   tmp;
107
108         flags = splhigh();
109
110         switch (board_type) {   /* Output password */
111         case C928:
112         case MOZART:
113                 outb(PASSWD_REG, 0xE2);
114                 break;
115
116         case C929:
117                 outb(PASSWD_REG, 0xE3);
118                 break;
119         }
120
121         tmp = inb(port);
122         splx(flags);
123
124         return tmp;
125 }
126
127 static void
128 mad_write(int port, int value)
129 {
130         unsigned long   flags;
131
132         flags = splhigh();
133
134         switch (board_type) {   /* Output password */
135         case C928:
136         case MOZART:
137                 outb(PASSWD_REG, 0xE2);
138                 break;
139
140         case C929:
141                 outb(PASSWD_REG, 0xE3);
142                 break;
143         }
144
145         outb(port, (unsigned char) (value & 0xff));
146         splx(flags);
147 }
148
149 static int
150 detect_mad16(void)
151 {
152         unsigned char   tmp, tmp2;
153
154         /*
155          * Check that reading a register doesn't return bus float (0xff) when
156          * the card is accessed using password. This may fail in case the
157          * card is in low power mode. Normally at least the power saving mode
158          * bit should be 0.
159          */
160         if ((tmp = mad_read(MC1_PORT)) == 0xff) {
161                 DDB(printf("MC1_PORT returned 0xff\n"));
162                 return 0;
163         }
164         /*
165          * Now check that the gate is closed on first I/O after writing the
166          * password. (This is how a MAD16 compatible card works).
167          */
168
169         if ((tmp2 = inb(MC1_PORT)) == tmp) {    /* It didn't close */
170                 DDB(printf("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
171                 return 0;
172         }
173         mad_write(MC1_PORT, tmp ^ 0x80);        /* Togge a bit */
174
175         if ((tmp2 = mad_read(MC1_PORT)) != (tmp ^ 0x80)) {      /* Compare the bit */
176                 mad_write(MC1_PORT, tmp);       /* Restore */
177                 DDB(printf("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
178                 return 0;
179         }
180         mad_write(MC1_PORT, tmp);       /* Restore */
181         return 1;               /* Bingo */
182
183 }
184
185 int
186 probe_mad16(struct address_info * hw_config)
187 {
188         int             i;
189         static int      valid_ports[] =
190         {0x530, 0xe80, 0xf40, 0x604};
191         unsigned char   tmp;
192         unsigned char   cs4231_mode = 0;
193
194         int             ad_flags = 0;
195
196         if (already_initialized)
197                 return 0;
198
199         mad16_osp = hw_config->osp;
200         /*
201          * Check that all ports return 0xff (bus float) when no password is
202          * written to the password register.
203          */
204
205         DDB(printf("--- Detecting MAD16 / Mozart ---\n"));
206
207
208         /*
209          * Then try to detect with the old password
210          */
211         board_type = C928;
212
213         DDB(printf("Detect using password = 0xE2\n"));
214
215         if (!detect_mad16()) {  /* No luck. Try different model */
216                 board_type = C929;
217
218                 DDB(printf("Detect using password = 0xE3\n"));
219
220                 if (!detect_mad16())
221                         return 0;
222
223                 DDB(printf("mad16.c: 82C929 detected\n"));
224         } else {
225                 unsigned char   model;
226
227                 if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
228                         DDB(printf("mad16.c: Mozart detected\n"));
229                         board_type = MOZART;
230                 } else {
231                         DDB(printf("mad16.c: 82C928 detected???\n"));
232                         board_type = C928;
233                 }
234         }
235
236         for (i = 0xf8d; i <= 0xf93; i++)
237                 DDB(printf("port %03x = %03x\n", i, mad_read(i)));
238
239         /*
240          * Set the WSS address
241          */
242
243         tmp = 0x80;             /* Enable WSS, Disable SB */
244
245         for (i = 0; i < 5; i++) {
246                 if (i > 3) {    /* Not a valid port */
247                         printf("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
248                         return 0;
249                 }
250                 if (valid_ports[i] == hw_config->io_base) {
251                         tmp |= i << 4;  /* WSS port select bits */
252                         break;
253                 }
254         }
255
256         /*
257          * Set optional CD-ROM and joystick settings.
258          */
259
260 #ifdef MAD16_CONF
261         tmp |= ((MAD16_CONF) & 0x0f);   /* CD-ROM and joystick bits */
262 #endif
263         mad_write(MC1_PORT, tmp);
264
265 #if defined(MAD16_CONF) && defined(MAD16_CDSEL)
266         tmp = MAD16_CDSEL;
267 #else
268         tmp = 0x03;
269 #endif
270
271 #ifdef MAD16_OPL4
272         tmp |= 0x20;            /* Enable OPL4 access */
273 #endif
274
275         mad_write(MC2_PORT, tmp);
276         mad_write(MC3_PORT, 0xf0);      /* Disable SB */
277
278         if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
279                 return 0;
280
281         if (ad_flags & (AD_F_CS4231 | AD_F_CS4248))
282                 cs4231_mode = 0x02;     /* CS4248/CS4231 sync delay switch */
283
284         if (board_type == C929) {
285                 mad_write(MC4_PORT, 0xa2);
286                 mad_write(MC5_PORT, 0xA5 | cs4231_mode);
287                 mad_write(MC6_PORT, 0x03);      /* Disable MPU401 */
288         } else {
289                 mad_write(MC4_PORT, 0x02);
290                 mad_write(MC5_PORT, 0x30 | cs4231_mode);
291         }
292
293         for (i = 0xf8d; i <= 0xf93; i++)
294                 DDB(printf("port %03x after init = %03x\n", i, mad_read(i)));
295
296         /*
297          * Verify the WSS parameters
298          */
299
300         if (0) {
301                 printf("MSS: I/O port conflict\n");
302                 return 0;
303         }
304         /*
305          * Check if the IO port returns valid signature. The original MS
306          * Sound system returns 0x04 while some cards (AudioTriX Pro for
307          * example) return 0x00.
308          */
309
310         if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&
311             (inb(hw_config->io_base + 3) & 0x3f) != 0x00) {
312                 DDB(printf("No MSS signature detected on port 0x%x (0x%x)\n",
313                            hw_config->io_base, inb(hw_config->io_base + 3)));
314                 return 0;
315         }
316         if (hw_config->irq > 11) {
317                 printf("MSS: Bad IRQ %d\n", hw_config->irq);
318                 return 0;
319         }
320         if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) {
321                 printf("MSS: Bad DMA %d\n", hw_config->dma);
322                 return 0;
323         }
324         /*
325          * Check that DMA0 is not in use with a 8 bit board.
326          */
327
328         if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) {
329                 printf("MSS: Can't use DMA0 with a 8 bit card/slot\n");
330                 return 0;
331         }
332         if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) {
333                 printf("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
334                 return 0;
335         }
336         return 1;
337 }
338
339 void
340 attach_mad16(struct address_info * hw_config)
341 {
342
343         static char     interrupt_bits[12] =
344         {
345                 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
346         };
347         char            bits;
348
349         static char     dma_bits[4] =
350         {
351                 1, 2, 0, 3
352         };
353
354         int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
355         int             ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2;
356         unsigned char   dma2_bit = 0;
357
358         already_initialized = 1;
359
360         if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
361                 return;
362
363         /*
364          * Set the IRQ and DMA addresses.
365          */
366
367         bits = interrupt_bits[hw_config->irq];
368         if (bits == -1)
369                 return;
370
371         outb(config_port, bits | 0x40);
372         if ((inb(version_port) & 0x40) == 0)
373                 printf("[IRQ Conflict?]");
374
375         /*
376          * Handle the capture DMA channel
377          */
378
379         if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) {
380                 if ((dma == 0 && dma2 == 1) ||
381                     (dma == 1 && dma2 == 0) ||
382                     (dma == 3 && dma2 == 0)) {
383                         dma2_bit = 0x04;        /* Enable capture DMA */
384                 } else {
385                         printf("MAD16: Invalid capture DMA\n");
386                         dma2 = dma;
387                 }
388         } else
389                 dma2 = dma;
390
391         outb(config_port, bits | dma_bits[dma] | dma2_bit);     /* Write IRQ+DMA setup */
392
393         ad1848_init("MAD16 WSS", hw_config->io_base + 4,
394                     hw_config->irq,
395                     dma,
396                     dma2, 0,
397                     hw_config->osp);
398 }
399
400 void
401 attach_mad16_mpu(struct address_info * hw_config)
402 {
403         if (board_type < C929) {/* Early chip. No MPU support. Just SB MIDI */
404 #ifdef CONFIG_MIDI
405
406                 if (mad_read(MC1_PORT) & 0x20)
407                         hw_config->io_base = 0x240;
408                 else
409                         hw_config->io_base = 0x220;
410
411                 return mad16_sb_dsp_init(hw_config);
412 #else
413                 return 0;
414 #endif
415         }
416 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
417         if (!already_initialized)
418                 return;
419
420         attach_mpu401(hw_config);
421 #endif
422 }
423
424 int
425 probe_mad16_mpu(struct address_info * hw_config)
426 {
427 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
428         static int      mpu_attached = 0;
429         static int      valid_ports[] =
430         {0x330, 0x320, 0x310, 0x300};
431         static short    valid_irqs[] =
432         {9, 10, 5, 7};
433         unsigned char   tmp;
434
435         int             i;      /* A variable with secret power */
436
437         if (!already_initialized)       /* The MSS port must be initialized
438                                          * first */
439                 return 0;
440
441         if (mpu_attached)       /* Don't let them call this twice */
442                 return 0;
443         mpu_attached = 1;
444
445         if (board_type < C929) {/* Early chip. No MPU support. Just SB MIDI */
446
447 #ifdef CONFIG_MIDI
448                 unsigned char   tmp;
449
450                 tmp = mad_read(MC3_PORT);
451
452                 /*
453                  * MAD16 SB base is defined by the WSS base. It cannot be
454                  * changed alone. Ignore configured I/O base. Use the active
455                  * setting.
456                  */
457
458                 if (mad_read(MC1_PORT) & 0x20)
459                         hw_config->io_base = 0x240;
460                 else
461                         hw_config->io_base = 0x220;
462
463                 switch (hw_config->irq) {
464                 case 5:
465                         tmp = (tmp & 0x3f) | 0x80;
466                         break;
467                 case 7:
468                         tmp = (tmp & 0x3f);
469                         break;
470                 case 11:
471                         tmp = (tmp & 0x3f) | 0x40;
472                         break;
473                 default:
474                         printf("mad16/Mozart: Invalid MIDI IRQ\n");
475                         return 0;
476                 }
477
478                 mad_write(MC3_PORT, tmp | 0x04);
479                 return mad16_sb_dsp_detect(hw_config);
480 #else
481                 return 0;
482 #endif
483         }
484         tmp = 0x83;             /* MPU-401 enable */
485
486         /*
487          * Set the MPU base bits
488          */
489
490         for (i = 0; i < 5; i++) {
491                 if (i > 3) {    /* Out of array bounds */
492                         printf("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base);
493                         return 0;
494                 }
495                 if (valid_ports[i] == hw_config->io_base) {
496                         tmp |= i << 5;
497                         break;
498                 }
499         }
500
501         /*
502          * Set the MPU IRQ bits
503          */
504
505         for (i = 0; i < 5; i++) {
506                 if (i > 3) {    /* Out of array bounds */
507                         printf("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq);
508                         return 0;
509                 }
510                 if (valid_irqs[i] == hw_config->irq) {
511                         tmp |= i << 3;
512                         break;
513                 }
514         }
515         mad_write(MC6_PORT, tmp);       /* Write MPU401 config */
516
517         return probe_mpu401(hw_config);
518 #else
519         return 0;
520 #endif
521 }
522
523 /* That's all folks */
524 #endif