Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
0004     Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
0005 
0006 */
0007 
0008 /*
0009     This driver should provide support for most Aztech AZT2320 based cards.
0010     Several AZT2316 chips are also supported/tested, but autoprobe doesn't
0011     work: all module option have to be set.
0012 
0013     No docs available for us at Aztech headquarters !!!   Unbelievable ...
0014     No other help obtained.
0015 
0016     Thanks to Rainer Wiesner <rainer.wiesner@01019freenet.de> for the WSS
0017     activation method (full-duplex audio!).
0018 */
0019 
0020 #include <linux/io.h>
0021 #include <linux/delay.h>
0022 #include <linux/init.h>
0023 #include <linux/time.h>
0024 #include <linux/wait.h>
0025 #include <linux/pnp.h>
0026 #include <linux/module.h>
0027 #include <sound/core.h>
0028 #include <sound/initval.h>
0029 #include <sound/wss.h>
0030 #include <sound/mpu401.h>
0031 #include <sound/opl3.h>
0032 
0033 #define PFX "azt2320: "
0034 
0035 MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
0036 MODULE_DESCRIPTION("Aztech Systems AZT2320");
0037 MODULE_LICENSE("GPL");
0038 
0039 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;  /* Index 0-MAX */
0040 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;   /* ID for this card */
0041 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
0042 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
0043 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
0044 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
0045 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;  /* PnP setup */
0046 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* Pnp setup */
0047 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* Pnp setup */
0048 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;   /* PnP setup */
0049 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;   /* PnP setup */
0050 
0051 module_param_array(index, int, NULL, 0444);
0052 MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
0053 module_param_array(id, charp, NULL, 0444);
0054 MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
0055 module_param_array(enable, bool, NULL, 0444);
0056 MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
0057 
0058 struct snd_card_azt2320 {
0059     int dev_no;
0060     struct pnp_dev *dev;
0061     struct pnp_dev *devmpu;
0062     struct snd_wss *chip;
0063 };
0064 
0065 static const struct pnp_card_device_id snd_azt2320_pnpids[] = {
0066     /* PRO16V */
0067     { .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
0068     /* Aztech Sound Galaxy 16 */
0069     { .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
0070     /* Packard Bell Sound III 336 AM/SP */
0071     { .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
0072     /* AT3300 */
0073     { .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
0074     /* --- */
0075     { .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
0076     /* --- */
0077     { .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
0078     { .id = "" }    /* end */
0079 };
0080 
0081 MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
0082 
0083 #define DRIVER_NAME "snd-card-azt2320"
0084 
0085 static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
0086                 struct pnp_card_link *card,
0087                 const struct pnp_card_device_id *id)
0088 {
0089     struct pnp_dev *pdev;
0090     int err;
0091 
0092     acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
0093     if (acard->dev == NULL)
0094         return -ENODEV;
0095 
0096     acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
0097 
0098     pdev = acard->dev;
0099 
0100     err = pnp_activate_dev(pdev);
0101     if (err < 0) {
0102         snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
0103         return err;
0104     }
0105     port[dev] = pnp_port_start(pdev, 0);
0106     fm_port[dev] = pnp_port_start(pdev, 1);
0107     wss_port[dev] = pnp_port_start(pdev, 2);
0108     dma1[dev] = pnp_dma(pdev, 0);
0109     dma2[dev] = pnp_dma(pdev, 1);
0110     irq[dev] = pnp_irq(pdev, 0);
0111 
0112     pdev = acard->devmpu;
0113     if (pdev != NULL) {
0114         err = pnp_activate_dev(pdev);
0115         if (err < 0)
0116             goto __mpu_error;
0117         mpu_port[dev] = pnp_port_start(pdev, 0);
0118         mpu_irq[dev] = pnp_irq(pdev, 0);
0119     } else {
0120          __mpu_error:
0121             if (pdev) {
0122                 pnp_release_card_device(pdev);
0123                 snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
0124             }
0125             acard->devmpu = NULL;
0126             mpu_port[dev] = -1;
0127     }
0128 
0129     return 0;
0130 }
0131 
0132 /* same of snd_sbdsp_command by Jaroslav Kysela */
0133 static int snd_card_azt2320_command(unsigned long port, unsigned char val)
0134 {
0135     int i;
0136     unsigned long limit;
0137 
0138     limit = jiffies + HZ / 10;
0139     for (i = 50000; i && time_after(limit, jiffies); i--)
0140         if (!(inb(port + 0x0c) & 0x80)) {
0141             outb(val, port + 0x0c);
0142             return 0;
0143         }
0144     return -EBUSY;
0145 }
0146 
0147 static int snd_card_azt2320_enable_wss(unsigned long port)
0148 {
0149     int error;
0150 
0151     error = snd_card_azt2320_command(port, 0x09);
0152     if (error)
0153         return error;
0154     error = snd_card_azt2320_command(port, 0x00);
0155     if (error)
0156         return error;
0157 
0158     mdelay(5);
0159     return 0;
0160 }
0161 
0162 static int snd_card_azt2320_probe(int dev,
0163                   struct pnp_card_link *pcard,
0164                   const struct pnp_card_device_id *pid)
0165 {
0166     int error;
0167     struct snd_card *card;
0168     struct snd_card_azt2320 *acard;
0169     struct snd_wss *chip;
0170     struct snd_opl3 *opl3;
0171 
0172     error = snd_devm_card_new(&pcard->card->dev,
0173                   index[dev], id[dev], THIS_MODULE,
0174                   sizeof(struct snd_card_azt2320), &card);
0175     if (error < 0)
0176         return error;
0177     acard = card->private_data;
0178 
0179     error = snd_card_azt2320_pnp(dev, acard, pcard, pid);
0180     if (error)
0181         return error;
0182 
0183     error = snd_card_azt2320_enable_wss(port[dev]);
0184     if (error)
0185         return error;
0186 
0187     error = snd_wss_create(card, wss_port[dev], -1,
0188                    irq[dev],
0189                    dma1[dev], dma2[dev],
0190                    WSS_HW_DETECT, 0, &chip);
0191     if (error < 0)
0192         return error;
0193 
0194     strcpy(card->driver, "AZT2320");
0195     strcpy(card->shortname, "Aztech AZT2320");
0196     sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
0197         card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
0198 
0199     error = snd_wss_pcm(chip, 0);
0200     if (error < 0)
0201         return error;
0202     error = snd_wss_mixer(chip);
0203     if (error < 0)
0204         return error;
0205     error = snd_wss_timer(chip, 0);
0206     if (error < 0)
0207         return error;
0208 
0209     if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
0210         if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
0211                 mpu_port[dev], 0,
0212                 mpu_irq[dev], NULL) < 0)
0213             snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
0214     }
0215 
0216     if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
0217         if (snd_opl3_create(card,
0218                     fm_port[dev], fm_port[dev] + 2,
0219                     OPL3_HW_AUTO, 0, &opl3) < 0) {
0220             snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
0221                    fm_port[dev], fm_port[dev] + 2);
0222         } else {
0223             error = snd_opl3_timer_new(opl3, 1, 2);
0224             if (error < 0)
0225                 return error;
0226             error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
0227             if (error < 0)
0228                 return error;
0229         }
0230     }
0231 
0232     error = snd_card_register(card);
0233     if (error < 0)
0234         return error;
0235     pnp_set_card_drvdata(pcard, card);
0236     return 0;
0237 }
0238 
0239 static unsigned int azt2320_devices;
0240 
0241 static int snd_azt2320_pnp_detect(struct pnp_card_link *card,
0242                   const struct pnp_card_device_id *id)
0243 {
0244     static int dev;
0245     int res;
0246 
0247     for ( ; dev < SNDRV_CARDS; dev++) {
0248         if (!enable[dev])
0249             continue;
0250         res = snd_card_azt2320_probe(dev, card, id);
0251         if (res < 0)
0252             return res;
0253         dev++;
0254         azt2320_devices++;
0255         return 0;
0256     }
0257         return -ENODEV;
0258 }
0259 
0260 #ifdef CONFIG_PM
0261 static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
0262 {
0263     struct snd_card *card = pnp_get_card_drvdata(pcard);
0264     struct snd_card_azt2320 *acard = card->private_data;
0265     struct snd_wss *chip = acard->chip;
0266 
0267     snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
0268     chip->suspend(chip);
0269     return 0;
0270 }
0271 
0272 static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
0273 {
0274     struct snd_card *card = pnp_get_card_drvdata(pcard);
0275     struct snd_card_azt2320 *acard = card->private_data;
0276     struct snd_wss *chip = acard->chip;
0277 
0278     chip->resume(chip);
0279     snd_power_change_state(card, SNDRV_CTL_POWER_D0);
0280     return 0;
0281 }
0282 #endif
0283 
0284 static struct pnp_card_driver azt2320_pnpc_driver = {
0285     .flags          = PNP_DRIVER_RES_DISABLE,
0286     .name           = "azt2320",
0287     .id_table       = snd_azt2320_pnpids,
0288     .probe          = snd_azt2320_pnp_detect,
0289 #ifdef CONFIG_PM
0290     .suspend    = snd_azt2320_pnp_suspend,
0291     .resume     = snd_azt2320_pnp_resume,
0292 #endif
0293 };
0294 
0295 static int __init alsa_card_azt2320_init(void)
0296 {
0297     int err;
0298 
0299     err = pnp_register_card_driver(&azt2320_pnpc_driver);
0300     if (err)
0301         return err;
0302 
0303     if (!azt2320_devices) {
0304         pnp_unregister_card_driver(&azt2320_pnpc_driver);
0305 #ifdef MODULE
0306         snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
0307 #endif
0308         return -ENODEV;
0309     }
0310     return 0;
0311 }
0312 
0313 static void __exit alsa_card_azt2320_exit(void)
0314 {
0315     pnp_unregister_card_driver(&azt2320_pnpc_driver);
0316 }
0317 
0318 module_init(alsa_card_azt2320_init)
0319 module_exit(alsa_card_azt2320_exit)