Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Feb 10-13, 2025
Register
Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible
  4 *  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");
 20MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}");
 21
 22static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 23static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 24static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
 25static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260 */
 26static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
 27static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 1,3 */
 28
 29module_param_array(index, int, NULL, 0444);
 30MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard.");
 31module_param_array(id, charp, NULL, 0444);
 32MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard.");
 33module_param_array(enable, bool, NULL, 0444);
 34MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard.");
 35module_param_hw_array(port, long, ioport, NULL, 0444);
 36MODULE_PARM_DESC(port, "Port # for SB8 driver.");
 37module_param_hw_array(irq, int, irq, NULL, 0444);
 38MODULE_PARM_DESC(irq, "IRQ # for SB8 driver.");
 39module_param_hw_array(dma8, int, dma, NULL, 0444);
 40MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");
 41
 42struct snd_sb8 {
 43	struct resource *fm_res;	/* used to block FM i/o region for legacy cards */
 44	struct snd_sb *chip;
 45};
 46
 47static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
 48{
 49	struct snd_sb *chip = dev_id;
 50
 51	if (chip->open & SB_OPEN_PCM) {
 52		return snd_sb8dsp_interrupt(chip);
 53	} else {
 54		return snd_sb8dsp_midi_interrupt(chip);
 55	}
 56}
 57
 58static void snd_sb8_free(struct snd_card *card)
 59{
 60	struct snd_sb8 *acard = card->private_data;
 61
 62	if (acard == NULL)
 63		return;
 64	release_and_free_resource(acard->fm_res);
 65}
 66
 67static int snd_sb8_match(struct device *pdev, unsigned int dev)
 68{
 69	if (!enable[dev])
 70		return 0;
 71	if (irq[dev] == SNDRV_AUTO_IRQ) {
 72		dev_err(pdev, "please specify irq\n");
 73		return 0;
 74	}
 75	if (dma8[dev] == SNDRV_AUTO_DMA) {
 76		dev_err(pdev, "please specify dma8\n");
 77		return 0;
 78	}
 79	return 1;
 80}
 81
 82static int snd_sb8_probe(struct device *pdev, unsigned int dev)
 83{
 84	struct snd_sb *chip;
 85	struct snd_card *card;
 86	struct snd_sb8 *acard;
 87	struct snd_opl3 *opl3;
 88	int err;
 89
 90	err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
 91			   sizeof(struct snd_sb8), &card);
 92	if (err < 0)
 93		return err;
 94	acard = card->private_data;
 95	card->private_free = snd_sb8_free;
 96
 97	/* block the 0x388 port to avoid PnP conflicts */
 98	acard->fm_res = request_region(0x388, 4, "SoundBlaster FM");
 99	if (!acard->fm_res) {
100		err = -EBUSY;
101		goto _err;
102	}
 
103
104	if (port[dev] != SNDRV_AUTO_PORT) {
105		if ((err = snd_sbdsp_create(card, port[dev], irq[dev],
106					    snd_sb8_interrupt,
107					    dma8[dev],
108					    -1,
109					    SB_HW_AUTO,
110					    &chip)) < 0)
111			goto _err;
112	} else {
113		/* auto-probe legacy ports */
114		static unsigned long possible_ports[] = {
115			0x220, 0x240, 0x260,
116		};
117		int i;
118		for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
119			err = snd_sbdsp_create(card, possible_ports[i],
120					       irq[dev],
121					       snd_sb8_interrupt,
122					       dma8[dev],
123					       -1,
124					       SB_HW_AUTO,
125					       &chip);
126			if (err >= 0) {
127				port[dev] = possible_ports[i];
128				break;
129			}
130		}
131		if (i >= ARRAY_SIZE(possible_ports)) {
132			err = -EINVAL;
133			goto _err;
134		}
135	}
136	acard->chip = chip;
137			
138	if (chip->hardware >= SB_HW_16) {
139		if (chip->hardware == SB_HW_ALS100)
140			snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n",
141				    port[dev]);
142		else
143			snd_printk(KERN_WARNING "SB 16 chip detected at 0x%lx, try snd-sb16 module\n",
144				   port[dev]);
145		err = -ENODEV;
146		goto _err;
147	}
148
149	if ((err = snd_sb8dsp_pcm(chip, 0)) < 0)
150		goto _err;
 
151
152	if ((err = snd_sbmixer_new(chip)) < 0)
153		goto _err;
 
154
155	if (chip->hardware == SB_HW_10 || chip->hardware == SB_HW_20) {
156		if ((err = snd_opl3_create(card, chip->port + 8, 0,
157					   OPL3_HW_AUTO, 1,
158					   &opl3)) < 0) {
159			snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx\n", chip->port + 8);
160		}
161	} else {
162		if ((err = snd_opl3_create(card, chip->port, chip->port + 2,
163					   OPL3_HW_AUTO, 1,
164					   &opl3)) < 0) {
165			snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx-0x%lx\n",
166				   chip->port, chip->port + 2);
167		}
168	}
169	if (err >= 0) {
170		if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0)
171			goto _err;
 
172	}
173
174	if ((err = snd_sb8dsp_midi(chip, 0)) < 0)
175		goto _err;
 
176
177	strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
178	strcpy(card->shortname, chip->name);
179	sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
180		chip->name,
181		chip->port,
182		irq[dev], dma8[dev]);
183
184	if ((err = snd_card_register(card)) < 0)
185		goto _err;
 
186
187	dev_set_drvdata(pdev, card);
188	return 0;
189
190 _err:
191	snd_card_free(card);
192	return err;
193}
194
195static int snd_sb8_remove(struct device *pdev, unsigned int dev)
196{
197	snd_card_free(dev_get_drvdata(pdev));
198	return 0;
199}
200
201#ifdef CONFIG_PM
202static int snd_sb8_suspend(struct device *dev, unsigned int n,
203			   pm_message_t state)
204{
205	struct snd_card *card = dev_get_drvdata(dev);
206	struct snd_sb8 *acard = card->private_data;
207	struct snd_sb *chip = acard->chip;
208
209	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
210	snd_sbmixer_suspend(chip);
211	return 0;
212}
213
214static int snd_sb8_resume(struct device *dev, unsigned int n)
215{
216	struct snd_card *card = dev_get_drvdata(dev);
217	struct snd_sb8 *acard = card->private_data;
218	struct snd_sb *chip = acard->chip;
219
220	snd_sbdsp_reset(chip);
221	snd_sbmixer_resume(chip);
222	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
223	return 0;
224}
225#endif
226
227#define DEV_NAME "sb8"
228
229static struct isa_driver snd_sb8_driver = {
230	.match		= snd_sb8_match,
231	.probe		= snd_sb8_probe,
232	.remove		= snd_sb8_remove,
233#ifdef CONFIG_PM
234	.suspend	= snd_sb8_suspend,
235	.resume		= snd_sb8_resume,
236#endif
237	.driver		= {
238		.name	= DEV_NAME 
239	},
240};
241
242module_isa_driver(snd_sb8_driver, SNDRV_CARDS);
v6.8
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible
  4 *  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			snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n",
127				    port[dev]);
128		else
129			snd_printk(KERN_WARNING "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			snd_printk(KERN_WARNING "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			snd_printk(KERN_WARNING "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_PM
181static 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#endif
205
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_PM
212	.suspend	= snd_sb8_suspend,
213	.resume		= snd_sb8_resume,
214#endif
215	.driver		= {
216		.name	= DEV_NAME 
217	},
218};
219
220module_isa_driver(snd_sb8_driver, SNDRV_CARDS);