Lines Matching +full:3 +full:- +full:port
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for C-Media CMI8328-based soundcards, such as AudioExcel AV500
7 * - CMI8328 - main chip (SB Pro emulation, gameport, OPL3, MPU401, CD-ROM)
8 * - CS4231A - WSS codec
9 * - Dream SAM9233+GMS950400+RAM+ROM: Wavetable MIDI, connected to MPU401
26 MODULE_AUTHOR("Ondrej Zary <linux@rainbow-software.org>");
27 MODULE_DESCRIPTION("C-Media CMI8328");
34 /* I/O port is configured by jumpers on the card to one of these */
38 static int index[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = -1};
39 static char *id[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = NULL};
40 static long port[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT}; variable
41 static int irq[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
42 static int dma1[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
43 static int dma2[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
44 static long mpuport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
45 static int mpuirq[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
47 static bool gameport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = true};
55 module_param_hw_array(port, long, ioport, NULL, 0444);
56 MODULE_PARM_DESC(port, "Port # for CMI8328 driver.");
65 MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8328 driver.");
67 MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8328 MPU-401 port.");
74 u16 port; member
75 u8 cfg[3];
91 * bits 2-4: SB IRQ: 001=3, 010=5, 011=7, 100=9, 101=10, 110=11
92 * bits 5-6: SB DMA: 00=disabled (when SB disabled), 01=DMA0, 10=DMA1, 11=DMA3
93 * bit 7: SB port: 0=0x220, 1=0x240
98 * bits 0-1: CD-ROM mode: 00=disabled, 01=Panasonic, 10=Sony/Mitsumi/Wearnes,
101 * bits 3-4: MPU401 IRQ: 00=3, 01=5, 10=7, 11=9,
102 * bits 5-7: MPU401 port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x332,
107 * bits 0-2: CD-ROM IRQ: 000=disabled, 001=3, 010=5, 011=7, 100=9, 101=10,
109 * bits 3-4: CD-ROM DMA: 00=disabled, 01=DMA0, 10=DMA1, 11=DMA3
110 * bits 5-7: CD-ROM port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x340,
114 static u8 snd_cmi8328_cfg_read(u16 port, u8 reg) in snd_cmi8328_cfg_read() argument
116 outb(0x43, port + 3); in snd_cmi8328_cfg_read()
117 outb(0x21, port + 3); in snd_cmi8328_cfg_read()
118 outb(reg, port + 3); in snd_cmi8328_cfg_read()
119 return inb(port); in snd_cmi8328_cfg_read()
122 static void snd_cmi8328_cfg_write(u16 port, u8 reg, u8 val) in snd_cmi8328_cfg_write() argument
124 outb(0x43, port + 3); in snd_cmi8328_cfg_write()
125 outb(0x21, port + 3); in snd_cmi8328_cfg_write()
126 outb(reg, port + 3); in snd_cmi8328_cfg_write()
127 outb(val, port + 3); /* yes, value goes to the same port as index */ in snd_cmi8328_cfg_write()
131 static void snd_cmi8328_cfg_save(u16 port, u8 cfg[]) in snd_cmi8328_cfg_save() argument
133 cfg[0] = snd_cmi8328_cfg_read(port, CFG1); in snd_cmi8328_cfg_save()
134 cfg[1] = snd_cmi8328_cfg_read(port, CFG2); in snd_cmi8328_cfg_save()
135 cfg[2] = snd_cmi8328_cfg_read(port, CFG3); in snd_cmi8328_cfg_save()
138 static void snd_cmi8328_cfg_restore(u16 port, u8 cfg[]) in snd_cmi8328_cfg_restore() argument
140 snd_cmi8328_cfg_write(port, CFG1, cfg[0]); in snd_cmi8328_cfg_restore()
141 snd_cmi8328_cfg_write(port, CFG2, cfg[1]); in snd_cmi8328_cfg_restore()
142 snd_cmi8328_cfg_write(port, CFG3, cfg[2]); in snd_cmi8328_cfg_restore()
152 card = chip->card; in snd_cmi8328_mixer()
162 dev_err(card->dev, "error renaming control\n"); in snd_cmi8328_mixer()
170 dev_err(card->dev, "error renaming control\n"); in snd_cmi8328_mixer()
179 dev_err(card->dev, "error renaming control\n"); in snd_cmi8328_mixer()
188 dev_err(card->dev, "error renaming control\n"); in snd_cmi8328_mixer()
195 /* find index of an item in "-1"-ended array */
200 for (i = 0; array[i] != -1; i++) in array_find()
204 return -1; in array_find()
211 for (i = 0; array[i] != -1; i++) in array_find_l()
215 return -1; in array_find_l()
228 0x336, -1 }; in snd_cmi8328_probe()
229 static const u8 mpu_port_bits[] = { 3, 0, 1, 2, 4, 5, 6 }; in snd_cmi8328_probe()
230 static const int mpu_irqs[] = { 9, 7, 5, 3, -1 }; in snd_cmi8328_probe()
231 static const u8 mpu_irq_bits[] = { 3, 2, 1, 0 }; in snd_cmi8328_probe()
232 static const int irqs[] = { 9, 10, 11, 7, -1 }; in snd_cmi8328_probe()
233 static const u8 irq_bits[] = { 2, 3, 4, 1 }; in snd_cmi8328_probe()
234 static const int dma1s[] = { 3, 1, 0, -1 }; in snd_cmi8328_probe()
235 static const u8 dma_bits[] = { 3, 2, 1 }; in snd_cmi8328_probe()
236 static const int dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, {0, -1} }; in snd_cmi8328_probe()
237 u16 port = cmi8328_ports[ndev]; in snd_cmi8328_probe() local
240 /* 0xff is invalid configuration (but settable - hope it isn't set) */ in snd_cmi8328_probe()
241 if (snd_cmi8328_cfg_read(port, CFG1) == 0xff) in snd_cmi8328_probe()
242 return -ENODEV; in snd_cmi8328_probe()
244 snd_cmi8328_cfg_write(port, CFG1, CFG1_SB_DISABLE); in snd_cmi8328_probe()
245 if (snd_cmi8328_cfg_read(port, CFG1) != CFG1_SB_DISABLE) in snd_cmi8328_probe()
246 return -ENODEV; in snd_cmi8328_probe()
248 snd_cmi8328_cfg_write(port, CFG2, 0); /* disable CDROM and MPU401 */ in snd_cmi8328_probe()
249 snd_cmi8328_cfg_write(port, CFG3, 0); /* disable CDROM IRQ and DMA */ in snd_cmi8328_probe()
255 return -EBUSY; in snd_cmi8328_probe()
262 return -EBUSY; in snd_cmi8328_probe()
268 dev_warn(pdev, "unable to find a free DMA2, full-duplex will not work\n"); in snd_cmi8328_probe()
269 dma2[ndev] = -1; in snd_cmi8328_probe()
276 return -EINVAL; in snd_cmi8328_probe()
278 val = irq_bits[pos] << 3; in snd_cmi8328_probe()
283 return -EINVAL; in snd_cmi8328_probe()
291 return -EINVAL; in snd_cmi8328_probe()
295 outb(val, port); in snd_cmi8328_probe()
301 cmi = card->private_data; in snd_cmi8328_probe()
302 cmi->card = card; in snd_cmi8328_probe()
303 cmi->port = port; in snd_cmi8328_probe()
304 cmi->wss_cfg = val; in snd_cmi8328_probe()
306 err = snd_wss_create(card, port + 4, -1, irq[ndev], dma1[ndev], in snd_cmi8328_probe()
307 dma2[ndev], WSS_HW_DETECT, 0, &cmi->wss); in snd_cmi8328_probe()
311 err = snd_wss_pcm(cmi->wss, 0); in snd_cmi8328_probe()
315 err = snd_wss_mixer(cmi->wss); in snd_cmi8328_probe()
318 err = snd_cmi8328_mixer(cmi->wss); in snd_cmi8328_probe()
322 if (snd_wss_timer(cmi->wss, 0) < 0) in snd_cmi8328_probe()
328 dev_err(pdev, "unable to find a free MPU401 port\n"); in snd_cmi8328_probe()
340 dev_warn(pdev, "invalid MPU401 port 0x%lx\n", in snd_cmi8328_probe()
349 val |= mpu_irq_bits[pos] << 3; in snd_cmi8328_probe()
350 snd_cmi8328_cfg_write(port, CFG2, val); in snd_cmi8328_probe()
365 strcpy(card->driver, "CMI8328"); in snd_cmi8328_probe()
366 strcpy(card->shortname, "C-Media CMI8328"); in snd_cmi8328_probe()
367 sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d,%d", in snd_cmi8328_probe()
368 card->shortname, cmi->wss->port, irq[ndev], dma1[ndev], in snd_cmi8328_probe()
381 dev_warn(pdev, "unable to allocate gameport I/O port\n"); in snd_cmi8328_probe()
383 struct gameport *gp = cmi->gameport = gameport_allocate_port(); in snd_cmi8328_probe()
384 if (cmi->gameport) { in snd_cmi8328_probe()
388 gp->io = 0x200; in snd_cmi8328_probe()
390 snd_cmi8328_cfg_write(port, CFG1, in snd_cmi8328_probe()
402 struct snd_cmi8328 *cmi = card->private_data; in snd_cmi8328_remove()
405 if (cmi->gameport) in snd_cmi8328_remove()
406 gameport_unregister_port(cmi->gameport); in snd_cmi8328_remove()
409 snd_cmi8328_cfg_write(cmi->port, CFG1, CFG1_SB_DISABLE); in snd_cmi8328_remove()
410 snd_cmi8328_cfg_write(cmi->port, CFG2, 0); in snd_cmi8328_remove()
411 snd_cmi8328_cfg_write(cmi->port, CFG3, 0); in snd_cmi8328_remove()
423 cmi = card->private_data; in snd_cmi8328_suspend()
424 snd_cmi8328_cfg_save(cmi->port, cmi->cfg); in snd_cmi8328_suspend()
426 cmi->wss->suspend(cmi->wss); in snd_cmi8328_suspend()
438 cmi = card->private_data; in snd_cmi8328_resume()
439 snd_cmi8328_cfg_restore(cmi->port, cmi->cfg); in snd_cmi8328_resume()
440 outb(cmi->wss_cfg, cmi->port); in snd_cmi8328_resume()
441 cmi->wss->resume(cmi->wss); in snd_cmi8328_resume()