source: GPL/alsa-kernel/isa/sgalaxy.c@ 18

Last change on this file since 18 was 18, checked in by vladest, 20 years ago

initial import

File size: 10.1 KB
Line 
1/*
2 * Driver for Aztech Sound Galaxy cards
3 * Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
4 *
5 * I don't have documentation for this card, I based this driver on the
6 * driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24#define SNDRV_MAIN_OBJECT_FILE
25#include <sound/driver.h>
26#include <sound/sb.h>
27#include <sound/ad1848.h>
28#define SNDRV_LEGACY_FIND_FREE_IRQ
29#define SNDRV_LEGACY_FIND_FREE_DMA
30#define SNDRV_GET_ID
31#include <sound/initval.h>
32
33EXPORT_NO_SYMBOLS;
34MODULE_DESCRIPTION("Aztech Sound Galaxy");
35MODULE_CLASSES("{sound}");
36MODULE_DEVICES("{{Aztech Systems,Sound Galaxy}}");
37
38static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
39static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
40static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
41static long snd_sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */
42static long snd_wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
43static int snd_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */
44static int snd_dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
45
46MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
47MODULE_PARM_DESC(snd_index, "Index value for Sound Galaxy soundcard.");
48MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
49MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
50MODULE_PARM_DESC(snd_id, "ID string for Sound Galaxy soundcard.");
51MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
52MODULE_PARM(snd_sbport, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
53MODULE_PARM_DESC(snd_sbport, "Port # for Sound Galaxy SB driver.");
54MODULE_PARM_SYNTAX(snd_sbport, SNDRV_ENABLED ",allows:{{0x220},{0x240}},dialog:list");
55MODULE_PARM(snd_wssport, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
56MODULE_PARM_DESC(snd_wssport, "Port # for Sound Galaxy WSS driver.");
57MODULE_PARM_SYNTAX(snd_wssport, SNDRV_ENABLED ",allows:{{0x530},{0xe80},{0xf40},{0x604}},dialog:list");
58MODULE_PARM(snd_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
59MODULE_PARM_DESC(snd_irq, "IRQ # for Sound Galaxy driver.");
60MODULE_PARM_SYNTAX(snd_irq, SNDRV_ENABLED ",allows:{{7},{9},{10},{11}},dialog:list");
61MODULE_PARM(snd_dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
62MODULE_PARM_DESC(snd_dma1, "DMA1 # for Sound Galaxy driver.");
63MODULE_PARM_SYNTAX(snd_dma1, SNDRV_DMA8_DESC);
64
65#define SGALAXY_AUXC_LEFT 18
66#define SGALAXY_AUXC_RIGHT 19
67
68static snd_card_t *snd_sgalaxy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
69
70/*
71
72 */
73
74#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
75
76/* from lowlevel/sb/sb.c - to avoid having to allocate a sb_t for the */
77/* short time we actually need it.. */
78
79static int snd_sgalaxy_sbdsp_reset(unsigned long port)
80{
81 int i;
82
83 outb(1, SBP1(port, RESET));
84 udelay(10);
85 outb(0, SBP1(port, RESET));
86 udelay(30);
87 for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
88 if (inb(SBP1(port, READ)) != 0xaa) {
89 snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
90 return -ENODEV;
91 }
92 return 0;
93}
94
95static int __init snd_sgalaxy_sbdsp_command(unsigned long port, unsigned char val)
96{
97 int i;
98
99 for (i = 10000; i; i--)
100 if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
101 outb(val, SBP1(port, COMMAND));
102 return 1;
103 }
104
105 return 0;
106}
107
108static int __init snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
109{
110 static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1,
111 0x10, 0x18, 0x20, -1, -1, -1, -1};
112 static int dma_bits[] = {1, 2, 0, 3};
113 int tmp, tmp1;
114
115 unsigned int flags;
116
117 if ((tmp = inb(port + 3)) == 0xff)
118 {
119 snd_printdd("I/O address dead (0x%lx)\n", tmp);
120 return 0;
121 }
122#if 0
123 snd_printdd("WSS signature = 0x%x\n", tmp);
124#endif
125
126 if ((tmp & 0x3f) != 0x04 &&
127 (tmp & 0x3f) != 0x0f &&
128 (tmp & 0x3f) != 0x00) {
129 snd_printdd("No WSS signature detected on port 0x%lx\n",
130 port + 3);
131 return 0;
132 }
133
134#if 0
135 snd_printdd("sgalaxy - setting up IRQ/DMA for WSS\n");
136#endif
137
138 save_flags(flags);
139 cli();
140
141 /* initialize IRQ for WSS codec */
142 tmp = interrupt_bits[irq % 16];
143 if (tmp < 0) {
144 restore_flags(flags);
145 return -EINVAL;
146 }
147 outb(tmp | 0x40, port);
148 tmp1 = dma_bits[dma % 4];
149 outb(tmp | tmp1, port);
150
151 restore_flags(flags);
152 return 0;
153}
154
155static int __init snd_sgalaxy_detect(int dev, int irq, int dma)
156{
157#if 0
158 snd_printdd("sgalaxy - switching to WSS mode\n");
159#endif
160
161 /* switch to WSS mode */
162 snd_sgalaxy_sbdsp_reset(snd_sbport[dev]);
163
164 snd_sgalaxy_sbdsp_command(snd_sbport[dev], 9);
165 snd_sgalaxy_sbdsp_command(snd_sbport[dev], 0);
166
167 udelay(400);
168 return snd_sgalaxy_setup_wss(snd_wssport[dev], irq, dma);
169}
170
171#define SGALAXY_CONTROLS 2
172
173static snd_kcontrol_new_t snd_sgalaxy_controls[2] = {
174AD1848_DOUBLE("Aux Playback Switch", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
175AD1848_DOUBLE("Aux Playback Volume", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
176};
177
178static int __init snd_sgalaxy_mixer(ad1848_t *chip)
179{
180 snd_card_t *card = chip->card;
181 snd_ctl_elem_id_t id1, id2;
182 int idx, err;
183
184 memset(&id1, 0, sizeof(id1));
185 memset(&id2, 0, sizeof(id2));
186 id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
187 /* reassign AUX0 to LINE */
188 strcpy(id1.name, "Aux Playback Switch");
189 strcpy(id2.name, "Line Playback Switch");
190 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
191 return err;
192 strcpy(id1.name, "Aux Playback Volume");
193 strcpy(id2.name, "Line Playback Volume");
194 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
195 return err;
196 /* reassign AUX1 to FM */
197 strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
198 strcpy(id2.name, "FM Playback Switch");
199 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
200 return err;
201 strcpy(id1.name, "Aux Playback Volume");
202 strcpy(id2.name, "FM Playback Volume");
203 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
204 return err;
205 /* build AUX2 input */
206 for (idx = 0; idx < SGALAXY_CONTROLS; idx++) {
207 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_sgalaxy_controls[idx], chip))) < 0)
208 return err;
209 }
210 return 0;
211}
212
213static int __init snd_sgalaxy_probe(int dev)
214{
215 static int possible_irqs[] = {7, 9, 10, 11, -1};
216 static int possible_dmas[] = {1, 3, 0, -1};
217 int err, irq, dma1;
218 snd_card_t *card;
219 ad1848_t *chip;
220
221 if (snd_sbport[dev] == SNDRV_AUTO_PORT) {
222 snd_printk("specify SB port\n");
223 return -EINVAL;
224 }
225 if (snd_wssport[dev] == SNDRV_AUTO_PORT) {
226 snd_printk("specify WSS port\n");
227 return -EINVAL;
228 }
229 card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
230 if (card == NULL)
231 return -ENOMEM;
232
233 irq = snd_irq[dev];
234 if (irq == SNDRV_AUTO_IRQ) {
235 if ((irq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
236 snd_card_free(card);
237 snd_printk("unable to find a free IRQ\n");
238 return -EBUSY;
239 }
240 }
241 dma1 = snd_dma1[dev];
242 if (dma1 == SNDRV_AUTO_DMA) {
243 if ((dma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
244 snd_card_free(card);
245 snd_printk("unable to find a free DMA\n");
246 return -EBUSY;
247 }
248 }
249
250 if ((err = snd_sgalaxy_detect(dev, irq, dma1)) < 0) {
251 snd_card_free(card);
252 return err;
253 }
254
255 if ((err = snd_ad1848_create(card, snd_wssport[dev] + 4,
256 irq, dma1,
257 AD1848_HW_DETECT, &chip)) < 0) {
258 snd_card_free(card);
259 return err;
260 }
261
262 if ((err = snd_ad1848_pcm(chip, 0, NULL)) < 0) {
263 snd_printdd("sgalaxy - error creating new ad1848 PCM device\n");
264 snd_card_free(card);
265 return err;
266 }
267 if ((err = snd_ad1848_mixer(chip)) < 0) {
268 snd_printdd("sgalaxy - error creating new ad1848 mixer\n");
269 snd_card_free(card);
270 return err;
271 }
272 if (snd_sgalaxy_mixer(chip) < 0) {
273 snd_printdd("sgalaxy - the mixer rewrite failed\n");
274 snd_card_free(card);
275 return err;
276 }
277
278 strcpy(card->driver, "Sound Galaxy");
279 strcpy(card->shortname, "Sound Galaxy");
280 sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
281 snd_wssport[dev], irq, dma1);
282
283 if ((err = snd_card_register(card)) < 0) {
284 snd_card_free(card);
285 return err;
286 }
287 snd_sgalaxy_cards[dev] = card;
288 return 0;
289}
290
291static int __init alsa_card_sgalaxy_init(void)
292{
293 int dev, cards;
294
295 for (dev = cards = 0; dev < SNDRV_CARDS && snd_enable[dev]; dev++) {
296 if (snd_sgalaxy_probe(dev) >= 0)
297 cards++;
298 }
299 if (!cards) {
300#ifdef MODULE
301 snd_printk("Sound Galaxy soundcard not found or device busy\n");
302#endif
303 return -ENODEV;
304 }
305
306 return 0;
307}
308
309static void __exit alsa_card_sgalaxy_exit(void)
310{
311 int idx;
312
313 for (idx = 0; idx < SNDRV_CARDS; idx++)
314 snd_card_free(snd_sgalaxy_cards[idx]);
315}
316
317module_init(alsa_card_sgalaxy_init)
318module_exit(alsa_card_sgalaxy_exit)
319
320#ifndef MODULE
321
322/* format is: snd-card-sgalaxy=snd_enable,snd_index,snd_id,
323 snd_sbport,snd_wssport,
324 snd_irq,snd_dma1 */
325
326static int __init alsa_card_sgalaxy_setup(char *str)
327{
328 static unsigned __initdata nr_dev = 0;
329
330 if (nr_dev >= SNDRV_CARDS)
331 return 0;
332 (void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
333 get_option(&str,&snd_index[nr_dev]) == 2 &&
334 get_id(&str,&snd_id[nr_dev]) == 2 &&
335 get_option(&str,(int *)&snd_sbport[nr_dev]) == 2 &&
336 get_option(&str,(int *)&snd_wssport[nr_dev]) == 2 &&
337 get_option(&str,(int *)&snd_irq[nr_dev]) == 2 &&
338 get_option(&str,(int *)&snd_dma1[nr_dev]) == 2);
339 nr_dev++;
340 return 1;
341}
342
343__setup("snd-card-sgalaxy=", alsa_card_sgalaxy_setup);
344
345#endif /* ifndef MODULE */
Note: See TracBrowser for help on using the repository browser.