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