Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Aztech AZT1605/AZT2316 Driver
0004  * Copyright (C) 2007,2010  Rene Herman
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/isa.h>
0010 #include <linux/delay.h>
0011 #include <linux/io.h>
0012 #include <asm/processor.h>
0013 #include <sound/core.h>
0014 #include <sound/initval.h>
0015 #include <sound/wss.h>
0016 #include <sound/mpu401.h>
0017 #include <sound/opl3.h>
0018 
0019 MODULE_DESCRIPTION(CRD_NAME);
0020 MODULE_AUTHOR("Rene Herman");
0021 MODULE_LICENSE("GPL");
0022 
0023 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
0024 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
0025 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
0026 
0027 module_param_array(index, int, NULL, 0444);
0028 MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
0029 module_param_array(id, charp, NULL, 0444);
0030 MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
0031 module_param_array(enable, bool, NULL, 0444);
0032 MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
0033 
0034 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
0035 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
0036 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
0037 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
0038 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
0039 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
0040 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
0041 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
0042 
0043 module_param_hw_array(port, long, ioport, NULL, 0444);
0044 MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
0045 module_param_hw_array(wss_port, long, ioport, NULL, 0444);
0046 MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
0047 module_param_hw_array(mpu_port, long, ioport, NULL, 0444);
0048 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
0049 module_param_hw_array(fm_port, long, ioport, NULL, 0444);
0050 MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
0051 module_param_hw_array(irq, int, irq, NULL, 0444);
0052 MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
0053 module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
0054 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
0055 module_param_hw_array(dma1, int, dma, NULL, 0444);
0056 MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
0057 module_param_hw_array(dma2, int, dma, NULL, 0444);
0058 MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
0059 
0060 /*
0061  * Generic SB DSP support routines
0062  */
0063 
0064 #define DSP_PORT_RESET      0x6
0065 #define DSP_PORT_READ       0xa
0066 #define DSP_PORT_COMMAND    0xc
0067 #define DSP_PORT_STATUS     0xc
0068 #define DSP_PORT_DATA_AVAIL 0xe
0069 
0070 #define DSP_SIGNATURE       0xaa
0071 
0072 #define DSP_COMMAND_GET_VERSION 0xe1
0073 
0074 static int dsp_get_byte(void __iomem *port, u8 *val)
0075 {
0076     int loops = 1000;
0077 
0078     while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
0079         if (!loops--)
0080             return -EIO;
0081         cpu_relax();
0082     }
0083     *val = ioread8(port + DSP_PORT_READ);
0084     return 0;
0085 }
0086 
0087 static int dsp_reset(void __iomem *port)
0088 {
0089     u8 val;
0090 
0091     iowrite8(1, port + DSP_PORT_RESET);
0092     udelay(10);
0093     iowrite8(0, port + DSP_PORT_RESET);
0094 
0095     if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
0096         return -ENODEV;
0097 
0098     return 0;
0099 }
0100 
0101 static int dsp_command(void __iomem *port, u8 cmd)
0102 {
0103     int loops = 1000;
0104 
0105     while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
0106         if (!loops--)
0107             return -EIO;
0108         cpu_relax();
0109     }
0110     iowrite8(cmd, port + DSP_PORT_COMMAND);
0111     return 0;
0112 }
0113 
0114 static int dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
0115 {
0116     int err;
0117 
0118     err = dsp_command(port, DSP_COMMAND_GET_VERSION);
0119     if (err < 0)
0120         return err;
0121 
0122     err = dsp_get_byte(port, major);
0123     if (err < 0)
0124         return err;
0125 
0126     err = dsp_get_byte(port, minor);
0127     if (err < 0)
0128         return err;
0129 
0130     return 0;
0131 }
0132 
0133 /*
0134  * Generic WSS support routines
0135  */
0136 
0137 #define WSS_CONFIG_DMA_0    (1 << 0)
0138 #define WSS_CONFIG_DMA_1    (2 << 0)
0139 #define WSS_CONFIG_DMA_3    (3 << 0)
0140 #define WSS_CONFIG_DUPLEX   (1 << 2)
0141 #define WSS_CONFIG_IRQ_7    (1 << 3)
0142 #define WSS_CONFIG_IRQ_9    (2 << 3)
0143 #define WSS_CONFIG_IRQ_10   (3 << 3)
0144 #define WSS_CONFIG_IRQ_11   (4 << 3)
0145 
0146 #define WSS_PORT_CONFIG     0
0147 #define WSS_PORT_SIGNATURE  3
0148 
0149 #define WSS_SIGNATURE       4
0150 
0151 static int wss_detect(void __iomem *wss_port)
0152 {
0153     if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
0154         return -ENODEV;
0155 
0156     return 0;
0157 }
0158 
0159 static void wss_set_config(void __iomem *wss_port, u8 wss_config)
0160 {
0161     iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
0162 }
0163 
0164 /*
0165  * Aztech Sound Galaxy specifics
0166  */
0167 
0168 #define GALAXY_PORT_CONFIG  1024
0169 #define CONFIG_PORT_SET     4
0170 
0171 #define DSP_COMMAND_GALAXY_8    8
0172 #define GALAXY_COMMAND_GET_TYPE 5
0173 
0174 #define DSP_COMMAND_GALAXY_9    9
0175 #define GALAXY_COMMAND_WSSMODE  0
0176 #define GALAXY_COMMAND_SB8MODE  1
0177 
0178 #define GALAXY_MODE_WSS     GALAXY_COMMAND_WSSMODE
0179 #define GALAXY_MODE_SB8     GALAXY_COMMAND_SB8MODE
0180 
0181 struct snd_galaxy {
0182     void __iomem *port;
0183     void __iomem *config_port;
0184     void __iomem *wss_port;
0185     u32 config;
0186     struct resource *res_port;
0187     struct resource *res_config_port;
0188     struct resource *res_wss_port;
0189 };
0190 
0191 static u32 config[SNDRV_CARDS];
0192 static u8 wss_config[SNDRV_CARDS];
0193 
0194 static int snd_galaxy_match(struct device *dev, unsigned int n)
0195 {
0196     if (!enable[n])
0197         return 0;
0198 
0199     switch (port[n]) {
0200     case SNDRV_AUTO_PORT:
0201         dev_err(dev, "please specify port\n");
0202         return 0;
0203     case 0x220:
0204         config[n] |= GALAXY_CONFIG_SBA_220;
0205         break;
0206     case 0x240:
0207         config[n] |= GALAXY_CONFIG_SBA_240;
0208         break;
0209     case 0x260:
0210         config[n] |= GALAXY_CONFIG_SBA_260;
0211         break;
0212     case 0x280:
0213         config[n] |= GALAXY_CONFIG_SBA_280;
0214         break;
0215     default:
0216         dev_err(dev, "invalid port %#lx\n", port[n]);
0217         return 0;
0218     }
0219 
0220     switch (wss_port[n]) {
0221     case SNDRV_AUTO_PORT:
0222         dev_err(dev,  "please specify wss_port\n");
0223         return 0;
0224     case 0x530:
0225         config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
0226         break;
0227     case 0x604:
0228         config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
0229         break;
0230     case 0xe80:
0231         config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
0232         break;
0233     case 0xf40:
0234         config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
0235         break;
0236     default:
0237         dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
0238         return 0;
0239     }
0240 
0241     switch (irq[n]) {
0242     case SNDRV_AUTO_IRQ:
0243         dev_err(dev,  "please specify irq\n");
0244         return 0;
0245     case 7:
0246         wss_config[n] |= WSS_CONFIG_IRQ_7;
0247         break;
0248     case 2:
0249         irq[n] = 9;
0250         fallthrough;
0251     case 9:
0252         wss_config[n] |= WSS_CONFIG_IRQ_9;
0253         break;
0254     case 10:
0255         wss_config[n] |= WSS_CONFIG_IRQ_10;
0256         break;
0257     case 11:
0258         wss_config[n] |= WSS_CONFIG_IRQ_11;
0259         break;
0260     default:
0261         dev_err(dev, "invalid IRQ %d\n", irq[n]);
0262         return 0;
0263     }
0264 
0265     switch (dma1[n]) {
0266     case SNDRV_AUTO_DMA:
0267         dev_err(dev,  "please specify dma1\n");
0268         return 0;
0269     case 0:
0270         wss_config[n] |= WSS_CONFIG_DMA_0;
0271         break;
0272     case 1:
0273         wss_config[n] |= WSS_CONFIG_DMA_1;
0274         break;
0275     case 3:
0276         wss_config[n] |= WSS_CONFIG_DMA_3;
0277         break;
0278     default:
0279         dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
0280         return 0;
0281     }
0282 
0283     if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
0284         dma2[n] = -1;
0285         goto mpu;
0286     }
0287 
0288     wss_config[n] |= WSS_CONFIG_DUPLEX;
0289     switch (dma2[n]) {
0290     case 0:
0291         break;
0292     case 1:
0293         if (dma1[n] == 0)
0294             break;
0295         fallthrough;
0296     default:
0297         dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
0298         return 0;
0299     }
0300 
0301 mpu:
0302     switch (mpu_port[n]) {
0303     case SNDRV_AUTO_PORT:
0304         dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
0305         mpu_port[n] = -1;
0306         goto fm;
0307     case 0x300:
0308         config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
0309         break;
0310     case 0x330:
0311         config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
0312         break;
0313     default:
0314         dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
0315         return 0;
0316     }
0317 
0318     switch (mpu_irq[n]) {
0319     case SNDRV_AUTO_IRQ:
0320         dev_warn(dev, "mpu_irq not specified: using polling mode\n");
0321         mpu_irq[n] = -1;
0322         break;
0323     case 2:
0324         mpu_irq[n] = 9;
0325         fallthrough;
0326     case 9:
0327         config[n] |= GALAXY_CONFIG_MPUIRQ_2;
0328         break;
0329 #ifdef AZT1605
0330     case 3:
0331         config[n] |= GALAXY_CONFIG_MPUIRQ_3;
0332         break;
0333 #endif
0334     case 5:
0335         config[n] |= GALAXY_CONFIG_MPUIRQ_5;
0336         break;
0337     case 7:
0338         config[n] |= GALAXY_CONFIG_MPUIRQ_7;
0339         break;
0340 #ifdef AZT2316
0341     case 10:
0342         config[n] |= GALAXY_CONFIG_MPUIRQ_10;
0343         break;
0344 #endif
0345     default:
0346         dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
0347         return 0;
0348     }
0349 
0350     if (mpu_irq[n] == irq[n]) {
0351         dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
0352         return 0;
0353     }
0354 
0355 fm:
0356     switch (fm_port[n]) {
0357     case SNDRV_AUTO_PORT:
0358         dev_warn(dev, "fm_port not specified: not using OPL3\n");
0359         fm_port[n] = -1;
0360         break;
0361     case 0x388:
0362         break;
0363     default:
0364         dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
0365         return 0;
0366     }
0367 
0368     config[n] |= GALAXY_CONFIG_GAME_ENABLE;
0369     return 1;
0370 }
0371 
0372 static int galaxy_init(struct snd_galaxy *galaxy, u8 *type)
0373 {
0374     u8 major;
0375     u8 minor;
0376     int err;
0377 
0378     err = dsp_reset(galaxy->port);
0379     if (err < 0)
0380         return err;
0381 
0382     err = dsp_get_version(galaxy->port, &major, &minor);
0383     if (err < 0)
0384         return err;
0385 
0386     if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
0387         return -ENODEV;
0388 
0389     err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
0390     if (err < 0)
0391         return err;
0392 
0393     err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
0394     if (err < 0)
0395         return err;
0396 
0397     err = dsp_get_byte(galaxy->port, type);
0398     if (err < 0)
0399         return err;
0400 
0401     return 0;
0402 }
0403 
0404 static int galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
0405 {
0406     int err;
0407 
0408     err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
0409     if (err < 0)
0410         return err;
0411 
0412     err = dsp_command(galaxy->port, mode);
0413     if (err < 0)
0414         return err;
0415 
0416 #ifdef AZT1605
0417     /*
0418      * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
0419      */
0420     err = dsp_reset(galaxy->port);
0421     if (err < 0)
0422         return err;
0423 #endif
0424 
0425     return 0;
0426 }
0427 
0428 static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
0429 {
0430     u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
0431     int i;
0432 
0433     iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
0434     for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
0435         iowrite8(config, galaxy->config_port + i);
0436         config >>= 8;
0437     }
0438     iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
0439     msleep(10);
0440 }
0441 
0442 static void galaxy_config(struct snd_galaxy *galaxy, u32 config)
0443 {
0444     int i;
0445 
0446     for (i = GALAXY_CONFIG_SIZE; i; i--) {
0447         u8 tmp = ioread8(galaxy->config_port + i - 1);
0448         galaxy->config = (galaxy->config << 8) | tmp;
0449     }
0450     config |= galaxy->config & GALAXY_CONFIG_MASK;
0451     galaxy_set_config(galaxy, config);
0452 }
0453 
0454 static int galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
0455 {
0456     int err;
0457 
0458     err = wss_detect(galaxy->wss_port);
0459     if (err < 0)
0460         return err;
0461 
0462     wss_set_config(galaxy->wss_port, wss_config);
0463 
0464     err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
0465     if (err < 0)
0466         return err;
0467 
0468     return 0;
0469 }
0470 
0471 static void snd_galaxy_free(struct snd_card *card)
0472 {
0473     struct snd_galaxy *galaxy = card->private_data;
0474 
0475     if (galaxy->wss_port)
0476         wss_set_config(galaxy->wss_port, 0);
0477     if (galaxy->config_port)
0478         galaxy_set_config(galaxy, galaxy->config);
0479 }
0480 
0481 static int __snd_galaxy_probe(struct device *dev, unsigned int n)
0482 {
0483     struct snd_galaxy *galaxy;
0484     struct snd_wss *chip;
0485     struct snd_card *card;
0486     u8 type;
0487     int err;
0488 
0489     err = snd_devm_card_new(dev, index[n], id[n], THIS_MODULE,
0490                 sizeof(*galaxy), &card);
0491     if (err < 0)
0492         return err;
0493 
0494     card->private_free = snd_galaxy_free;
0495     galaxy = card->private_data;
0496 
0497     galaxy->res_port = devm_request_region(dev, port[n], 16, DRV_NAME);
0498     if (!galaxy->res_port) {
0499         dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
0500             port[n] + 15);
0501         return -EBUSY;
0502     }
0503     galaxy->port = devm_ioport_map(dev, port[n], 16);
0504     if (!galaxy->port)
0505         return -ENOMEM;
0506 
0507     err = galaxy_init(galaxy, &type);
0508     if (err < 0) {
0509         dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
0510         return err;
0511     }
0512     dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
0513 
0514     galaxy->res_config_port =
0515         devm_request_region(dev, port[n] + GALAXY_PORT_CONFIG, 16,
0516                     DRV_NAME);
0517     if (!galaxy->res_config_port) {
0518         dev_err(dev, "could not grab ports %#lx-%#lx\n",
0519             port[n] + GALAXY_PORT_CONFIG,
0520             port[n] + GALAXY_PORT_CONFIG + 15);
0521         return -EBUSY;
0522     }
0523     galaxy->config_port =
0524         devm_ioport_map(dev, port[n] + GALAXY_PORT_CONFIG, 16);
0525     if (!galaxy->config_port)
0526         return -ENOMEM;
0527     galaxy_config(galaxy, config[n]);
0528 
0529     galaxy->res_wss_port = devm_request_region(dev, wss_port[n], 4, DRV_NAME);
0530     if (!galaxy->res_wss_port)  {
0531         dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
0532             wss_port[n] + 3);
0533         return -EBUSY;
0534     }
0535     galaxy->wss_port = devm_ioport_map(dev, wss_port[n], 4);
0536     if (!galaxy->wss_port)
0537         return -ENOMEM;
0538 
0539     err = galaxy_wss_config(galaxy, wss_config[n]);
0540     if (err < 0) {
0541         dev_err(dev, "could not configure WSS\n");
0542         return err;
0543     }
0544 
0545     strcpy(card->driver, DRV_NAME);
0546     strcpy(card->shortname, DRV_NAME);
0547     sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
0548         card->shortname, port[n], wss_port[n], irq[n], dma1[n],
0549         dma2[n]);
0550 
0551     err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
0552                  dma2[n], WSS_HW_DETECT, 0, &chip);
0553     if (err < 0)
0554         return err;
0555 
0556     err = snd_wss_pcm(chip, 0);
0557     if (err < 0)
0558         return err;
0559 
0560     err = snd_wss_mixer(chip);
0561     if (err < 0)
0562         return err;
0563 
0564     err = snd_wss_timer(chip, 0);
0565     if (err < 0)
0566         return err;
0567 
0568     if (mpu_port[n] >= 0) {
0569         err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
0570                       mpu_port[n], 0, mpu_irq[n], NULL);
0571         if (err < 0)
0572             return err;
0573     }
0574 
0575     if (fm_port[n] >= 0) {
0576         struct snd_opl3 *opl3;
0577 
0578         err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
0579                       OPL3_HW_AUTO, 0, &opl3);
0580         if (err < 0) {
0581             dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
0582             return err;
0583         }
0584         err = snd_opl3_timer_new(opl3, 1, 2);
0585         if (err < 0)
0586             return err;
0587 
0588         err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
0589         if (err < 0)
0590             return err;
0591     }
0592 
0593     err = snd_card_register(card);
0594     if (err < 0)
0595         return err;
0596 
0597     dev_set_drvdata(dev, card);
0598     return 0;
0599 }
0600 
0601 static int snd_galaxy_probe(struct device *dev, unsigned int n)
0602 {
0603     return snd_card_free_on_error(dev, __snd_galaxy_probe(dev, n));
0604 }
0605 
0606 static struct isa_driver snd_galaxy_driver = {
0607     .match      = snd_galaxy_match,
0608     .probe      = snd_galaxy_probe,
0609 
0610     .driver     = {
0611         .name   = DEV_NAME
0612     }
0613 };
0614 
0615 module_isa_driver(snd_galaxy_driver, SNDRV_CARDS);