Initial import from FreeBSD RELENG_4:
[games.git] / sys / dev / sound / isa / i386 / trix / trix.c
1 /*
2  * sound/trix.c
3  * 
4  * Low level driver for the MediaTriX AudioTriX Pro (MT-0002-PC Control Chip)
5  * 
6  * Copyright by Hannu Savolainen 1995
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  */
29
30 #include <i386/isa/sound/sound_config.h>
31
32 #if NTRIX > 0
33
34 #ifdef INCLUDE_TRIX_BOOT
35 #include <i386/isa/sound/trix_boot.h>
36 #endif
37
38 #if (NSB > 0)
39 extern int      sb_no_recording;
40 #endif
41
42 static int      kilroy_was_here = 0;    /* Don't detect twice */
43 static int      sb_initialized = 0;
44
45 static sound_os_info *trix_osp = NULL;
46
47 static u_char
48 trix_read(int addr)
49 {
50     outb(0x390, (u_char) addr); /* MT-0002-PC ASIC address */
51     return inb(0x391);  /* MT-0002-PC ASIC data */
52 }
53
54 static void
55 trix_write(int addr, int data)
56 {
57     outb(0x390, (u_char) addr); /* MT-0002-PC ASIC address */
58     outb(0x391, (u_char) data); /* MT-0002-PC ASIC data */
59 }
60
61 static void
62 download_boot(int base)
63 {
64 #ifdef INCLUDE_TRIX_BOOT
65     int             i = 0, n = sizeof(trix_boot);
66
67     trix_write(0xf8, 0x00);     /* ??????? */
68     outb(base + 6, 0x01);       /* Clear the internal data pointer */
69     outb(base + 6, 0x00);       /* Restart */
70
71     /*
72      * Write the boot code to the RAM upload/download register. Each
73      * write increments the internal data pointer.
74      */
75     outb(base + 6, 0x01);       /* Clear the internal data pointer */
76     outb(0x390, 0x1A);  /* Select RAM download/upload port */
77
78     for (i = 0; i < n; i++)
79         outb(0x391, trix_boot[i]);
80     for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */
81         outb(0x391, 0x00);
82     outb(base + 6, 0x00);       /* Reset */
83     outb(0x390, 0x50);  /* ?????? */
84 #endif
85
86 }
87
88 static int
89 trix_set_wss_port(struct address_info * hw_config)
90 {
91     u_char   addr_bits;
92
93     if (0) {
94         printf("AudioTriX: Config port I/O conflict\n");
95         return 0;
96     }
97     if (kilroy_was_here)        /* Already initialized */
98         return 0;
99
100     if (trix_read(0x15) != 0x71) {      /* No asic signature */
101         DDB(printf("No AudioTriX ASIC signature found\n"));
102         return 0;
103     }
104
105     kilroy_was_here = 1;
106
107     /*
108      * Reset some registers.
109      */
110
111     trix_write(0x13, 0);
112     trix_write(0x14, 0);
113
114     /*
115      * Configure the ASIC to place the codec to the proper I/O location
116      */
117
118     switch (hw_config->io_base) {
119     case 0x530:
120         addr_bits = 0;
121         break;
122     case 0x604:
123         addr_bits = 1;
124         break;
125     case 0xE80:
126         addr_bits = 2;
127         break;
128     case 0xF40:
129         addr_bits = 3;
130         break;
131     default:
132         return 0;
133     }
134
135     trix_write(0x19, (trix_read(0x19) & 0x03) | addr_bits);
136     return 1;
137 }
138
139 /*
140  * Probe and attach routines for the Windows Sound System mode of AudioTriX
141  * Pro
142  */
143
144 int
145 probe_trix_wss(struct address_info * hw_config)
146 {
147     /*
148      * Check if the IO port returns valid signature. The original MS
149      * Sound system returns 0x04 while some cards (AudioTriX Pro for
150      * example) return 0x00.
151      */
152
153     if (0) {
154         printf("AudioTriX: MSS I/O port conflict\n");
155         return 0;
156     }
157     trix_osp = hw_config->osp;
158
159     if (!trix_set_wss_port(hw_config))
160         return 0;
161
162     if ((inb(hw_config->io_base + 3) & 0x3f) != 0x00) {
163         DDB(printf("No MSS signature detected on port 0x%x\n",
164                 hw_config->io_base));
165         return 0;
166     }
167     if (hw_config->irq > 11) {
168         printf("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq);
169         return 0;
170     }
171     if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) {
172         printf("AudioTriX: Bad WSS DMA %d\n", hw_config->dma);
173         return 0;
174     }
175     if (hw_config->dma2 != -1)
176         if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3) {
177             printf("AudioTriX: Bad capture DMA %d\n", hw_config->dma2);
178             return 0;
179         }
180     /*
181      * Check that DMA0 is not in use with a 8 bit board.
182      */
183
184     if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) {
185         printf("AudioTriX: Can't use DMA0 with a 8 bit card\n");
186         return 0;
187     }
188     if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) {
189         printf("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq);
190         return 0;
191     }
192     return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);
193 }
194
195 void
196 attach_trix_wss(struct address_info * hw_config)
197 {
198     static u_char interrupt_bits[12] =
199         {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
200     char            bits;
201
202     static u_char dma_bits[4] =
203         {1, 2, 0, 3};
204
205     int config_port = hw_config->io_base + 0,
206         version_port = hw_config->io_base + 3;
207     int dma1 = hw_config->dma, dma2 = hw_config->dma2;
208
209     trix_osp = hw_config->osp;
210
211     if (!kilroy_was_here) {
212         DDB(printf("AudioTriX: Attach called but not probed yet???\n"));
213         return ;
214     }
215     /*
216      * Set the IRQ and DMA addresses.
217      */
218
219     bits = interrupt_bits[hw_config->irq];
220     if (bits == -1) {
221         printf("AudioTriX: Bad IRQ (%d)\n", hw_config->irq);
222         return ;
223     }
224     outb(config_port, bits | 0x40);
225     if ((inb(version_port) & 0x40) == 0)
226         printf("[IRQ Conflict?]");
227
228     if (hw_config->dma2 == -1) {        /* Single DMA mode */
229         bits |= dma_bits[dma1];
230         dma2 = dma1;
231     } else {
232         u_char   tmp;
233
234         tmp = trix_read(0x13) & ~30;
235         trix_write(0x13, tmp | 0x80 | (dma1 << 4));
236
237         tmp = trix_read(0x14) & ~30;
238         trix_write(0x14, tmp | 0x80 | (dma2 << 4));
239     }
240
241     outb(config_port, bits);/* Write IRQ+DMA setup */
242
243     ad1848_init("AudioTriX Pro", hw_config->io_base + 4,
244         hw_config->irq,
245         dma1,
246         dma2,
247         0,
248         hw_config->osp);
249         return ;
250 }
251
252 int
253 probe_trix_sb(struct address_info * hw_config)
254 {
255     int             tmp;
256     u_char   conf;
257     static char     irq_translate[] = {-1, -1, -1, 0, 1, 2, -1, 3};
258
259 #ifndef INCLUDE_TRIX_BOOT
260     return 0;           /* No boot code -> no fun */
261 #endif
262     if (!kilroy_was_here)
263         return 0;       /* AudioTriX Pro has not been detected earlier */
264
265     if (sb_initialized)
266         return 0;
267
268     if ((hw_config->io_base & 0xffffff8f) != 0x200)
269         return 0;
270
271     tmp = hw_config->irq;
272     if (tmp > 7)
273         return 0;
274     if (irq_translate[tmp] == -1)
275         return 0;
276
277     tmp = hw_config->dma;
278     if (tmp != 1 && tmp != 3)
279         return 0;
280
281     conf = 0x84;                /* DMA and IRQ enable */
282     conf |= hw_config->io_base & 0x70;  /* I/O address bits */
283     conf |= irq_translate[hw_config->irq];
284     if (hw_config->dma == 3)
285         conf |= 0x08;
286     trix_write(0x1b, conf);
287
288     download_boot(hw_config->io_base);
289     sb_initialized = 1;
290
291     return 1;
292 }
293
294 void
295 attach_trix_sb(struct address_info * hw_config)
296 {
297 #if (NSB > 0)
298     sb_dsp_disable_midi();
299     sb_no_recording = 1;
300 #endif
301     conf_printf("AudioTriX (SB)", hw_config);
302 }
303
304 void
305 attach_trix_mpu(struct address_info * hw_config)
306 {
307 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
308     attach_mpu401(hw_config);
309 #endif
310 }
311
312 int
313 probe_trix_mpu(struct address_info * hw_config)
314 {
315 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
316     u_char   conf;
317     static char     irq_bits[] = {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5};
318
319     if (!kilroy_was_here) {
320         DDB(printf("Trix: WSS and SB modes must be initialized before MPU\n"));
321         return 0;       /* AudioTriX Pro has not been detected earlier */
322     }
323     if (!sb_initialized) {
324         DDB(printf("Trix: SB mode must be initialized before MPU\n"));
325         return 0;
326     }
327     if (mpu_initialized) {
328         DDB(printf("Trix: MPU mode already initialized\n"));
329         return 0;
330     }
331     if (hw_config->irq > 9) {
332         printf("AudioTriX: Bad MPU IRQ %d\n", hw_config->irq);
333         return 0;
334     }
335     if (irq_bits[hw_config->irq] == -1) {
336         printf("AudioTriX: Bad MPU IRQ %d\n", hw_config->irq);
337         return 0;
338     }
339     switch (hw_config->io_base) {
340     case 0x330:
341         conf = 0x00;
342         break;
343     case 0x370:
344         conf = 0x04;
345         break;
346     case 0x3b0:
347         conf = 0x08;
348         break;
349     case 0x3f0:
350         conf = 0x0c;
351         break;
352     default:
353         return 0;       /* Invalid port */
354     }
355
356     conf |= irq_bits[hw_config->irq] << 4;
357
358     trix_write(0x19, (trix_read(0x19) & 0x83) | conf);
359
360     mpu_initialized = 1;
361
362     return probe_mpu401(hw_config);
363 #else
364     return 0;
365 #endif
366 }
367
368 #endif