Remove redundant panic.
[dragonfly.git] / sys / dev / sound / isa / i386 / pas2 / pas2_card.c
1 /*
2  * sound/pas2_card.c
3  * 
4  * Detection routine for the Pro Audio Spectrum cards.
5  * 
6  * Copyright by Hannu Savolainen 1993
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 #include <i386/isa/sound/sound_config.h>
30
31 #if defined(CONFIG_PAS)
32 #define _PAS2_CARD_C_
33
34 #define DEFINE_TRANSLATIONS
35 #include <i386/isa/sound/pas_hw.h>
36
37 /*
38  * The Address Translation code is used to convert I/O register addresses to
39  * be relative to the given base -register
40  */
41
42 int             translat_code;
43 static int      pas_intr_mask = 0;
44 static int      pas_irq = 0;
45
46 static sound_os_info  *pas_osp;
47
48 char            pas_model;
49 static char    *pas_model_names[] =
50 {"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
51
52 /*
53  * pas_read() and pas_write() are equivalents of inb and outb
54  */
55 /*
56  * These routines perform the I/O address translation required
57  */
58 /*
59  * to support other than the default base address
60  */
61 extern void     mix_write(u_char data, int ioaddr);
62
63 u_char
64 pas_read(int ioaddr)
65 {
66         return inb(ioaddr ^ translat_code);
67 }
68
69 void
70 pas_write(u_char data, int ioaddr)
71 {
72         outb(ioaddr ^ translat_code, data);
73 }
74
75 static void
76 pas2_msg(char *foo)
77 {
78         printf("    PAS2: %s.\n", foo);
79 }
80
81 /******************* Begin of the Interrupt Handler ********************/
82
83 void
84 pasintr(int irq)
85 {
86         int             status;
87
88         status = pas_read(INTERRUPT_STATUS);
89         pas_write(status, INTERRUPT_STATUS);    /* Clear interrupt */
90
91         if (status & I_S_PCM_SAMPLE_BUFFER_IRQ) {
92 #ifdef CONFIG_AUDIO
93                 pas_pcm_interrupt(status, 1);
94 #endif
95                 status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ;
96         }
97         if (status & I_S_MIDI_IRQ) {
98 #ifdef CONFIG_MIDI
99                 pas_midi_interrupt();
100 #endif
101                 status &= ~I_S_MIDI_IRQ;
102         }
103 }
104
105 int
106 pas_set_intr(int mask)
107 {
108         if (!mask)
109                 return 0;
110
111         pas_intr_mask |= mask;
112
113         pas_write(pas_intr_mask, INTERRUPT_MASK);
114         return 0;
115 }
116
117 int
118 pas_remove_intr(int mask)
119 {
120         if (!mask)
121                 return 0;
122
123         pas_intr_mask &= ~mask;
124         pas_write(pas_intr_mask, INTERRUPT_MASK);
125
126         return 0;
127 }
128
129 /******************* End of the Interrupt handler **********************/
130
131 /******************* Begin of the Initialization Code ******************/
132
133 static int
134 config_pas_hw(struct address_info * hw_config)
135 {
136         char            ok = 1;
137         u_int        int_ptrs;  /* scsi/sound interrupt pointers */
138
139         pas_irq = hw_config->irq;
140
141         pas_write(0x00, INTERRUPT_MASK);
142
143         pas_write(0x36, SAMPLE_COUNTER_CONTROL);        /* Local timer control *
144                                                          * register */
145
146         pas_write(0x36, SAMPLE_RATE_TIMER);     /* Sample rate timer (16 bit) */
147         pas_write(0, SAMPLE_RATE_TIMER);
148
149         pas_write(0x74, SAMPLE_COUNTER_CONTROL);        /* Local timer control *
150                                                          * register */
151
152         pas_write(0x74, SAMPLE_BUFFER_COUNTER); /* Sample count register (16 *
153                                                  * bit) */
154         pas_write(0, SAMPLE_BUFFER_COUNTER);
155
156         pas_write(F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY);
157         pas_write(P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL);
158         pas_write(S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* | S_M_OPL3_DUAL_MONO */ , SERIAL_MIXER);
159
160         pas_write(I_C_1_BOOT_RESET_ENABLE
161 #ifdef PAS_JOYSTICK_ENABLE
162                   | I_C_1_JOYSTICK_ENABLE
163 #endif
164                   ,IO_CONFIGURATION_1);
165
166         if (pas_irq < 0 || pas_irq > 15) {
167                 printf("PAS2: Invalid IRQ %d", pas_irq);
168                 ok = 0;
169         } else {
170                 int_ptrs = pas_read(IO_CONFIGURATION_3);
171                 int_ptrs |= I_C_3_PCM_IRQ_translate[pas_irq] & 0xf;
172                 pas_write(int_ptrs, IO_CONFIGURATION_3);
173                 if (!I_C_3_PCM_IRQ_translate[pas_irq]) {
174                     printf("PAS2: Invalid IRQ %d", pas_irq);
175                     ok = 0;
176                 } else {
177                     if (snd_set_irq_handler(pas_irq, pasintr, hw_config->osp) < 0)
178                         ok = 0;
179                 }
180         }
181
182         if (hw_config->dma < 0 || hw_config->dma > 7) {
183                 printf("PAS2: Invalid DMA selection %d", hw_config->dma);
184                 ok = 0;
185         } else {
186                 pas_write(I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2);
187                 if (!I_C_2_PCM_DMA_translate[hw_config->dma]) {
188                         printf("PAS2: Invalid DMA selection %d", hw_config->dma);
189                         ok = 0;
190                 } else {
191                         if (0) {
192                                 printf("pas2_card.c: Can't allocate DMA channel\n");
193                                 ok = 0;
194                         }
195                 }
196         }
197
198         /*
199          * This fixes the timing problems of the PAS due to the Symphony
200          * chipset as per Media Vision.  Only define this if your PAS doesn't
201          * work correctly.
202          */
203 #ifdef SYMPHONY_PAS
204         outb(0xa8, 0x05);
205         outb(0xa9, 0x60);
206 #endif
207
208 #ifdef BROKEN_BUS_CLOCK
209         pas_write(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
210 #else
211         /*
212          * pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);
213          */
214         pas_write(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
215 #endif
216         pas_write(0x18, SYSTEM_CONFIGURATION_3);        /* ??? */
217
218         pas_write(F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY);   /* Sets mute off and *
219                                                                  * selects filter rate *
220                                                                  * of 17.897 kHz */
221         pas_write(8, PRESCALE_DIVIDER);
222
223         mix_write(P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
224         mix_write(5, PARALLEL_MIXER);
225
226 #if defined(CONFIG_SB_EMULATION) && defined(CONFIG_SB)
227
228         {
229                 struct address_info *sb_config;
230
231                 if ((sb_config = sound_getconf(SNDCARD_SB))) {
232                         u_char   irq_dma;
233
234                         /*
235                          * Turn on Sound Blaster compatibility
236                          */
237                         /*
238                          * bit 1 = SB emulation
239                          */
240                         /*
241                          * bit 0 = MPU401 emulation (CDPC only :-( )
242                          */
243                         pas_write(0x02, COMPATIBILITY_ENABLE);
244
245                         /*
246                          * "Emulation address"
247                          */
248                         pas_write((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
249
250                         if (!E_C_SB_DMA_translate[sb_config->dma])
251                                 printf("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
252                                        sb_config->dma);
253
254                         if (!E_C_SB_IRQ_translate[sb_config->irq])
255                                 printf("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
256                                        sb_config->irq);
257
258                         irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
259                                 E_C_SB_IRQ_translate[sb_config->irq];
260
261                         pas_write(irq_dma, EMULATION_CONFIGURATION);
262                 }
263         }
264 #else
265         pas_write(0x00, COMPATIBILITY_ENABLE);
266 #endif
267
268         if (!ok)
269                 pas2_msg("Driver not enabled");
270
271         return ok;
272 }
273
274 static int
275 detect_pas_hw(struct address_info * hw_config)
276 {
277         u_char   board_id, foo;
278
279         /*
280          * WARNING: Setting an option like W:1 or so that disables warm boot
281          * reset of the card will screw up this detect code something fierce.
282          * Adding code to handle this means possibly interfering with other
283          * cards on the bus if you have something on base port 0x388. SO be
284          * forewarned.
285          */
286
287         outb(MASTER_DECODE, 0xBC);      /* Talk to first board */
288         outb(MASTER_DECODE, hw_config->io_base >> 2);   /* Set base address */
289         translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base;
290         pas_write(1, WAIT_STATE);       /* One wait-state */
291
292         board_id = pas_read(INTERRUPT_MASK);
293
294         if (board_id == 0xff)
295                 return 0;
296
297         /*
298          * We probably have a PAS-series board, now check for a PAS2-series
299          * board by trying to change the board revision bits. PAS2-series
300          * hardware won't let you do this - the bits are read-only.
301          */
302
303         foo = board_id ^ 0xe0;
304
305         pas_write(foo, INTERRUPT_MASK);
306         foo = inb(INTERRUPT_MASK);
307         pas_write(board_id, INTERRUPT_MASK);
308
309         if (board_id != foo)    /* Not a PAS2 */
310                 return 0;
311
312         pas_model = pas_read(CHIP_REV);
313
314         return pas_model;
315 }
316
317 void
318 attach_pas_card(struct address_info * hw_config)
319 {
320         pas_irq = hw_config->irq;
321         pas_osp = hw_config->osp;
322
323         if (detect_pas_hw(hw_config)) {
324
325                 if ((pas_model = pas_read(CHIP_REV))) {
326                         char            temp[100];
327
328                         snprintf(temp, sizeof(temp),
329                               "%s rev %d", pas_model_names[(int) pas_model],
330                                 pas_read(BOARD_REV_ID));
331                         conf_printf(temp, hw_config);
332                 }
333                 if (config_pas_hw(hw_config)) {
334
335 #ifdef CONFIG_AUDIO
336                         pas_pcm_init(hw_config);
337 #endif
338
339 #if defined(CONFIG_SB_EMULATION) && defined(CONFIG_SB)
340
341                         sb_dsp_disable_midi();  /* The SB emulation don't
342                                                  * support * midi */
343 #endif
344
345
346 #ifdef CONFIG_MIDI
347                         pas_midi_init();
348 #endif
349                         pas_init_mixer();
350                 }
351         }
352 }
353
354 int
355 probe_pas(struct address_info * hw_config)
356 {
357         pas_osp = hw_config->osp;
358         return detect_pas_hw(hw_config);
359 }
360
361 #endif