brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 8726778 Raw
221 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>5 */6 7#include <linux/init.h>8#include <linux/err.h>9#include <linux/isa.h>10#include <linux/ioport.h>11#include <linux/module.h>12#include <sound/core.h>13#include <sound/sb.h>14#include <sound/opl3.h>15#include <sound/initval.h>16 17MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");18MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro");19MODULE_LICENSE("GPL");20 21static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */22static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */23static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */24static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260 */25static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */26static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 1,3 */27 28module_param_array(index, int, NULL, 0444);29MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard.");30module_param_array(id, charp, NULL, 0444);31MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard.");32module_param_array(enable, bool, NULL, 0444);33MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard.");34module_param_hw_array(port, long, ioport, NULL, 0444);35MODULE_PARM_DESC(port, "Port # for SB8 driver.");36module_param_hw_array(irq, int, irq, NULL, 0444);37MODULE_PARM_DESC(irq, "IRQ # for SB8 driver.");38module_param_hw_array(dma8, int, dma, NULL, 0444);39MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");40 41struct snd_sb8 {42	struct resource *fm_res;	/* used to block FM i/o region for legacy cards */43	struct snd_sb *chip;44};45 46static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)47{48	struct snd_sb *chip = dev_id;49 50	if (chip->open & SB_OPEN_PCM) {51		return snd_sb8dsp_interrupt(chip);52	} else {53		return snd_sb8dsp_midi_interrupt(chip);54	}55}56 57static int snd_sb8_match(struct device *pdev, unsigned int dev)58{59	if (!enable[dev])60		return 0;61	if (irq[dev] == SNDRV_AUTO_IRQ) {62		dev_err(pdev, "please specify irq\n");63		return 0;64	}65	if (dma8[dev] == SNDRV_AUTO_DMA) {66		dev_err(pdev, "please specify dma8\n");67		return 0;68	}69	return 1;70}71 72static int snd_sb8_probe(struct device *pdev, unsigned int dev)73{74	struct snd_sb *chip;75	struct snd_card *card;76	struct snd_sb8 *acard;77	struct snd_opl3 *opl3;78	int err;79 80	err = snd_devm_card_new(pdev, index[dev], id[dev], THIS_MODULE,81				sizeof(struct snd_sb8), &card);82	if (err < 0)83		return err;84	acard = card->private_data;85 86	/*87	 * Block the 0x388 port to avoid PnP conflicts.88	 * No need to check this value after request_region,89	 * as we never do anything with it.90	 */91	acard->fm_res = devm_request_region(card->dev, 0x388, 4,92					    "SoundBlaster FM");93 94	if (port[dev] != SNDRV_AUTO_PORT) {95		err = snd_sbdsp_create(card, port[dev], irq[dev],96				       snd_sb8_interrupt, dma8[dev],97				       -1, SB_HW_AUTO, &chip);98		if (err < 0)99			return err;100	} else {101		/* auto-probe legacy ports */102		static const unsigned long possible_ports[] = {103			0x220, 0x240, 0x260,104		};105		int i;106		for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {107			err = snd_sbdsp_create(card, possible_ports[i],108					       irq[dev],109					       snd_sb8_interrupt,110					       dma8[dev],111					       -1,112					       SB_HW_AUTO,113					       &chip);114			if (err >= 0) {115				port[dev] = possible_ports[i];116				break;117			}118		}119		if (i >= ARRAY_SIZE(possible_ports))120			return -EINVAL;121	}122	acard->chip = chip;123			124	if (chip->hardware >= SB_HW_16) {125		if (chip->hardware == SB_HW_ALS100)126			dev_warn(pdev, "ALS100 chip detected at 0x%lx, try snd-als100 module\n",127				 port[dev]);128		else129			dev_warn(pdev, "SB 16 chip detected at 0x%lx, try snd-sb16 module\n",130				 port[dev]);131		return -ENODEV;132	}133 134	err = snd_sb8dsp_pcm(chip, 0);135	if (err < 0)136		return err;137 138	err = snd_sbmixer_new(chip);139	if (err < 0)140		return err;141 142	if (chip->hardware == SB_HW_10 || chip->hardware == SB_HW_20) {143		err = snd_opl3_create(card, chip->port + 8, 0,144				      OPL3_HW_AUTO, 1, &opl3);145		if (err < 0)146			dev_warn(pdev, "sb8: no OPL device at 0x%lx\n", chip->port + 8);147	} else {148		err = snd_opl3_create(card, chip->port, chip->port + 2,149				      OPL3_HW_AUTO, 1, &opl3);150		if (err < 0) {151			dev_warn(pdev, "sb8: no OPL device at 0x%lx-0x%lx\n",152				   chip->port, chip->port + 2);153		}154	}155	if (err >= 0) {156		err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);157		if (err < 0)158			return err;159	}160 161	err = snd_sb8dsp_midi(chip, 0);162	if (err < 0)163		return err;164 165	strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");166	strcpy(card->shortname, chip->name);167	sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",168		chip->name,169		chip->port,170		irq[dev], dma8[dev]);171 172	err = snd_card_register(card);173	if (err < 0)174		return err;175 176	dev_set_drvdata(pdev, card);177	return 0;178}179 180#ifdef CONFIG_PM181static int snd_sb8_suspend(struct device *dev, unsigned int n,182			   pm_message_t state)183{184	struct snd_card *card = dev_get_drvdata(dev);185	struct snd_sb8 *acard = card->private_data;186	struct snd_sb *chip = acard->chip;187 188	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);189	snd_sbmixer_suspend(chip);190	return 0;191}192 193static int snd_sb8_resume(struct device *dev, unsigned int n)194{195	struct snd_card *card = dev_get_drvdata(dev);196	struct snd_sb8 *acard = card->private_data;197	struct snd_sb *chip = acard->chip;198 199	snd_sbdsp_reset(chip);200	snd_sbmixer_resume(chip);201	snd_power_change_state(card, SNDRV_CTL_POWER_D0);202	return 0;203}204#endif205 206#define DEV_NAME "sb8"207 208static struct isa_driver snd_sb8_driver = {209	.match		= snd_sb8_match,210	.probe		= snd_sb8_probe,211#ifdef CONFIG_PM212	.suspend	= snd_sb8_suspend,213	.resume		= snd_sb8_resume,214#endif215	.driver		= {216		.name	= DEV_NAME 217	},218};219 220module_isa_driver(snd_sb8_driver, SNDRV_CARDS);221