2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
3 * Uros Bizjak <uros@kss-loka.si>
5 * Lowlevel routines for control of Sound Blaster cards
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/delay.h>
24 #include <linux/init.h>
25 #include <linux/interrupt.h>
26 #include <linux/slab.h>
27 #include <linux/ioport.h>
28 #include <sound/core.h>
30 #include <sound/initval.h>
35 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
36 MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards");
37 MODULE_LICENSE("GPL");
39 #define BUSY_LOOPS 100000
43 int snd_sbdsp_command(struct snd_sb
*chip
, unsigned char val
)
47 snd_printk(KERN_DEBUG
"command 0x%x\n", val
);
49 for (i
= BUSY_LOOPS
; i
; i
--)
50 if ((inb(SBP(chip
, STATUS
)) & 0x80) == 0) {
51 outb(val
, SBP(chip
, COMMAND
));
54 snd_printd("%s [0x%lx]: timeout (0x%x)\n", __func__
, chip
->port
, val
);
58 int snd_sbdsp_get_byte(struct snd_sb
*chip
)
62 for (i
= BUSY_LOOPS
; i
; i
--) {
63 if (inb(SBP(chip
, DATA_AVAIL
)) & 0x80) {
64 val
= inb(SBP(chip
, READ
));
66 snd_printk(KERN_DEBUG
"get_byte 0x%x\n", val
);
71 snd_printd("%s [0x%lx]: timeout\n", __func__
, chip
->port
);
75 int snd_sbdsp_reset(struct snd_sb
*chip
)
79 outb(1, SBP(chip
, RESET
));
81 outb(0, SBP(chip
, RESET
));
83 for (i
= BUSY_LOOPS
; i
; i
--)
84 if (inb(SBP(chip
, DATA_AVAIL
)) & 0x80) {
85 if (inb(SBP(chip
, READ
)) == 0xaa)
90 snd_printdd("%s [0x%lx] failed...\n", __func__
, chip
->port
);
94 static int snd_sbdsp_version(struct snd_sb
* chip
)
96 unsigned int result
= -ENODEV
;
98 snd_sbdsp_command(chip
, SB_DSP_GET_VERSION
);
99 result
= (short) snd_sbdsp_get_byte(chip
) << 8;
100 result
|= (short) snd_sbdsp_get_byte(chip
);
104 static int snd_sbdsp_probe(struct snd_sb
* chip
)
112 * initialization sequence
115 spin_lock_irqsave(&chip
->reg_lock
, flags
);
116 if (snd_sbdsp_reset(chip
) < 0) {
117 spin_unlock_irqrestore(&chip
->reg_lock
, flags
);
120 version
= snd_sbdsp_version(chip
);
122 spin_unlock_irqrestore(&chip
->reg_lock
, flags
);
125 spin_unlock_irqrestore(&chip
->reg_lock
, flags
);
126 major
= version
>> 8;
127 minor
= version
& 0xff;
128 snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
129 chip
->port
, major
, minor
);
131 switch (chip
->hardware
) {
135 chip
->hardware
= SB_HW_10
;
140 chip
->hardware
= SB_HW_201
;
143 chip
->hardware
= SB_HW_20
;
148 chip
->hardware
= SB_HW_PRO
;
152 chip
->hardware
= SB_HW_16
;
156 snd_printk(KERN_INFO
"SB [0x%lx]: unknown DSP chip version %i.%i\n",
157 chip
->port
, major
, minor
);
162 str
= "16 (ALS-100)";
165 str
= "16 (ALS-4000)";
168 str
= "(DT019X/ALS007)";
174 str
= "Pro (Jazz16)";
179 sprintf(chip
->name
, "Sound Blaster %s", str
);
180 chip
->version
= (major
<< 8) | minor
;
184 static int snd_sbdsp_free(struct snd_sb
*chip
)
187 release_and_free_resource(chip
->res_port
);
189 free_irq(chip
->irq
, (void *) chip
);
191 if (chip
->dma8
>= 0) {
192 disable_dma(chip
->dma8
);
193 free_dma(chip
->dma8
);
195 if (chip
->dma16
>= 0 && chip
->dma16
!= chip
->dma8
) {
196 disable_dma(chip
->dma16
);
197 free_dma(chip
->dma16
);
204 static int snd_sbdsp_dev_free(struct snd_device
*device
)
206 struct snd_sb
*chip
= device
->device_data
;
207 return snd_sbdsp_free(chip
);
210 int snd_sbdsp_create(struct snd_card
*card
,
213 irq_handler_t irq_handler
,
216 unsigned short hardware
,
217 struct snd_sb
**r_chip
)
221 static struct snd_device_ops ops
= {
222 .dev_free
= snd_sbdsp_dev_free
,
225 if (snd_BUG_ON(!r_chip
))
228 chip
= kzalloc(sizeof(*chip
), GFP_KERNEL
);
231 spin_lock_init(&chip
->reg_lock
);
232 spin_lock_init(&chip
->open_lock
);
233 spin_lock_init(&chip
->midi_input_lock
);
234 spin_lock_init(&chip
->mixer_lock
);
240 if (request_irq(irq
, irq_handler
,
241 (hardware
== SB_HW_ALS4000
||
242 hardware
== SB_HW_CS5530
) ?
243 IRQF_SHARED
: IRQF_DISABLED
,
244 "SoundBlaster", (void *) chip
)) {
245 snd_printk(KERN_ERR
"sb: can't grab irq %d\n", irq
);
246 snd_sbdsp_free(chip
);
251 if (hardware
== SB_HW_ALS4000
)
252 goto __skip_allocation
;
254 if ((chip
->res_port
= request_region(port
, 16, "SoundBlaster")) == NULL
) {
255 snd_printk(KERN_ERR
"sb: can't grab port 0x%lx\n", port
);
256 snd_sbdsp_free(chip
);
261 if (dma8
>= 0 && request_dma(dma8
, "SoundBlaster - 8bit")) {
262 snd_printk(KERN_ERR
"sb: can't grab DMA8 %d\n", dma8
);
263 snd_sbdsp_free(chip
);
268 if (hardware
!= SB_HW_ALS100
&& (dma16
< 5 || dma16
> 7)) {
271 } else if (request_dma(dma16
, "SoundBlaster - 16bit")) {
272 snd_printk(KERN_ERR
"sb: can't grab DMA16 %d\n", dma16
);
273 snd_sbdsp_free(chip
);
282 chip
->hardware
= hardware
;
283 if ((err
= snd_sbdsp_probe(chip
)) < 0) {
284 snd_sbdsp_free(chip
);
287 if ((err
= snd_device_new(card
, SNDRV_DEV_LOWLEVEL
, chip
, &ops
)) < 0) {
288 snd_sbdsp_free(chip
);
295 EXPORT_SYMBOL(snd_sbdsp_command
);
296 EXPORT_SYMBOL(snd_sbdsp_get_byte
);
297 EXPORT_SYMBOL(snd_sbdsp_reset
);
298 EXPORT_SYMBOL(snd_sbdsp_create
);
300 EXPORT_SYMBOL(snd_sbmixer_write
);
301 EXPORT_SYMBOL(snd_sbmixer_read
);
302 EXPORT_SYMBOL(snd_sbmixer_new
);
303 EXPORT_SYMBOL(snd_sbmixer_add_ctl
);
305 EXPORT_SYMBOL(snd_sbmixer_suspend
);
306 EXPORT_SYMBOL(snd_sbmixer_resume
);
313 static int __init
alsa_sb_common_init(void)
318 static void __exit
alsa_sb_common_exit(void)
322 module_init(alsa_sb_common_init
)
323 module_exit(alsa_sb_common_exit
)