1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4 * Uros Bizjak <uros@kss-loka.si>
6 * Lowlevel routines for control of Sound Blaster cards
9 #include <linux/delay.h>
10 #include <linux/init.h>
11 #include <linux/interrupt.h>
12 #include <linux/slab.h>
13 #include <linux/ioport.h>
14 #include <linux/module.h>
16 #include <sound/core.h>
18 #include <sound/initval.h>
22 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
23 MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards");
24 MODULE_LICENSE("GPL");
26 #define BUSY_LOOPS 100000
30 int snd_sbdsp_command(struct snd_sb
*chip
, unsigned char val
)
34 snd_printk(KERN_DEBUG
"command 0x%x\n", val
);
36 for (i
= BUSY_LOOPS
; i
; i
--)
37 if ((inb(SBP(chip
, STATUS
)) & 0x80) == 0) {
38 outb(val
, SBP(chip
, COMMAND
));
41 snd_printd("%s [0x%lx]: timeout (0x%x)\n", __func__
, chip
->port
, val
);
45 int snd_sbdsp_get_byte(struct snd_sb
*chip
)
49 for (i
= BUSY_LOOPS
; i
; i
--) {
50 if (inb(SBP(chip
, DATA_AVAIL
)) & 0x80) {
51 val
= inb(SBP(chip
, READ
));
53 snd_printk(KERN_DEBUG
"get_byte 0x%x\n", val
);
58 snd_printd("%s [0x%lx]: timeout\n", __func__
, chip
->port
);
62 int snd_sbdsp_reset(struct snd_sb
*chip
)
66 outb(1, SBP(chip
, RESET
));
68 outb(0, SBP(chip
, RESET
));
70 for (i
= BUSY_LOOPS
; i
; i
--)
71 if (inb(SBP(chip
, DATA_AVAIL
)) & 0x80) {
72 if (inb(SBP(chip
, READ
)) == 0xaa)
77 snd_printdd("%s [0x%lx] failed...\n", __func__
, chip
->port
);
81 static int snd_sbdsp_version(struct snd_sb
* chip
)
85 snd_sbdsp_command(chip
, SB_DSP_GET_VERSION
);
86 result
= (short) snd_sbdsp_get_byte(chip
) << 8;
87 result
|= (short) snd_sbdsp_get_byte(chip
);
91 static int snd_sbdsp_probe(struct snd_sb
* chip
)
99 * initialization sequence
102 spin_lock_irqsave(&chip
->reg_lock
, flags
);
103 if (snd_sbdsp_reset(chip
) < 0) {
104 spin_unlock_irqrestore(&chip
->reg_lock
, flags
);
107 version
= snd_sbdsp_version(chip
);
109 spin_unlock_irqrestore(&chip
->reg_lock
, flags
);
112 spin_unlock_irqrestore(&chip
->reg_lock
, flags
);
113 major
= version
>> 8;
114 minor
= version
& 0xff;
115 snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
116 chip
->port
, major
, minor
);
118 switch (chip
->hardware
) {
122 chip
->hardware
= SB_HW_10
;
127 chip
->hardware
= SB_HW_201
;
130 chip
->hardware
= SB_HW_20
;
135 chip
->hardware
= SB_HW_PRO
;
139 chip
->hardware
= SB_HW_16
;
143 snd_printk(KERN_INFO
"SB [0x%lx]: unknown DSP chip version %i.%i\n",
144 chip
->port
, major
, minor
);
149 str
= "16 (ALS-100)";
152 str
= "16 (ALS-4000)";
155 str
= "(DT019X/ALS007)";
161 str
= "Pro (Jazz16)";
166 sprintf(chip
->name
, "Sound Blaster %s", str
);
167 chip
->version
= (major
<< 8) | minor
;
171 static int snd_sbdsp_free(struct snd_sb
*chip
)
173 release_and_free_resource(chip
->res_port
);
175 free_irq(chip
->irq
, (void *) chip
);
177 if (chip
->dma8
>= 0) {
178 disable_dma(chip
->dma8
);
179 free_dma(chip
->dma8
);
181 if (chip
->dma16
>= 0 && chip
->dma16
!= chip
->dma8
) {
182 disable_dma(chip
->dma16
);
183 free_dma(chip
->dma16
);
190 static int snd_sbdsp_dev_free(struct snd_device
*device
)
192 struct snd_sb
*chip
= device
->device_data
;
193 return snd_sbdsp_free(chip
);
196 int snd_sbdsp_create(struct snd_card
*card
,
199 irq_handler_t irq_handler
,
202 unsigned short hardware
,
203 struct snd_sb
**r_chip
)
207 static const struct snd_device_ops ops
= {
208 .dev_free
= snd_sbdsp_dev_free
,
211 if (snd_BUG_ON(!r_chip
))
214 chip
= kzalloc(sizeof(*chip
), GFP_KERNEL
);
217 spin_lock_init(&chip
->reg_lock
);
218 spin_lock_init(&chip
->open_lock
);
219 spin_lock_init(&chip
->midi_input_lock
);
220 spin_lock_init(&chip
->mixer_lock
);
226 if (request_irq(irq
, irq_handler
,
227 (hardware
== SB_HW_ALS4000
||
228 hardware
== SB_HW_CS5530
) ?
230 "SoundBlaster", (void *) chip
)) {
231 snd_printk(KERN_ERR
"sb: can't grab irq %d\n", irq
);
232 snd_sbdsp_free(chip
);
236 card
->sync_irq
= chip
->irq
;
238 if (hardware
== SB_HW_ALS4000
)
239 goto __skip_allocation
;
241 if ((chip
->res_port
= request_region(port
, 16, "SoundBlaster")) == NULL
) {
242 snd_printk(KERN_ERR
"sb: can't grab port 0x%lx\n", port
);
243 snd_sbdsp_free(chip
);
248 if (dma8
>= 0 && request_dma(dma8
, "SoundBlaster - 8bit")) {
249 snd_printk(KERN_ERR
"sb: can't grab DMA8 %d\n", dma8
);
250 snd_sbdsp_free(chip
);
255 if (hardware
!= SB_HW_ALS100
&& (dma16
< 5 || dma16
> 7)) {
258 } else if (request_dma(dma16
, "SoundBlaster - 16bit")) {
259 snd_printk(KERN_ERR
"sb: can't grab DMA16 %d\n", dma16
);
260 snd_sbdsp_free(chip
);
269 chip
->hardware
= hardware
;
270 if ((err
= snd_sbdsp_probe(chip
)) < 0) {
271 snd_sbdsp_free(chip
);
274 if ((err
= snd_device_new(card
, SNDRV_DEV_LOWLEVEL
, chip
, &ops
)) < 0) {
275 snd_sbdsp_free(chip
);
282 EXPORT_SYMBOL(snd_sbdsp_command
);
283 EXPORT_SYMBOL(snd_sbdsp_get_byte
);
284 EXPORT_SYMBOL(snd_sbdsp_reset
);
285 EXPORT_SYMBOL(snd_sbdsp_create
);
287 EXPORT_SYMBOL(snd_sbmixer_write
);
288 EXPORT_SYMBOL(snd_sbmixer_read
);
289 EXPORT_SYMBOL(snd_sbmixer_new
);
290 EXPORT_SYMBOL(snd_sbmixer_add_ctl
);
292 EXPORT_SYMBOL(snd_sbmixer_suspend
);
293 EXPORT_SYMBOL(snd_sbmixer_resume
);