xref: /OK3568_Linux_fs/kernel/sound/isa/sb/sb_common.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4*4882a593Smuzhiyun  *                   Uros Bizjak <uros@kss-loka.si>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  Lowlevel routines for control of Sound Blaster cards
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/interrupt.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/ioport.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/io.h>
16*4882a593Smuzhiyun #include <sound/core.h>
17*4882a593Smuzhiyun #include <sound/sb.h>
18*4882a593Smuzhiyun #include <sound/initval.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <asm/dma.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
23*4882a593Smuzhiyun MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards");
24*4882a593Smuzhiyun MODULE_LICENSE("GPL");
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define BUSY_LOOPS 100000
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #undef IO_DEBUG
29*4882a593Smuzhiyun 
snd_sbdsp_command(struct snd_sb * chip,unsigned char val)30*4882a593Smuzhiyun int snd_sbdsp_command(struct snd_sb *chip, unsigned char val)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	int i;
33*4882a593Smuzhiyun #ifdef IO_DEBUG
34*4882a593Smuzhiyun 	snd_printk(KERN_DEBUG "command 0x%x\n", val);
35*4882a593Smuzhiyun #endif
36*4882a593Smuzhiyun 	for (i = BUSY_LOOPS; i; i--)
37*4882a593Smuzhiyun 		if ((inb(SBP(chip, STATUS)) & 0x80) == 0) {
38*4882a593Smuzhiyun 			outb(val, SBP(chip, COMMAND));
39*4882a593Smuzhiyun 			return 1;
40*4882a593Smuzhiyun 		}
41*4882a593Smuzhiyun 	snd_printd("%s [0x%lx]: timeout (0x%x)\n", __func__, chip->port, val);
42*4882a593Smuzhiyun 	return 0;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
snd_sbdsp_get_byte(struct snd_sb * chip)45*4882a593Smuzhiyun int snd_sbdsp_get_byte(struct snd_sb *chip)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	int val;
48*4882a593Smuzhiyun 	int i;
49*4882a593Smuzhiyun 	for (i = BUSY_LOOPS; i; i--) {
50*4882a593Smuzhiyun 		if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
51*4882a593Smuzhiyun 			val = inb(SBP(chip, READ));
52*4882a593Smuzhiyun #ifdef IO_DEBUG
53*4882a593Smuzhiyun 			snd_printk(KERN_DEBUG "get_byte 0x%x\n", val);
54*4882a593Smuzhiyun #endif
55*4882a593Smuzhiyun 			return val;
56*4882a593Smuzhiyun 		}
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 	snd_printd("%s [0x%lx]: timeout\n", __func__, chip->port);
59*4882a593Smuzhiyun 	return -ENODEV;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
snd_sbdsp_reset(struct snd_sb * chip)62*4882a593Smuzhiyun int snd_sbdsp_reset(struct snd_sb *chip)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	int i;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	outb(1, SBP(chip, RESET));
67*4882a593Smuzhiyun 	udelay(10);
68*4882a593Smuzhiyun 	outb(0, SBP(chip, RESET));
69*4882a593Smuzhiyun 	udelay(30);
70*4882a593Smuzhiyun 	for (i = BUSY_LOOPS; i; i--)
71*4882a593Smuzhiyun 		if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
72*4882a593Smuzhiyun 			if (inb(SBP(chip, READ)) == 0xaa)
73*4882a593Smuzhiyun 				return 0;
74*4882a593Smuzhiyun 			else
75*4882a593Smuzhiyun 				break;
76*4882a593Smuzhiyun 		}
77*4882a593Smuzhiyun 	snd_printdd("%s [0x%lx] failed...\n", __func__, chip->port);
78*4882a593Smuzhiyun 	return -ENODEV;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
snd_sbdsp_version(struct snd_sb * chip)81*4882a593Smuzhiyun static int snd_sbdsp_version(struct snd_sb * chip)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	unsigned int result;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	snd_sbdsp_command(chip, SB_DSP_GET_VERSION);
86*4882a593Smuzhiyun 	result = (short) snd_sbdsp_get_byte(chip) << 8;
87*4882a593Smuzhiyun 	result |= (short) snd_sbdsp_get_byte(chip);
88*4882a593Smuzhiyun 	return result;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
snd_sbdsp_probe(struct snd_sb * chip)91*4882a593Smuzhiyun static int snd_sbdsp_probe(struct snd_sb * chip)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	int version;
94*4882a593Smuzhiyun 	int major, minor;
95*4882a593Smuzhiyun 	char *str;
96*4882a593Smuzhiyun 	unsigned long flags;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	/*
99*4882a593Smuzhiyun 	 *  initialization sequence
100*4882a593Smuzhiyun 	 */
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	spin_lock_irqsave(&chip->reg_lock, flags);
103*4882a593Smuzhiyun 	if (snd_sbdsp_reset(chip) < 0) {
104*4882a593Smuzhiyun 		spin_unlock_irqrestore(&chip->reg_lock, flags);
105*4882a593Smuzhiyun 		return -ENODEV;
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 	version = snd_sbdsp_version(chip);
108*4882a593Smuzhiyun 	if (version < 0) {
109*4882a593Smuzhiyun 		spin_unlock_irqrestore(&chip->reg_lock, flags);
110*4882a593Smuzhiyun 		return -ENODEV;
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 	spin_unlock_irqrestore(&chip->reg_lock, flags);
113*4882a593Smuzhiyun 	major = version >> 8;
114*4882a593Smuzhiyun 	minor = version & 0xff;
115*4882a593Smuzhiyun 	snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
116*4882a593Smuzhiyun 		    chip->port, major, minor);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	switch (chip->hardware) {
119*4882a593Smuzhiyun 	case SB_HW_AUTO:
120*4882a593Smuzhiyun 		switch (major) {
121*4882a593Smuzhiyun 		case 1:
122*4882a593Smuzhiyun 			chip->hardware = SB_HW_10;
123*4882a593Smuzhiyun 			str = "1.0";
124*4882a593Smuzhiyun 			break;
125*4882a593Smuzhiyun 		case 2:
126*4882a593Smuzhiyun 			if (minor) {
127*4882a593Smuzhiyun 				chip->hardware = SB_HW_201;
128*4882a593Smuzhiyun 				str = "2.01+";
129*4882a593Smuzhiyun 			} else {
130*4882a593Smuzhiyun 				chip->hardware = SB_HW_20;
131*4882a593Smuzhiyun 				str = "2.0";
132*4882a593Smuzhiyun 			}
133*4882a593Smuzhiyun 			break;
134*4882a593Smuzhiyun 		case 3:
135*4882a593Smuzhiyun 			chip->hardware = SB_HW_PRO;
136*4882a593Smuzhiyun 			str = "Pro";
137*4882a593Smuzhiyun 			break;
138*4882a593Smuzhiyun 		case 4:
139*4882a593Smuzhiyun 			chip->hardware = SB_HW_16;
140*4882a593Smuzhiyun 			str = "16";
141*4882a593Smuzhiyun 			break;
142*4882a593Smuzhiyun 		default:
143*4882a593Smuzhiyun 			snd_printk(KERN_INFO "SB [0x%lx]: unknown DSP chip version %i.%i\n",
144*4882a593Smuzhiyun 				   chip->port, major, minor);
145*4882a593Smuzhiyun 			return -ENODEV;
146*4882a593Smuzhiyun 		}
147*4882a593Smuzhiyun 		break;
148*4882a593Smuzhiyun 	case SB_HW_ALS100:
149*4882a593Smuzhiyun 		str = "16 (ALS-100)";
150*4882a593Smuzhiyun 		break;
151*4882a593Smuzhiyun 	case SB_HW_ALS4000:
152*4882a593Smuzhiyun 		str = "16 (ALS-4000)";
153*4882a593Smuzhiyun 		break;
154*4882a593Smuzhiyun 	case SB_HW_DT019X:
155*4882a593Smuzhiyun 		str = "(DT019X/ALS007)";
156*4882a593Smuzhiyun 		break;
157*4882a593Smuzhiyun 	case SB_HW_CS5530:
158*4882a593Smuzhiyun 		str = "16 (CS5530)";
159*4882a593Smuzhiyun 		break;
160*4882a593Smuzhiyun 	case SB_HW_JAZZ16:
161*4882a593Smuzhiyun 		str = "Pro (Jazz16)";
162*4882a593Smuzhiyun 		break;
163*4882a593Smuzhiyun 	default:
164*4882a593Smuzhiyun 		return -ENODEV;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 	sprintf(chip->name, "Sound Blaster %s", str);
167*4882a593Smuzhiyun 	chip->version = (major << 8) | minor;
168*4882a593Smuzhiyun 	return 0;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
snd_sbdsp_free(struct snd_sb * chip)171*4882a593Smuzhiyun static int snd_sbdsp_free(struct snd_sb *chip)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	release_and_free_resource(chip->res_port);
174*4882a593Smuzhiyun 	if (chip->irq >= 0)
175*4882a593Smuzhiyun 		free_irq(chip->irq, (void *) chip);
176*4882a593Smuzhiyun #ifdef CONFIG_ISA
177*4882a593Smuzhiyun 	if (chip->dma8 >= 0) {
178*4882a593Smuzhiyun 		disable_dma(chip->dma8);
179*4882a593Smuzhiyun 		free_dma(chip->dma8);
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 	if (chip->dma16 >= 0 && chip->dma16 != chip->dma8) {
182*4882a593Smuzhiyun 		disable_dma(chip->dma16);
183*4882a593Smuzhiyun 		free_dma(chip->dma16);
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun #endif
186*4882a593Smuzhiyun 	kfree(chip);
187*4882a593Smuzhiyun 	return 0;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
snd_sbdsp_dev_free(struct snd_device * device)190*4882a593Smuzhiyun static int snd_sbdsp_dev_free(struct snd_device *device)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	struct snd_sb *chip = device->device_data;
193*4882a593Smuzhiyun 	return snd_sbdsp_free(chip);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
snd_sbdsp_create(struct snd_card * card,unsigned long port,int irq,irq_handler_t irq_handler,int dma8,int dma16,unsigned short hardware,struct snd_sb ** r_chip)196*4882a593Smuzhiyun int snd_sbdsp_create(struct snd_card *card,
197*4882a593Smuzhiyun 		     unsigned long port,
198*4882a593Smuzhiyun 		     int irq,
199*4882a593Smuzhiyun 		     irq_handler_t irq_handler,
200*4882a593Smuzhiyun 		     int dma8,
201*4882a593Smuzhiyun 		     int dma16,
202*4882a593Smuzhiyun 		     unsigned short hardware,
203*4882a593Smuzhiyun 		     struct snd_sb **r_chip)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	struct snd_sb *chip;
206*4882a593Smuzhiyun 	int err;
207*4882a593Smuzhiyun 	static const struct snd_device_ops ops = {
208*4882a593Smuzhiyun 		.dev_free =	snd_sbdsp_dev_free,
209*4882a593Smuzhiyun 	};
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	if (snd_BUG_ON(!r_chip))
212*4882a593Smuzhiyun 		return -EINVAL;
213*4882a593Smuzhiyun 	*r_chip = NULL;
214*4882a593Smuzhiyun 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
215*4882a593Smuzhiyun 	if (chip == NULL)
216*4882a593Smuzhiyun 		return -ENOMEM;
217*4882a593Smuzhiyun 	spin_lock_init(&chip->reg_lock);
218*4882a593Smuzhiyun 	spin_lock_init(&chip->open_lock);
219*4882a593Smuzhiyun 	spin_lock_init(&chip->midi_input_lock);
220*4882a593Smuzhiyun 	spin_lock_init(&chip->mixer_lock);
221*4882a593Smuzhiyun 	chip->irq = -1;
222*4882a593Smuzhiyun 	chip->dma8 = -1;
223*4882a593Smuzhiyun 	chip->dma16 = -1;
224*4882a593Smuzhiyun 	chip->port = port;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (request_irq(irq, irq_handler,
227*4882a593Smuzhiyun 			(hardware == SB_HW_ALS4000 ||
228*4882a593Smuzhiyun 			 hardware == SB_HW_CS5530) ?
229*4882a593Smuzhiyun 			IRQF_SHARED : 0,
230*4882a593Smuzhiyun 			"SoundBlaster", (void *) chip)) {
231*4882a593Smuzhiyun 		snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq);
232*4882a593Smuzhiyun 		snd_sbdsp_free(chip);
233*4882a593Smuzhiyun 		return -EBUSY;
234*4882a593Smuzhiyun 	}
235*4882a593Smuzhiyun 	chip->irq = irq;
236*4882a593Smuzhiyun 	card->sync_irq = chip->irq;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	if (hardware == SB_HW_ALS4000)
239*4882a593Smuzhiyun 		goto __skip_allocation;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if ((chip->res_port = request_region(port, 16, "SoundBlaster")) == NULL) {
242*4882a593Smuzhiyun 		snd_printk(KERN_ERR "sb: can't grab port 0x%lx\n", port);
243*4882a593Smuzhiyun 		snd_sbdsp_free(chip);
244*4882a593Smuzhiyun 		return -EBUSY;
245*4882a593Smuzhiyun 	}
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun #ifdef CONFIG_ISA
248*4882a593Smuzhiyun 	if (dma8 >= 0 && request_dma(dma8, "SoundBlaster - 8bit")) {
249*4882a593Smuzhiyun 		snd_printk(KERN_ERR "sb: can't grab DMA8 %d\n", dma8);
250*4882a593Smuzhiyun 		snd_sbdsp_free(chip);
251*4882a593Smuzhiyun 		return -EBUSY;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 	chip->dma8 = dma8;
254*4882a593Smuzhiyun 	if (dma16 >= 0) {
255*4882a593Smuzhiyun 		if (hardware != SB_HW_ALS100 && (dma16 < 5 || dma16 > 7)) {
256*4882a593Smuzhiyun 			/* no duplex */
257*4882a593Smuzhiyun 			dma16 = -1;
258*4882a593Smuzhiyun 		} else if (request_dma(dma16, "SoundBlaster - 16bit")) {
259*4882a593Smuzhiyun 			snd_printk(KERN_ERR "sb: can't grab DMA16 %d\n", dma16);
260*4882a593Smuzhiyun 			snd_sbdsp_free(chip);
261*4882a593Smuzhiyun 			return -EBUSY;
262*4882a593Smuzhiyun 		}
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 	chip->dma16 = dma16;
265*4882a593Smuzhiyun #endif
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun       __skip_allocation:
268*4882a593Smuzhiyun 	chip->card = card;
269*4882a593Smuzhiyun 	chip->hardware = hardware;
270*4882a593Smuzhiyun 	if ((err = snd_sbdsp_probe(chip)) < 0) {
271*4882a593Smuzhiyun 		snd_sbdsp_free(chip);
272*4882a593Smuzhiyun 		return err;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
275*4882a593Smuzhiyun 		snd_sbdsp_free(chip);
276*4882a593Smuzhiyun 		return err;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 	*r_chip = chip;
279*4882a593Smuzhiyun 	return 0;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbdsp_command);
283*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbdsp_get_byte);
284*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbdsp_reset);
285*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbdsp_create);
286*4882a593Smuzhiyun /* sb_mixer.c */
287*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbmixer_write);
288*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbmixer_read);
289*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbmixer_new);
290*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbmixer_add_ctl);
291*4882a593Smuzhiyun #ifdef CONFIG_PM
292*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbmixer_suspend);
293*4882a593Smuzhiyun EXPORT_SYMBOL(snd_sbmixer_resume);
294*4882a593Smuzhiyun #endif
295