Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible
0004  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0005  */
0006 
0007 #include <linux/init.h>
0008 #include <linux/err.h>
0009 #include <linux/isa.h>
0010 #include <linux/ioport.h>
0011 #include <linux/module.h>
0012 #include <sound/core.h>
0013 #include <sound/sb.h>
0014 #include <sound/opl3.h>
0015 #include <sound/initval.h>
0016 
0017 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
0018 MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro");
0019 MODULE_LICENSE("GPL");
0020 
0021 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;  /* Index 0-MAX */
0022 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;   /* ID for this card */
0023 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
0024 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
0025 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* 5,7,9,10 */
0026 static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;   /* 1,3 */
0027 
0028 module_param_array(index, int, NULL, 0444);
0029 MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard.");
0030 module_param_array(id, charp, NULL, 0444);
0031 MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard.");
0032 module_param_array(enable, bool, NULL, 0444);
0033 MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard.");
0034 module_param_hw_array(port, long, ioport, NULL, 0444);
0035 MODULE_PARM_DESC(port, "Port # for SB8 driver.");
0036 module_param_hw_array(irq, int, irq, NULL, 0444);
0037 MODULE_PARM_DESC(irq, "IRQ # for SB8 driver.");
0038 module_param_hw_array(dma8, int, dma, NULL, 0444);
0039 MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");
0040 
0041 struct snd_sb8 {
0042     struct resource *fm_res;    /* used to block FM i/o region for legacy cards */
0043     struct snd_sb *chip;
0044 };
0045 
0046 static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
0047 {
0048     struct snd_sb *chip = dev_id;
0049 
0050     if (chip->open & SB_OPEN_PCM) {
0051         return snd_sb8dsp_interrupt(chip);
0052     } else {
0053         return snd_sb8dsp_midi_interrupt(chip);
0054     }
0055 }
0056 
0057 static int snd_sb8_match(struct device *pdev, unsigned int dev)
0058 {
0059     if (!enable[dev])
0060         return 0;
0061     if (irq[dev] == SNDRV_AUTO_IRQ) {
0062         dev_err(pdev, "please specify irq\n");
0063         return 0;
0064     }
0065     if (dma8[dev] == SNDRV_AUTO_DMA) {
0066         dev_err(pdev, "please specify dma8\n");
0067         return 0;
0068     }
0069     return 1;
0070 }
0071 
0072 static int snd_sb8_probe(struct device *pdev, unsigned int dev)
0073 {
0074     struct snd_sb *chip;
0075     struct snd_card *card;
0076     struct snd_sb8 *acard;
0077     struct snd_opl3 *opl3;
0078     int err;
0079 
0080     err = snd_devm_card_new(pdev, index[dev], id[dev], THIS_MODULE,
0081                 sizeof(struct snd_sb8), &card);
0082     if (err < 0)
0083         return err;
0084     acard = card->private_data;
0085 
0086     /*
0087      * Block the 0x388 port to avoid PnP conflicts.
0088      * No need to check this value after request_region,
0089      * as we never do anything with it.
0090      */
0091     acard->fm_res = devm_request_region(card->dev, 0x388, 4,
0092                         "SoundBlaster FM");
0093 
0094     if (port[dev] != SNDRV_AUTO_PORT) {
0095         err = snd_sbdsp_create(card, port[dev], irq[dev],
0096                        snd_sb8_interrupt, dma8[dev],
0097                        -1, SB_HW_AUTO, &chip);
0098         if (err < 0)
0099             return err;
0100     } else {
0101         /* auto-probe legacy ports */
0102         static const unsigned long possible_ports[] = {
0103             0x220, 0x240, 0x260,
0104         };
0105         int i;
0106         for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
0107             err = snd_sbdsp_create(card, possible_ports[i],
0108                            irq[dev],
0109                            snd_sb8_interrupt,
0110                            dma8[dev],
0111                            -1,
0112                            SB_HW_AUTO,
0113                            &chip);
0114             if (err >= 0) {
0115                 port[dev] = possible_ports[i];
0116                 break;
0117             }
0118         }
0119         if (i >= ARRAY_SIZE(possible_ports))
0120             return -EINVAL;
0121     }
0122     acard->chip = chip;
0123             
0124     if (chip->hardware >= SB_HW_16) {
0125         if (chip->hardware == SB_HW_ALS100)
0126             snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n",
0127                     port[dev]);
0128         else
0129             snd_printk(KERN_WARNING "SB 16 chip detected at 0x%lx, try snd-sb16 module\n",
0130                    port[dev]);
0131         return -ENODEV;
0132     }
0133 
0134     err = snd_sb8dsp_pcm(chip, 0);
0135     if (err < 0)
0136         return err;
0137 
0138     err = snd_sbmixer_new(chip);
0139     if (err < 0)
0140         return err;
0141 
0142     if (chip->hardware == SB_HW_10 || chip->hardware == SB_HW_20) {
0143         err = snd_opl3_create(card, chip->port + 8, 0,
0144                       OPL3_HW_AUTO, 1, &opl3);
0145         if (err < 0)
0146             snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx\n", chip->port + 8);
0147     } else {
0148         err = snd_opl3_create(card, chip->port, chip->port + 2,
0149                       OPL3_HW_AUTO, 1, &opl3);
0150         if (err < 0) {
0151             snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx-0x%lx\n",
0152                    chip->port, chip->port + 2);
0153         }
0154     }
0155     if (err >= 0) {
0156         err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
0157         if (err < 0)
0158             return err;
0159     }
0160 
0161     err = snd_sb8dsp_midi(chip, 0);
0162     if (err < 0)
0163         return err;
0164 
0165     strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
0166     strcpy(card->shortname, chip->name);
0167     sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
0168         chip->name,
0169         chip->port,
0170         irq[dev], dma8[dev]);
0171 
0172     err = snd_card_register(card);
0173     if (err < 0)
0174         return err;
0175 
0176     dev_set_drvdata(pdev, card);
0177     return 0;
0178 }
0179 
0180 #ifdef CONFIG_PM
0181 static int snd_sb8_suspend(struct device *dev, unsigned int n,
0182                pm_message_t state)
0183 {
0184     struct snd_card *card = dev_get_drvdata(dev);
0185     struct snd_sb8 *acard = card->private_data;
0186     struct snd_sb *chip = acard->chip;
0187 
0188     snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
0189     snd_sbmixer_suspend(chip);
0190     return 0;
0191 }
0192 
0193 static int snd_sb8_resume(struct device *dev, unsigned int n)
0194 {
0195     struct snd_card *card = dev_get_drvdata(dev);
0196     struct snd_sb8 *acard = card->private_data;
0197     struct snd_sb *chip = acard->chip;
0198 
0199     snd_sbdsp_reset(chip);
0200     snd_sbmixer_resume(chip);
0201     snd_power_change_state(card, SNDRV_CTL_POWER_D0);
0202     return 0;
0203 }
0204 #endif
0205 
0206 #define DEV_NAME "sb8"
0207 
0208 static struct isa_driver snd_sb8_driver = {
0209     .match      = snd_sb8_match,
0210     .probe      = snd_sb8_probe,
0211 #ifdef CONFIG_PM
0212     .suspend    = snd_sb8_suspend,
0213     .resume     = snd_sb8_resume,
0214 #endif
0215     .driver     = {
0216         .name   = DEV_NAME 
0217     },
0218 };
0219 
0220 module_isa_driver(snd_sb8_driver, SNDRV_CARDS);