18c2ecf20Sopenharmony_ci 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * jazz16.c - driver for Media Vision Jazz16 based soundcards. 48c2ecf20Sopenharmony_ci * Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl> 58c2ecf20Sopenharmony_ci * Based on patches posted by Rask Ingemann Lambertsen and Rene Herman. 68c2ecf20Sopenharmony_ci * Based on OSS Sound Blaster driver. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 98c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 108c2ecf20Sopenharmony_ci * more details. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <asm/dma.h> 198c2ecf20Sopenharmony_ci#include <linux/isa.h> 208c2ecf20Sopenharmony_ci#include <sound/core.h> 218c2ecf20Sopenharmony_ci#include <sound/mpu401.h> 228c2ecf20Sopenharmony_ci#include <sound/opl3.h> 238c2ecf20Sopenharmony_ci#include <sound/sb.h> 248c2ecf20Sopenharmony_ci#define SNDRV_LEGACY_FIND_FREE_IRQ 258c2ecf20Sopenharmony_ci#define SNDRV_LEGACY_FIND_FREE_DMA 268c2ecf20Sopenharmony_ci#include <sound/initval.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define PFX "jazz16: " 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Media Vision Jazz16"); 318c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{Media Vision ??? }," 328c2ecf20Sopenharmony_ci "{RTL,RTL3000}}"); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciMODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); 358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 388c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 398c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ 408c2ecf20Sopenharmony_cistatic unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 418c2ecf20Sopenharmony_cistatic unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 428c2ecf20Sopenharmony_cistatic int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; 438c2ecf20Sopenharmony_cistatic int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; 448c2ecf20Sopenharmony_cistatic int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; 458c2ecf20Sopenharmony_cistatic int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard."); 498c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard."); 518c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard."); 538c2ecf20Sopenharmony_cimodule_param_hw_array(port, long, ioport, NULL, 0444); 548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(port, "Port # for jazz16 driver."); 558c2ecf20Sopenharmony_cimodule_param_hw_array(mpu_port, long, ioport, NULL, 0444); 568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver."); 578c2ecf20Sopenharmony_cimodule_param_hw_array(irq, int, irq, NULL, 0444); 588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irq, "IRQ # for jazz16 driver."); 598c2ecf20Sopenharmony_cimodule_param_hw_array(mpu_irq, int, irq, NULL, 0444); 608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver."); 618c2ecf20Sopenharmony_cimodule_param_hw_array(dma8, int, dma, NULL, 0444); 628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver."); 638c2ecf20Sopenharmony_cimodule_param_hw_array(dma16, int, dma, NULL, 0444); 648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver."); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define SB_JAZZ16_WAKEUP 0xaf 678c2ecf20Sopenharmony_ci#define SB_JAZZ16_SET_PORTS 0x50 688c2ecf20Sopenharmony_ci#define SB_DSP_GET_JAZZ_BRD_REV 0xfa 698c2ecf20Sopenharmony_ci#define SB_JAZZ16_SET_DMAINTR 0xfb 708c2ecf20Sopenharmony_ci#define SB_DSP_GET_JAZZ_MODEL 0xfe 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct snd_card_jazz16 { 738c2ecf20Sopenharmony_ci struct snd_sb *chip; 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic irqreturn_t jazz16_interrupt(int irq, void *chip) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci return snd_sb8dsp_interrupt(chip); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int jazz16_configure_ports(unsigned long port, 828c2ecf20Sopenharmony_ci unsigned long mpu_port, int idx) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci unsigned char val; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (!request_region(0x201, 1, "jazz16 config")) { 878c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "config port region is already in use.\n"); 888c2ecf20Sopenharmony_ci return -EBUSY; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci outb(SB_JAZZ16_WAKEUP - idx, 0x201); 918c2ecf20Sopenharmony_ci udelay(100); 928c2ecf20Sopenharmony_ci outb(SB_JAZZ16_SET_PORTS + idx, 0x201); 938c2ecf20Sopenharmony_ci udelay(100); 948c2ecf20Sopenharmony_ci val = port & 0x70; 958c2ecf20Sopenharmony_ci val |= (mpu_port & 0x30) >> 4; 968c2ecf20Sopenharmony_ci outb(val, 0x201); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci release_region(0x201, 1); 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int jazz16_detect_board(unsigned long port, 1038c2ecf20Sopenharmony_ci unsigned long mpu_port) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int err; 1068c2ecf20Sopenharmony_ci int val; 1078c2ecf20Sopenharmony_ci struct snd_sb chip; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (!request_region(port, 0x10, "jazz16")) { 1108c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "I/O port region is already in use.\n"); 1118c2ecf20Sopenharmony_ci return -EBUSY; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci /* just to call snd_sbdsp_command/reset/get_byte() */ 1148c2ecf20Sopenharmony_ci chip.port = port; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci err = snd_sbdsp_reset(&chip); 1178c2ecf20Sopenharmony_ci if (err < 0) 1188c2ecf20Sopenharmony_ci for (val = 0; val < 4; val++) { 1198c2ecf20Sopenharmony_ci err = jazz16_configure_ports(port, mpu_port, val); 1208c2ecf20Sopenharmony_ci if (err < 0) 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci err = snd_sbdsp_reset(&chip); 1248c2ecf20Sopenharmony_ci if (!err) 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci if (err < 0) { 1288c2ecf20Sopenharmony_ci err = -ENODEV; 1298c2ecf20Sopenharmony_ci goto err_unmap; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) { 1328c2ecf20Sopenharmony_ci err = -EBUSY; 1338c2ecf20Sopenharmony_ci goto err_unmap; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci val = snd_sbdsp_get_byte(&chip); 1368c2ecf20Sopenharmony_ci if (val >= 0x30) 1378c2ecf20Sopenharmony_ci snd_sbdsp_get_byte(&chip); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if ((val & 0xf0) != 0x10) { 1408c2ecf20Sopenharmony_ci err = -ENODEV; 1418c2ecf20Sopenharmony_ci goto err_unmap; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) { 1448c2ecf20Sopenharmony_ci err = -EBUSY; 1458c2ecf20Sopenharmony_ci goto err_unmap; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci snd_sbdsp_get_byte(&chip); 1488c2ecf20Sopenharmony_ci err = snd_sbdsp_get_byte(&chip); 1498c2ecf20Sopenharmony_ci snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n", 1508c2ecf20Sopenharmony_ci val, err); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci err = 0; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cierr_unmap: 1558c2ecf20Sopenharmony_ci release_region(port, 0x10); 1568c2ecf20Sopenharmony_ci return err; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int jazz16_configure_board(struct snd_sb *chip, int mpu_irq) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci static const unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, 1628c2ecf20Sopenharmony_ci 0, 2, 5, 0, 0, 0, 0, 6 }; 1638c2ecf20Sopenharmony_ci static const unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 }; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (jazz_dma_bits[chip->dma8] == 0 || 1668c2ecf20Sopenharmony_ci jazz_dma_bits[chip->dma16] == 0 || 1678c2ecf20Sopenharmony_ci jazz_irq_bits[chip->irq] == 0) 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR)) 1718c2ecf20Sopenharmony_ci return -EBUSY; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (!snd_sbdsp_command(chip, 1748c2ecf20Sopenharmony_ci jazz_dma_bits[chip->dma8] | 1758c2ecf20Sopenharmony_ci (jazz_dma_bits[chip->dma16] << 4))) 1768c2ecf20Sopenharmony_ci return -EBUSY; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!snd_sbdsp_command(chip, 1798c2ecf20Sopenharmony_ci jazz_irq_bits[chip->irq] | 1808c2ecf20Sopenharmony_ci (jazz_irq_bits[mpu_irq] << 4))) 1818c2ecf20Sopenharmony_ci return -EBUSY; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int snd_jazz16_match(struct device *devptr, unsigned int dev) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci if (!enable[dev]) 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci if (port[dev] == SNDRV_AUTO_PORT) { 1918c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "please specify port\n"); 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci } else if (port[dev] == 0x200 || (port[dev] & ~0x270)) { 1948c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "incorrect port specified\n"); 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci if (dma8[dev] != SNDRV_AUTO_DMA && 1988c2ecf20Sopenharmony_ci dma8[dev] != 1 && dma8[dev] != 3) { 1998c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "dma8 must be 1 or 3\n"); 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci if (dma16[dev] != SNDRV_AUTO_DMA && 2038c2ecf20Sopenharmony_ci dma16[dev] != 5 && dma16[dev] != 7) { 2048c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "dma16 must be 5 or 7\n"); 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci if (mpu_port[dev] != SNDRV_AUTO_PORT && 2088c2ecf20Sopenharmony_ci (mpu_port[dev] & ~0x030) != 0x300) { 2098c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "incorrect mpu_port specified\n"); 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci if (mpu_irq[dev] != SNDRV_AUTO_DMA && 2138c2ecf20Sopenharmony_ci mpu_irq[dev] != 2 && mpu_irq[dev] != 3 && 2148c2ecf20Sopenharmony_ci mpu_irq[dev] != 5 && mpu_irq[dev] != 7) { 2158c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n"); 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci return 1; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int snd_jazz16_probe(struct device *devptr, unsigned int dev) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct snd_card *card; 2248c2ecf20Sopenharmony_ci struct snd_card_jazz16 *jazz16; 2258c2ecf20Sopenharmony_ci struct snd_sb *chip; 2268c2ecf20Sopenharmony_ci struct snd_opl3 *opl3; 2278c2ecf20Sopenharmony_ci static const int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1}; 2288c2ecf20Sopenharmony_ci static const int possible_dmas8[] = {1, 3, -1}; 2298c2ecf20Sopenharmony_ci static const int possible_dmas16[] = {5, 7, -1}; 2308c2ecf20Sopenharmony_ci int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE, 2338c2ecf20Sopenharmony_ci sizeof(struct snd_card_jazz16), &card); 2348c2ecf20Sopenharmony_ci if (err < 0) 2358c2ecf20Sopenharmony_ci return err; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci jazz16 = card->private_data; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci xirq = irq[dev]; 2408c2ecf20Sopenharmony_ci if (xirq == SNDRV_AUTO_IRQ) { 2418c2ecf20Sopenharmony_ci xirq = snd_legacy_find_free_irq(possible_irqs); 2428c2ecf20Sopenharmony_ci if (xirq < 0) { 2438c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "unable to find a free IRQ\n"); 2448c2ecf20Sopenharmony_ci err = -EBUSY; 2458c2ecf20Sopenharmony_ci goto err_free; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci xdma8 = dma8[dev]; 2498c2ecf20Sopenharmony_ci if (xdma8 == SNDRV_AUTO_DMA) { 2508c2ecf20Sopenharmony_ci xdma8 = snd_legacy_find_free_dma(possible_dmas8); 2518c2ecf20Sopenharmony_ci if (xdma8 < 0) { 2528c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "unable to find a free DMA8\n"); 2538c2ecf20Sopenharmony_ci err = -EBUSY; 2548c2ecf20Sopenharmony_ci goto err_free; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci xdma16 = dma16[dev]; 2588c2ecf20Sopenharmony_ci if (xdma16 == SNDRV_AUTO_DMA) { 2598c2ecf20Sopenharmony_ci xdma16 = snd_legacy_find_free_dma(possible_dmas16); 2608c2ecf20Sopenharmony_ci if (xdma16 < 0) { 2618c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "unable to find a free DMA16\n"); 2628c2ecf20Sopenharmony_ci err = -EBUSY; 2638c2ecf20Sopenharmony_ci goto err_free; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci xmpu_port = mpu_port[dev]; 2688c2ecf20Sopenharmony_ci if (xmpu_port == SNDRV_AUTO_PORT) 2698c2ecf20Sopenharmony_ci xmpu_port = 0; 2708c2ecf20Sopenharmony_ci err = jazz16_detect_board(port[dev], xmpu_port); 2718c2ecf20Sopenharmony_ci if (err < 0) { 2728c2ecf20Sopenharmony_ci printk(KERN_ERR "Media Vision Jazz16 board not detected\n"); 2738c2ecf20Sopenharmony_ci goto err_free; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci err = snd_sbdsp_create(card, port[dev], irq[dev], 2768c2ecf20Sopenharmony_ci jazz16_interrupt, 2778c2ecf20Sopenharmony_ci dma8[dev], dma16[dev], 2788c2ecf20Sopenharmony_ci SB_HW_JAZZ16, 2798c2ecf20Sopenharmony_ci &chip); 2808c2ecf20Sopenharmony_ci if (err < 0) 2818c2ecf20Sopenharmony_ci goto err_free; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci xmpu_irq = mpu_irq[dev]; 2848c2ecf20Sopenharmony_ci if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT) 2858c2ecf20Sopenharmony_ci xmpu_irq = 0; 2868c2ecf20Sopenharmony_ci err = jazz16_configure_board(chip, xmpu_irq); 2878c2ecf20Sopenharmony_ci if (err < 0) { 2888c2ecf20Sopenharmony_ci printk(KERN_ERR "Media Vision Jazz16 configuration failed\n"); 2898c2ecf20Sopenharmony_ci goto err_free; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci jazz16->chip = chip; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci strcpy(card->driver, "jazz16"); 2958c2ecf20Sopenharmony_ci strcpy(card->shortname, "Media Vision Jazz16"); 2968c2ecf20Sopenharmony_ci sprintf(card->longname, 2978c2ecf20Sopenharmony_ci "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d", 2988c2ecf20Sopenharmony_ci port[dev], xirq, xdma8, xdma16); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci err = snd_sb8dsp_pcm(chip, 0); 3018c2ecf20Sopenharmony_ci if (err < 0) 3028c2ecf20Sopenharmony_ci goto err_free; 3038c2ecf20Sopenharmony_ci err = snd_sbmixer_new(chip); 3048c2ecf20Sopenharmony_ci if (err < 0) 3058c2ecf20Sopenharmony_ci goto err_free; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci err = snd_opl3_create(card, chip->port, chip->port + 2, 3088c2ecf20Sopenharmony_ci OPL3_HW_AUTO, 1, &opl3); 3098c2ecf20Sopenharmony_ci if (err < 0) 3108c2ecf20Sopenharmony_ci snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", 3118c2ecf20Sopenharmony_ci chip->port, chip->port + 2); 3128c2ecf20Sopenharmony_ci else { 3138c2ecf20Sopenharmony_ci err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); 3148c2ecf20Sopenharmony_ci if (err < 0) 3158c2ecf20Sopenharmony_ci goto err_free; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { 3188c2ecf20Sopenharmony_ci if (mpu_irq[dev] == SNDRV_AUTO_IRQ) 3198c2ecf20Sopenharmony_ci mpu_irq[dev] = -1; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (snd_mpu401_uart_new(card, 0, 3228c2ecf20Sopenharmony_ci MPU401_HW_MPU401, 3238c2ecf20Sopenharmony_ci mpu_port[dev], 0, 3248c2ecf20Sopenharmony_ci mpu_irq[dev], 3258c2ecf20Sopenharmony_ci NULL) < 0) 3268c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n", 3278c2ecf20Sopenharmony_ci mpu_port[dev]); 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci err = snd_card_register(card); 3318c2ecf20Sopenharmony_ci if (err < 0) 3328c2ecf20Sopenharmony_ci goto err_free; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci dev_set_drvdata(devptr, card); 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cierr_free: 3388c2ecf20Sopenharmony_ci snd_card_free(card); 3398c2ecf20Sopenharmony_ci return err; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int snd_jazz16_remove(struct device *devptr, unsigned int dev) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(devptr); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci snd_card_free(card); 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 3518c2ecf20Sopenharmony_cistatic int snd_jazz16_suspend(struct device *pdev, unsigned int n, 3528c2ecf20Sopenharmony_ci pm_message_t state) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(pdev); 3558c2ecf20Sopenharmony_ci struct snd_card_jazz16 *acard = card->private_data; 3568c2ecf20Sopenharmony_ci struct snd_sb *chip = acard->chip; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 3598c2ecf20Sopenharmony_ci snd_sbmixer_suspend(chip); 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int snd_jazz16_resume(struct device *pdev, unsigned int n) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(pdev); 3668c2ecf20Sopenharmony_ci struct snd_card_jazz16 *acard = card->private_data; 3678c2ecf20Sopenharmony_ci struct snd_sb *chip = acard->chip; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci snd_sbdsp_reset(chip); 3708c2ecf20Sopenharmony_ci snd_sbmixer_resume(chip); 3718c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D0); 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci#endif 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic struct isa_driver snd_jazz16_driver = { 3778c2ecf20Sopenharmony_ci .match = snd_jazz16_match, 3788c2ecf20Sopenharmony_ci .probe = snd_jazz16_probe, 3798c2ecf20Sopenharmony_ci .remove = snd_jazz16_remove, 3808c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 3818c2ecf20Sopenharmony_ci .suspend = snd_jazz16_suspend, 3828c2ecf20Sopenharmony_ci .resume = snd_jazz16_resume, 3838c2ecf20Sopenharmony_ci#endif 3848c2ecf20Sopenharmony_ci .driver = { 3858c2ecf20Sopenharmony_ci .name = "jazz16" 3868c2ecf20Sopenharmony_ci }, 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cimodule_isa_driver(snd_jazz16_driver, SNDRV_CARDS); 390