1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50#include <linux/config.h>
51#include <linux/isapnp.h>
52#include <linux/module.h>
53#include <linux/init.h>
54
55#include "sound_config.h"
56
57#include "cs4232.h"
58#include "ad1848.h"
59#include "mpu401.h"
60
61#define KEY_PORT 0x279
62#define CSN_NUM 0x99
63#define INDEX_ADDRESS 0x00
64#define INDEX_DATA 0x01
65#define PIN_CONTROL 0x0a
66#define ENABLE_PINS 0xc0
67
68static void CS_OUT(unsigned char a)
69{
70 outb(a, KEY_PORT);
71}
72
73#define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);}
74#define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
75
76static int __initdata bss = 0;
77static int mpu_base = 0, mpu_irq = 0;
78static int synth_base = 0, synth_irq = 0;
79static int mpu_detected = 0;
80
81int __init probe_cs4232_mpu(struct address_info *hw_config)
82{
83
84
85
86
87 mpu_base = hw_config->io_base;
88 mpu_irq = hw_config->irq;
89
90 return 1;
91}
92
93static unsigned char crystal_key[] __initdata =
94{
95 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
96 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
97 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,
98 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a
99};
100
101static void sleep(unsigned howlong)
102{
103 current->state = TASK_INTERRUPTIBLE;
104 schedule_timeout(howlong);
105}
106
107static void enable_xctrl(int baseio)
108{
109 unsigned char regd;
110
111
112
113
114
115
116
117
118
119
120 printk("cs4232: enabling Bose Sound System Amplifier.\n");
121
122
123 regd = inb(baseio + INDEX_ADDRESS) & 0xe0;
124 outb(((unsigned char) (PIN_CONTROL | regd)), baseio + INDEX_ADDRESS );
125
126
127 regd = inb(baseio + INDEX_DATA);
128 outb(((unsigned char) (ENABLE_PINS | regd)), baseio + INDEX_DATA );
129}
130
131int __init probe_cs4232(struct address_info *hw_config, int isapnp_configured)
132{
133 int i, n;
134 int base = hw_config->io_base, irq = hw_config->irq;
135 int dma1 = hw_config->dma, dma2 = hw_config->dma2;
136
137
138
139
140
141 if (check_region(base, 4))
142 {
143 printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base);
144 return 0;
145 }
146 if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) {
147 return 1;
148 }
149 if (isapnp_configured) {
150 printk(KERN_ERR "cs4232.c: ISA PnP configured, but not detected?\n");
151 return 0;
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 for (n = 0; n < 4; n++)
170 {
171
172
173
174
175 for (i = 0; i < 32; i++)
176 CS_OUT(crystal_key[i]);
177
178 sleep(HZ / 10);
179
180
181
182
183
184 CS_OUT2(0x06, CSN_NUM);
185
186
187
188
189
190 CS_OUT2(0x15, 0x00);
191 CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff);
192
193 if (check_region(0x388, 4))
194 CS_OUT3(0x48, 0x00, 0x00)
195 else
196 CS_OUT3(0x48, 0x03, 0x88);
197
198 CS_OUT3(0x42, 0x00, 0x00);
199 CS_OUT2(0x22, irq);
200 CS_OUT2(0x2a, dma1);
201
202 if (dma2 != -1)
203 CS_OUT2(0x25, dma2)
204 else
205 CS_OUT2(0x25, 4);
206
207 CS_OUT2(0x33, 0x01);
208
209 sleep(HZ / 10);
210
211
212
213
214
215 if (mpu_base != 0 && mpu_irq != 0)
216 {
217 CS_OUT2(0x15, 0x03);
218 CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff);
219 CS_OUT2(0x22, mpu_irq);
220 CS_OUT2(0x33, 0x01);
221 }
222
223 if(synth_base != 0)
224 {
225 CS_OUT2 (0x15, 0x04);
226 CS_OUT3 (0x47, (synth_base >> 8) & 0xff,
227 synth_base & 0xff);
228 CS_OUT2 (0x22, synth_irq);
229 CS_OUT2 (0x33, 0x01);
230 }
231
232
233
234
235
236 CS_OUT(0x79);
237
238 sleep(HZ / 5);
239
240
241
242
243
244 if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp))
245 return 1;
246
247 sleep(HZ);
248 }
249 return 0;
250}
251
252void __init attach_cs4232(struct address_info *hw_config)
253{
254 int base = hw_config->io_base,
255 irq = hw_config->irq,
256 dma1 = hw_config->dma,
257 dma2 = hw_config->dma2;
258
259 if (base == -1 || irq == -1 || dma1 == -1) {
260 printk(KERN_ERR "cs4232: dma, irq and io must be set.\n");
261 return;
262 }
263
264 if (dma2 == -1)
265 dma2 = dma1;
266
267 hw_config->slots[0] = ad1848_init("Crystal audio controller", base,
268 irq,
269 dma1,
270 dma2,
271 0,
272 hw_config->osp,
273 THIS_MODULE);
274
275 if (hw_config->slots[0] != -1 &&
276 audio_devs[hw_config->slots[0]]->mixer_dev!=-1)
277 {
278
279 AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
280 AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
281 AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH);
282 }
283 if (mpu_base != 0 && mpu_irq != 0)
284 {
285 static struct address_info hw_config2 = {
286 0
287 };
288
289 hw_config2.io_base = mpu_base;
290 hw_config2.irq = mpu_irq;
291 hw_config2.dma = -1;
292 hw_config2.dma2 = -1;
293 hw_config2.always_detect = 0;
294 hw_config2.name = NULL;
295 hw_config2.driver_use_1 = 0;
296 hw_config2.driver_use_2 = 0;
297 hw_config2.card_subtype = 0;
298
299 if (probe_uart401(&hw_config2, THIS_MODULE))
300 {
301 mpu_detected = 1;
302 }
303 else
304 {
305 mpu_base = mpu_irq = 0;
306 }
307 hw_config->slots[1] = hw_config2.slots[1];
308 }
309
310 if (bss)
311 {
312 enable_xctrl(base);
313 }
314}
315
316void unload_cs4232(struct address_info *hw_config)
317{
318 int base = hw_config->io_base, irq = hw_config->irq;
319 int dma1 = hw_config->dma, dma2 = hw_config->dma2;
320
321 if (dma2 == -1)
322 dma2 = dma1;
323
324 ad1848_unload(base,
325 irq,
326 dma1,
327 dma2,
328 0);
329
330 sound_unload_audiodev(hw_config->slots[0]);
331 if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
332 {
333 static struct address_info hw_config2 =
334 {
335 0
336 };
337
338 hw_config2.io_base = mpu_base;
339 hw_config2.irq = mpu_irq;
340 hw_config2.dma = -1;
341 hw_config2.dma2 = -1;
342 hw_config2.always_detect = 0;
343 hw_config2.name = NULL;
344 hw_config2.driver_use_1 = 0;
345 hw_config2.driver_use_2 = 0;
346 hw_config2.card_subtype = 0;
347 hw_config2.slots[1] = hw_config->slots[1];
348
349 unload_uart401(&hw_config2);
350 }
351}
352
353static struct address_info cfg;
354static struct address_info cfg_mpu;
355
356static int __initdata io = -1;
357static int __initdata irq = -1;
358static int __initdata dma = -1;
359static int __initdata dma2 = -1;
360static int __initdata mpuio = -1;
361static int __initdata mpuirq = -1;
362static int __initdata synthio = -1;
363static int __initdata synthirq = -1;
364static int __initdata isapnp = 1;
365
366MODULE_DESCRIPTION("CS4232 based soundcard driver");
367MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis");
368MODULE_LICENSE("GPL");
369
370MODULE_PARM(io,"i");
371MODULE_PARM_DESC(io,"base I/O port for AD1848");
372MODULE_PARM(irq,"i");
373MODULE_PARM_DESC(irq,"IRQ for AD1848 chip");
374MODULE_PARM(dma,"i");
375MODULE_PARM_DESC(dma,"8 bit DMA for AD1848 chip");
376MODULE_PARM(dma2,"i");
377MODULE_PARM_DESC(dma2,"16 bit DMA for AD1848 chip");
378MODULE_PARM(mpuio,"i");
379MODULE_PARM_DESC(mpuio,"MPU 401 base address");
380MODULE_PARM(mpuirq,"i");
381MODULE_PARM_DESC(mpuirq,"MPU 401 IRQ");
382MODULE_PARM(synthio,"i");
383MODULE_PARM_DESC(synthio,"Maui WaveTable base I/O port");
384MODULE_PARM(synthirq,"i");
385MODULE_PARM_DESC(synthirq,"Maui WaveTable IRQ");
386MODULE_PARM(isapnp,"i");
387MODULE_PARM_DESC(isapnp,"Enable ISAPnP probing (default 1)");
388MODULE_PARM(bss,"i");
389MODULE_PARM_DESC(bss,"Enable Bose Sound System Support (default 0)");
390
391
392
393
394
395
396
397
398struct isapnp_device_id isapnp_cs4232_list[] __initdata = {
399 { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
400 ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0100),
401 0 },
402 { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
403 ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0000),
404 0 },
405
406
407 { ISAPNP_VENDOR('C','S','C'), ISAPNP_ANY_ID,
408 ISAPNP_VENDOR('G','I','M'), ISAPNP_FUNCTION(0x0100),
409 0 },
410 {0}
411};
412
413MODULE_DEVICE_TABLE(isapnp, isapnp_cs4232_list);
414
415int cs4232_isapnp_probe(struct pci_dev *dev, const struct isapnp_device_id *id)
416{
417 int ret;
418 struct address_info *isapnpcfg;
419
420 isapnpcfg=(struct address_info*)kmalloc(sizeof(*isapnpcfg),GFP_KERNEL);
421 if (!isapnpcfg)
422 return -ENOMEM;
423
424
425
426
427 ret = dev->prepare(dev);
428 if(ret && ret != -EBUSY) {
429 printk(KERN_ERR "cs4232: ISA PnP found device that could not be autoconfigured.\n");
430 kfree(isapnpcfg);
431 return -ENODEV;
432 }
433 if(ret != -EBUSY) {
434 if(dev->activate(dev) < 0) {
435 printk(KERN_WARNING "cs4232: ISA PnP activate failed\n");
436 kfree(isapnpcfg);
437 return -ENODEV;
438 }
439 }
440
441 isapnpcfg->irq = dev->irq_resource[0].start;
442 isapnpcfg->dma = dev->dma_resource[0].start;
443 isapnpcfg->dma2 = dev->dma_resource[1].start;
444 isapnpcfg->io_base = dev->resource[0].start;
445 if (probe_cs4232(isapnpcfg,TRUE) == 0) {
446 printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n");
447 kfree(isapnpcfg);
448 return -ENODEV;
449 }
450 attach_cs4232(isapnpcfg);
451 pci_set_drvdata(dev,isapnpcfg);
452 return 0;
453}
454
455static int __init init_cs4232(void)
456{
457#ifdef CONFIG_SOUND_WAVEFRONT_MODULE
458 if(synthio == -1)
459 printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n");
460 else {
461 synth_base = synthio;
462 synth_irq = synthirq;
463 }
464#else
465 if(synthio != -1)
466 printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n");
467#endif
468 cfg.irq = -1;
469
470 if (isapnp &&
471 (isapnp_probe_devs(isapnp_cs4232_list, cs4232_isapnp_probe) > 0)
472 )
473 return 0;
474
475 if(io==-1||irq==-1||dma==-1)
476 {
477 printk(KERN_ERR "cs4232: Must set io, irq and dma.\n");
478 return -ENODEV;
479 }
480
481 cfg.io_base = io;
482 cfg.irq = irq;
483 cfg.dma = dma;
484 cfg.dma2 = dma2;
485
486 cfg_mpu.io_base = -1;
487 cfg_mpu.irq = -1;
488
489 if (mpuio != -1 && mpuirq != -1) {
490 cfg_mpu.io_base = mpuio;
491 cfg_mpu.irq = mpuirq;
492 probe_cs4232_mpu(&cfg_mpu);
493 }
494
495 if (probe_cs4232(&cfg,FALSE) == 0)
496 return -ENODEV;
497 attach_cs4232(&cfg);
498
499 return 0;
500}
501
502int cs4232_isapnp_remove(struct pci_dev *dev, const struct isapnp_device_id *id)
503{
504 struct address_info *cfg = (struct address_info*)pci_get_drvdata(dev);
505 if (cfg) unload_cs4232(cfg);
506 pci_set_drvdata(dev,NULL);
507 dev->deactivate(dev);
508 return 0;
509}
510
511static void __exit cleanup_cs4232(void)
512{
513 isapnp_probe_devs(isapnp_cs4232_list, cs4232_isapnp_remove);
514 if (cfg.irq != -1)
515 unload_cs4232(&cfg);
516}
517
518module_init(init_cs4232);
519module_exit(cleanup_cs4232);
520
521#ifndef MODULE
522static int __init setup_cs4232(char *str)
523{
524
525 int ints[7];
526
527
528 if (isapnp_probe_devs(isapnp_cs4232_list, cs4232_isapnp_probe) > 0)
529 return 1;
530
531 str = get_options(str, ARRAY_SIZE(ints), ints);
532
533 io = ints[1];
534 irq = ints[2];
535 dma = ints[3];
536 dma2 = ints[4];
537 mpuio = ints[5];
538 mpuirq = ints[6];
539
540 return 1;
541}
542
543__setup("cs4232=", setup_cs4232);
544#endif
545