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