Blame view
sound/isa/sscape.c
32.1 KB
1a59d1b8e treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
acd471009 ALSA: sscape: con... |
3 |
* Low-level ALSA driver for the ENSONIQ SoundScape |
1da177e4c Linux-2.6.12-rc2 |
4 5 6 7 |
* Copyright (c) by Chris Rankin * * This driver was written in part using information obtained from * the OSS/Free SoundScape driver, written by Hannu Savolainen. |
1da177e4c Linux-2.6.12-rc2 |
8 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
9 |
#include <linux/init.h> |
277e926c9 [ALSA] sscape - U... |
10 |
#include <linux/err.h> |
37419584a ALSA: sscape: add... |
11 |
#include <linux/io.h> |
5e24c1c1c [ALSA] Port the r... |
12 |
#include <linux/isa.h> |
1da177e4c Linux-2.6.12-rc2 |
13 |
#include <linux/delay.h> |
acd471009 ALSA: sscape: con... |
14 |
#include <linux/firmware.h> |
1da177e4c Linux-2.6.12-rc2 |
15 16 |
#include <linux/pnp.h> #include <linux/spinlock.h> |
65a772172 sound: fix driver... |
17 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
18 19 |
#include <asm/dma.h> #include <sound/core.h> |
61ef19d7e ALSA: wss_lib: re... |
20 |
#include <sound/wss.h> |
1da177e4c Linux-2.6.12-rc2 |
21 22 |
#include <sound/mpu401.h> #include <sound/initval.h> |
1da177e4c Linux-2.6.12-rc2 |
23 24 |
MODULE_AUTHOR("Chris Rankin"); |
acd471009 ALSA: sscape: con... |
25 |
MODULE_DESCRIPTION("ENSONIQ SoundScape driver"); |
1da177e4c Linux-2.6.12-rc2 |
26 |
MODULE_LICENSE("GPL"); |
acd471009 ALSA: sscape: con... |
27 28 29 30 31 32 |
MODULE_FIRMWARE("sndscape.co0"); MODULE_FIRMWARE("sndscape.co1"); MODULE_FIRMWARE("sndscape.co2"); MODULE_FIRMWARE("sndscape.co3"); MODULE_FIRMWARE("sndscape.co4"); MODULE_FIRMWARE("scope.cod"); |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
ed76f652d ALSA: sscape - Re... |
34 35 36 37 38 39 40 41 42 |
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; static bool joystick[SNDRV_CARDS]; |
1da177e4c Linux-2.6.12-rc2 |
43 44 45 46 47 48 |
module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); module_param_array(id, charp, NULL, 0444); MODULE_PARM_DESC(id, "Description for SoundScape card"); |
e992ef570 Annotate hardware... |
49 |
module_param_hw_array(port, long, ioport, NULL, 0444); |
1da177e4c Linux-2.6.12-rc2 |
50 |
MODULE_PARM_DESC(port, "Port # for SoundScape driver."); |
e992ef570 Annotate hardware... |
51 |
module_param_hw_array(wss_port, long, ioport, NULL, 0444); |
4996bca98 [ALSA] sscape: dr... |
52 |
MODULE_PARM_DESC(wss_port, "WSS Port # for SoundScape driver."); |
e992ef570 Annotate hardware... |
53 |
module_param_hw_array(irq, int, irq, NULL, 0444); |
1da177e4c Linux-2.6.12-rc2 |
54 |
MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver."); |
e992ef570 Annotate hardware... |
55 |
module_param_hw_array(mpu_irq, int, irq, NULL, 0444); |
1da177e4c Linux-2.6.12-rc2 |
56 |
MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # for SoundScape driver."); |
e992ef570 Annotate hardware... |
57 |
module_param_hw_array(dma, int, dma, NULL, 0444); |
1da177e4c Linux-2.6.12-rc2 |
58 |
MODULE_PARM_DESC(dma, "DMA # for SoundScape driver."); |
f7a9275d9 [ALSA] unregister... |
59 |
|
e992ef570 Annotate hardware... |
60 |
module_param_hw_array(dma2, int, dma, NULL, 0444); |
4996bca98 [ALSA] sscape: dr... |
61 |
MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver."); |
1cb0fdeba ALSA: sscape: for... |
62 63 |
module_param_array(joystick, bool, NULL, 0444); MODULE_PARM_DESC(joystick, "Enable gameport."); |
1da177e4c Linux-2.6.12-rc2 |
64 |
#ifdef CONFIG_PNP |
609d76941 [ALSA] Fix probe ... |
65 |
static int isa_registered; |
59b1b34f4 [ALSA] Fix compil... |
66 |
static int pnp_registered; |
609d76941 [ALSA] Fix probe ... |
67 |
|
05e20b265 ALSA: sscape: con... |
68 |
static const struct pnp_card_device_id sscape_pnpids[] = { |
4996bca98 [ALSA] sscape: dr... |
69 70 |
{ .id = "ENS3081", .devs = { { "ENS0000" } } }, /* Soundscape PnP */ { .id = "ENS4081", .devs = { { "ENS1011" } } }, /* VIVO90 */ |
1da177e4c Linux-2.6.12-rc2 |
71 72 73 74 75 |
{ .id = "" } /* end */ }; MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids); #endif |
1da177e4c Linux-2.6.12-rc2 |
76 |
|
1da177e4c Linux-2.6.12-rc2 |
77 78 79 80 81 82 83 84 85 86 87 |
#define HOST_CTRL_IO(i) ((i) + 2) #define HOST_DATA_IO(i) ((i) + 3) #define ODIE_ADDR_IO(i) ((i) + 4) #define ODIE_DATA_IO(i) ((i) + 5) #define CODEC_IO(i) ((i) + 8) #define IC_ODIE 1 #define IC_OPUS 2 #define RX_READY 0x01 #define TX_READY 0x02 |
6fcfa3959 ALSA: sscape: cod... |
88 89 90 91 92 93 94 95 |
#define CMD_ACK 0x80 #define CMD_SET_MIDI_VOL 0x84 #define CMD_GET_MIDI_VOL 0x85 #define CMD_XXX_MIDI_VOL 0x86 #define CMD_SET_EXTMIDI 0x8a #define CMD_GET_EXTMIDI 0x8b #define CMD_SET_MT32 0x8c #define CMD_GET_MT32 0x8d |
1da177e4c Linux-2.6.12-rc2 |
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
enum GA_REG { GA_INTSTAT_REG = 0, GA_INTENA_REG, GA_DMAA_REG, GA_DMAB_REG, GA_INTCFG_REG, GA_DMACFG_REG, GA_CDCFG_REG, GA_SMCFGA_REG, GA_SMCFGB_REG, GA_HMCTL_REG }; #define DMA_8BIT 0x80 |
4996bca98 [ALSA] sscape: dr... |
111 |
enum card_type { |
f0968e3f7 ALSA: sscape: add... |
112 113 |
MEDIA_FX, /* Sequoia S-1000 */ SSCAPE, /* Sequoia S-2000 */ |
4996bca98 [ALSA] sscape: dr... |
114 115 116 |
SSCAPE_PNP, SSCAPE_VIVO, }; |
1da177e4c Linux-2.6.12-rc2 |
117 118 119 |
struct soundscape { spinlock_t lock; unsigned io_base; |
1da177e4c Linux-2.6.12-rc2 |
120 |
int ic_type; |
4996bca98 [ALSA] sscape: dr... |
121 |
enum card_type type; |
1da177e4c Linux-2.6.12-rc2 |
122 |
struct resource *io_res; |
ec1e79493 [ALSA] sscape: su... |
123 |
struct resource *wss_res; |
7779f75f0 ALSA: wss_lib: re... |
124 |
struct snd_wss *chip; |
1da177e4c Linux-2.6.12-rc2 |
125 |
|
1da177e4c Linux-2.6.12-rc2 |
126 127 128 129 |
unsigned char midi_vol; }; #define INVALID_IRQ ((unsigned)-1) |
be6245373 [ALSA] Remove xxx... |
130 |
static inline struct soundscape *get_card_soundscape(struct snd_card *c) |
1da177e4c Linux-2.6.12-rc2 |
131 132 133 |
{ return (struct soundscape *) (c->private_data); } |
1da177e4c Linux-2.6.12-rc2 |
134 135 136 137 138 |
/* * Allocates some kernel memory that we can use for DMA. * I think this means that the memory has to map to * contiguous pages of physical memory. */ |
0b6a2c9cf ALSA: isa: Avoid ... |
139 140 |
static struct snd_dma_buffer *get_dmabuf(struct soundscape *s, struct snd_dma_buffer *buf, |
6fcfa3959 ALSA: sscape: cod... |
141 |
unsigned long size) |
1da177e4c Linux-2.6.12-rc2 |
142 143 |
{ if (buf) { |
6fcfa3959 ALSA: sscape: cod... |
144 |
if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, |
0b6a2c9cf ALSA: isa: Avoid ... |
145 |
s->chip->card->dev, |
1da177e4c Linux-2.6.12-rc2 |
146 |
size, buf) < 0) { |
bcde1f8a8 ALSA: sscape: rem... |
147 148 149 150 |
snd_printk(KERN_ERR "sscape: Failed to allocate " "%lu bytes for DMA ", size); |
1da177e4c Linux-2.6.12-rc2 |
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
return NULL; } } return buf; } /* * Release the DMA-able kernel memory ... */ static void free_dmabuf(struct snd_dma_buffer *buf) { if (buf && buf->area) snd_dma_free_pages(buf); } |
1da177e4c Linux-2.6.12-rc2 |
166 167 168 169 170 |
/* * This function writes to the SoundScape's control registers, * but doesn't do any locking. It's up to the caller to do that. * This is why this function is "unsafe" ... */ |
6fcfa3959 ALSA: sscape: cod... |
171 172 |
static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val) |
1da177e4c Linux-2.6.12-rc2 |
173 174 175 176 177 178 179 180 181 |
{ outb(reg, ODIE_ADDR_IO(io_base)); outb(val, ODIE_DATA_IO(io_base)); } /* * Write to the SoundScape's control registers, and do the * necessary locking ... */ |
6fcfa3959 ALSA: sscape: cod... |
182 183 |
static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val) |
1da177e4c Linux-2.6.12-rc2 |
184 185 186 187 188 189 190 191 192 193 194 195 |
{ unsigned long flags; spin_lock_irqsave(&s->lock, flags); sscape_write_unsafe(s->io_base, reg, val); spin_unlock_irqrestore(&s->lock, flags); } /* * Read from the SoundScape's control registers, but leave any * locking to the caller. This is why the function is "unsafe" ... */ |
6fcfa3959 ALSA: sscape: cod... |
196 197 |
static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg) |
1da177e4c Linux-2.6.12-rc2 |
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
{ outb(reg, ODIE_ADDR_IO(io_base)); return inb(ODIE_DATA_IO(io_base)); } /* * Puts the SoundScape into "host" mode, as compared to "MIDI" mode */ static inline void set_host_mode_unsafe(unsigned io_base) { outb(0x0, HOST_CTRL_IO(io_base)); } /* * Puts the SoundScape into "MIDI" mode, as compared to "host" mode */ static inline void set_midi_mode_unsafe(unsigned io_base) { outb(0x3, HOST_CTRL_IO(io_base)); } /* * Read the SoundScape's host-mode control register, but leave * any locking issues to the caller ... */ static inline int host_read_unsafe(unsigned io_base) { int data = -1; |
6fcfa3959 ALSA: sscape: cod... |
226 |
if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) |
1da177e4c Linux-2.6.12-rc2 |
227 |
data = inb(HOST_DATA_IO(io_base)); |
1da177e4c Linux-2.6.12-rc2 |
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
return data; } /* * Read the SoundScape's host-mode control register, performing * a limited amount of busy-waiting if the register isn't ready. * Also leaves all locking-issues to the caller ... */ static int host_read_ctrl_unsafe(unsigned io_base, unsigned timeout) { int data; while (((data = host_read_unsafe(io_base)) < 0) && (timeout != 0)) { udelay(100); --timeout; } /* while */ return data; } /* * Write to the SoundScape's host-mode control registers, but * leave any locking issues to the caller ... */ static inline int host_write_unsafe(unsigned io_base, unsigned char data) { if ((inb(HOST_CTRL_IO(io_base)) & TX_READY) != 0) { outb(data, HOST_DATA_IO(io_base)); return 1; } return 0; } /* * Write to the SoundScape's host-mode control registers, performing * a limited amount of busy-waiting if the register isn't ready. * Also leaves all locking-issues to the caller ... */ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, |
6fcfa3959 ALSA: sscape: cod... |
269 |
unsigned timeout) |
1da177e4c Linux-2.6.12-rc2 |
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
{ int err; while (!(err = host_write_unsafe(io_base, data)) && (timeout != 0)) { udelay(100); --timeout; } /* while */ return err; } /* * Check that the MIDI subsystem is operational. If it isn't, * then we will hang the computer if we try to use it ... * * NOTE: This check is based upon observation, not documentation. */ |
6fcfa3959 ALSA: sscape: cod... |
288 |
static inline int verify_mpu401(const struct snd_mpu401 *mpu) |
1da177e4c Linux-2.6.12-rc2 |
289 |
{ |
c9864fd30 ALSA: sscape: use... |
290 |
return ((inb(MPU401C(mpu)) & 0xc0) == 0x80); |
1da177e4c Linux-2.6.12-rc2 |
291 292 293 |
} /* |
f5d0f820f ALSA: isa: fix sp... |
294 |
* This is apparently the standard way to initialise an MPU-401 |
1da177e4c Linux-2.6.12-rc2 |
295 |
*/ |
6fcfa3959 ALSA: sscape: cod... |
296 |
static inline void initialise_mpu401(const struct snd_mpu401 *mpu) |
1da177e4c Linux-2.6.12-rc2 |
297 |
{ |
c9864fd30 ALSA: sscape: use... |
298 |
outb(0, MPU401D(mpu)); |
1da177e4c Linux-2.6.12-rc2 |
299 300 301 302 303 304 305 |
} /* * Tell the SoundScape to activate the AD1845 chip (I think). * The AD1845 detection fails if we *don't* do this, so I * think that this is a good idea ... */ |
6fcfa3959 ALSA: sscape: cod... |
306 |
static void activate_ad1845_unsafe(unsigned io_base) |
1da177e4c Linux-2.6.12-rc2 |
307 |
{ |
6fcfa3959 ALSA: sscape: cod... |
308 309 |
unsigned char val = sscape_read_unsafe(io_base, GA_HMCTL_REG); sscape_write_unsafe(io_base, GA_HMCTL_REG, (val & 0xcf) | 0x10); |
1da177e4c Linux-2.6.12-rc2 |
310 311 312 313 314 315 |
sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80); } /* * Do the necessary ALSA-level cleanup to deallocate our driver ... */ |
be6245373 [ALSA] Remove xxx... |
316 |
static void soundscape_free(struct snd_card *c) |
1da177e4c Linux-2.6.12-rc2 |
317 |
{ |
ec1e79493 [ALSA] sscape: su... |
318 |
struct soundscape *sscape = get_card_soundscape(c); |
b1d5776d8 [ALSA] Remove vma... |
319 |
release_and_free_resource(sscape->io_res); |
ec1e79493 [ALSA] sscape: su... |
320 |
release_and_free_resource(sscape->wss_res); |
1da177e4c Linux-2.6.12-rc2 |
321 322 323 324 |
free_dma(sscape->chip->dma1); } /* |
f5d0f820f ALSA: isa: fix sp... |
325 |
* Tell the SoundScape to begin a DMA transfer using the given channel. |
1da177e4c Linux-2.6.12-rc2 |
326 327 |
* All locking issues are left to the caller. */ |
6fcfa3959 ALSA: sscape: cod... |
328 |
static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg) |
1da177e4c Linux-2.6.12-rc2 |
329 |
{ |
6fcfa3959 ALSA: sscape: cod... |
330 331 332 333 |
sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01); sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe); |
1da177e4c Linux-2.6.12-rc2 |
334 335 336 337 338 339 |
} /* * Wait for a DMA transfer to complete. This is a "limited busy-wait", * and all locking issues are left to the caller. */ |
6fcfa3959 ALSA: sscape: cod... |
340 341 |
static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout) |
1da177e4c Linux-2.6.12-rc2 |
342 343 344 345 346 |
{ while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) { udelay(100); --timeout; } /* while */ |
6fcfa3959 ALSA: sscape: cod... |
347 |
return sscape_read_unsafe(io_base, reg) & 0x01; |
1da177e4c Linux-2.6.12-rc2 |
348 349 350 351 352 353 354 355 356 357 358 |
} /* * Wait for the On-Board Processor to return its start-up * acknowledgement sequence. This wait is too long for * us to perform "busy-waiting", and so we must sleep. * This in turn means that we must not be holding any * spinlocks when we call this function. */ static int obp_startup_ack(struct soundscape *s, unsigned timeout) { |
554b91ede ALSA: sscape: fix... |
359 360 361 |
unsigned long end_time = jiffies + msecs_to_jiffies(timeout); do { |
1da177e4c Linux-2.6.12-rc2 |
362 |
unsigned long flags; |
acd471009 ALSA: sscape: con... |
363 |
int x; |
1da177e4c Linux-2.6.12-rc2 |
364 |
|
1da177e4c Linux-2.6.12-rc2 |
365 |
spin_lock_irqsave(&s->lock, flags); |
acd471009 ALSA: sscape: con... |
366 |
x = host_read_unsafe(s->io_base); |
1da177e4c Linux-2.6.12-rc2 |
367 |
spin_unlock_irqrestore(&s->lock, flags); |
acd471009 ALSA: sscape: con... |
368 |
if (x == 0xfe || x == 0xff) |
1da177e4c Linux-2.6.12-rc2 |
369 |
return 1; |
554b91ede ALSA: sscape: fix... |
370 371 |
msleep(10); } while (time_before(jiffies, end_time)); |
1da177e4c Linux-2.6.12-rc2 |
372 373 374 375 376 377 378 379 380 381 382 383 384 |
return 0; } /* * Wait for the host to return its start-up acknowledgement * sequence. This wait is too long for us to perform * "busy-waiting", and so we must sleep. This in turn means * that we must not be holding any spinlocks when we call * this function. */ static int host_startup_ack(struct soundscape *s, unsigned timeout) { |
554b91ede ALSA: sscape: fix... |
385 386 387 |
unsigned long end_time = jiffies + msecs_to_jiffies(timeout); do { |
1da177e4c Linux-2.6.12-rc2 |
388 |
unsigned long flags; |
acd471009 ALSA: sscape: con... |
389 |
int x; |
1da177e4c Linux-2.6.12-rc2 |
390 |
|
1da177e4c Linux-2.6.12-rc2 |
391 |
spin_lock_irqsave(&s->lock, flags); |
acd471009 ALSA: sscape: con... |
392 |
x = host_read_unsafe(s->io_base); |
1da177e4c Linux-2.6.12-rc2 |
393 394 395 |
spin_unlock_irqrestore(&s->lock, flags); if (x == 0xfe) return 1; |
554b91ede ALSA: sscape: fix... |
396 397 |
msleep(10); } while (time_before(jiffies, end_time)); |
1da177e4c Linux-2.6.12-rc2 |
398 399 400 401 402 403 404 |
return 0; } /* * Upload a byte-stream into the SoundScape using DMA channel A. */ |
6fcfa3959 ALSA: sscape: cod... |
405 406 |
static int upload_dma_data(struct soundscape *s, const unsigned char *data, size_t size) |
1da177e4c Linux-2.6.12-rc2 |
407 408 409 410 |
{ unsigned long flags; struct snd_dma_buffer dma; int ret; |
6fcfa3959 ALSA: sscape: cod... |
411 |
unsigned char val; |
1da177e4c Linux-2.6.12-rc2 |
412 |
|
0b6a2c9cf ALSA: isa: Avoid ... |
413 |
if (!get_dmabuf(s, &dma, PAGE_ALIGN(32 * 1024))) |
1da177e4c Linux-2.6.12-rc2 |
414 415 416 417 418 419 420 |
return -ENOMEM; spin_lock_irqsave(&s->lock, flags); /* * Reset the board ... */ |
6fcfa3959 ALSA: sscape: cod... |
421 422 |
val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f); |
1da177e4c Linux-2.6.12-rc2 |
423 424 425 426 |
/* * Enable the DMA channels and configure them ... */ |
6fcfa3959 ALSA: sscape: cod... |
427 428 |
val = (s->chip->dma1 << 4) | DMA_8BIT; sscape_write_unsafe(s->io_base, GA_DMAA_REG, val); |
1da177e4c Linux-2.6.12-rc2 |
429 430 431 432 433 |
sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20); /* * Take the board out of reset ... */ |
6fcfa3959 ALSA: sscape: cod... |
434 435 |
val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80); |
1da177e4c Linux-2.6.12-rc2 |
436 437 |
/* |
acd471009 ALSA: sscape: con... |
438 |
* Upload the firmware to the SoundScape |
1da177e4c Linux-2.6.12-rc2 |
439 440 441 442 |
* board through the DMA channel ... */ while (size != 0) { unsigned long len; |
1da177e4c Linux-2.6.12-rc2 |
443 |
len = min(size, dma.bytes); |
acd471009 ALSA: sscape: con... |
444 |
memcpy(dma.area, data, len); |
1da177e4c Linux-2.6.12-rc2 |
445 446 |
data += len; size -= len; |
1da177e4c Linux-2.6.12-rc2 |
447 448 449 450 |
snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE); sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG); if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) { /* |
6fcfa3959 ALSA: sscape: cod... |
451 |
* Don't forget to release this spinlock we're holding |
1da177e4c Linux-2.6.12-rc2 |
452 453 |
*/ spin_unlock_irqrestore(&s->lock, flags); |
bcde1f8a8 ALSA: sscape: rem... |
454 455 456 |
snd_printk(KERN_ERR "sscape: DMA upload has timed out "); |
1da177e4c Linux-2.6.12-rc2 |
457 458 459 460 461 462 |
ret = -EAGAIN; goto _release_dma; } } /* while */ set_host_mode_unsafe(s->io_base); |
acd471009 ALSA: sscape: con... |
463 |
outb(0x0, s->io_base); |
1da177e4c Linux-2.6.12-rc2 |
464 465 466 467 |
/* * Boot the board ... (I think) */ |
6fcfa3959 ALSA: sscape: cod... |
468 469 |
val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40); |
1da177e4c Linux-2.6.12-rc2 |
470 471 472 473 474 475 476 477 |
spin_unlock_irqrestore(&s->lock, flags); /* * If all has gone well, then the board should acknowledge * the new upload and tell us that it has rebooted OK. We * give it 5 seconds (max) ... */ ret = 0; |
554b91ede ALSA: sscape: fix... |
478 |
if (!obp_startup_ack(s, 5000)) { |
bcde1f8a8 ALSA: sscape: rem... |
479 480 481 |
snd_printk(KERN_ERR "sscape: No response " "from on-board processor after upload "); |
1da177e4c Linux-2.6.12-rc2 |
482 |
ret = -EAGAIN; |
554b91ede ALSA: sscape: fix... |
483 |
} else if (!host_startup_ack(s, 5000)) { |
bcde1f8a8 ALSA: sscape: rem... |
484 485 486 |
snd_printk(KERN_ERR "sscape: SoundScape failed to initialise "); |
1da177e4c Linux-2.6.12-rc2 |
487 488 |
ret = -EAGAIN; } |
4996bca98 [ALSA] sscape: dr... |
489 |
_release_dma: |
1da177e4c Linux-2.6.12-rc2 |
490 491 492 |
/* * NOTE!!! We are NOT holding any spinlocks at this point !!! */ |
acd471009 ALSA: sscape: con... |
493 |
sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70)); |
1da177e4c Linux-2.6.12-rc2 |
494 495 496 497 498 499 500 501 502 |
free_dmabuf(&dma); return ret; } /* * Upload the bootblock(?) into the SoundScape. The only * purpose of this block of code seems to be to tell * us which version of the microcode we should be using. |
1da177e4c Linux-2.6.12-rc2 |
503 |
*/ |
acd471009 ALSA: sscape: con... |
504 |
static int sscape_upload_bootblock(struct snd_card *card) |
1da177e4c Linux-2.6.12-rc2 |
505 |
{ |
acd471009 ALSA: sscape: con... |
506 |
struct soundscape *sscape = get_card_soundscape(card); |
1da177e4c Linux-2.6.12-rc2 |
507 |
unsigned long flags; |
acd471009 ALSA: sscape: con... |
508 |
const struct firmware *init_fw = NULL; |
1da177e4c Linux-2.6.12-rc2 |
509 510 |
int data = 0; int ret; |
acd471009 ALSA: sscape: con... |
511 512 |
ret = request_firmware(&init_fw, "scope.cod", card->dev); if (ret < 0) { |
bcde1f8a8 ALSA: sscape: rem... |
513 |
snd_printk(KERN_ERR "sscape: Error loading scope.cod"); |
acd471009 ALSA: sscape: con... |
514 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
515 |
} |
acd471009 ALSA: sscape: con... |
516 |
ret = upload_dma_data(sscape, init_fw->data, init_fw->size); |
1da177e4c Linux-2.6.12-rc2 |
517 |
|
acd471009 ALSA: sscape: con... |
518 |
release_firmware(init_fw); |
1da177e4c Linux-2.6.12-rc2 |
519 |
|
acd471009 ALSA: sscape: con... |
520 521 522 |
spin_lock_irqsave(&sscape->lock, flags); if (ret == 0) data = host_read_ctrl_unsafe(sscape->io_base, 100); |
1da177e4c Linux-2.6.12-rc2 |
523 |
|
acd471009 ALSA: sscape: con... |
524 525 |
if (data & 0x10) sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f); |
1da177e4c Linux-2.6.12-rc2 |
526 |
|
1da177e4c Linux-2.6.12-rc2 |
527 |
spin_unlock_irqrestore(&sscape->lock, flags); |
acd471009 ALSA: sscape: con... |
528 529 |
data &= 0xf; if (ret == 0 && data > 7) { |
bcde1f8a8 ALSA: sscape: rem... |
530 531 532 |
snd_printk(KERN_ERR "sscape: timeout reading firmware version "); |
acd471009 ALSA: sscape: con... |
533 534 |
ret = -EAGAIN; } |
1da177e4c Linux-2.6.12-rc2 |
535 |
|
acd471009 ALSA: sscape: con... |
536 |
return (ret == 0) ? data : ret; |
1da177e4c Linux-2.6.12-rc2 |
537 538 539 |
} /* |
acd471009 ALSA: sscape: con... |
540 |
* Upload the microcode into the SoundScape. |
1da177e4c Linux-2.6.12-rc2 |
541 |
*/ |
acd471009 ALSA: sscape: con... |
542 |
static int sscape_upload_microcode(struct snd_card *card, int version) |
1da177e4c Linux-2.6.12-rc2 |
543 |
{ |
acd471009 ALSA: sscape: con... |
544 545 546 |
struct soundscape *sscape = get_card_soundscape(card); const struct firmware *init_fw = NULL; char name[14]; |
1da177e4c Linux-2.6.12-rc2 |
547 |
int err; |
acd471009 ALSA: sscape: con... |
548 |
snprintf(name, sizeof(name), "sndscape.co%d", version); |
1da177e4c Linux-2.6.12-rc2 |
549 |
|
acd471009 ALSA: sscape: con... |
550 551 |
err = request_firmware(&init_fw, name, card->dev); if (err < 0) { |
bcde1f8a8 ALSA: sscape: rem... |
552 553 |
snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d", version); |
acd471009 ALSA: sscape: con... |
554 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
555 |
} |
acd471009 ALSA: sscape: con... |
556 557 |
err = upload_dma_data(sscape, init_fw->data, init_fw->size); if (err == 0) |
dc5027a72 ALSA: sscape: Use... |
558 559 |
snd_printk(KERN_INFO "sscape: MIDI firmware loaded %zu KBs ", |
acd471009 ALSA: sscape: con... |
560 |
init_fw->size >> 10); |
1da177e4c Linux-2.6.12-rc2 |
561 |
|
acd471009 ALSA: sscape: con... |
562 |
release_firmware(init_fw); |
1da177e4c Linux-2.6.12-rc2 |
563 564 565 |
return err; } |
1da177e4c Linux-2.6.12-rc2 |
566 567 568 |
/* * Mixer control for the SoundScape's MIDI device. */ |
be6245373 [ALSA] Remove xxx... |
569 |
static int sscape_midi_info(struct snd_kcontrol *ctl, |
6fcfa3959 ALSA: sscape: cod... |
570 |
struct snd_ctl_elem_info *uinfo) |
1da177e4c Linux-2.6.12-rc2 |
571 572 573 574 575 576 577 |
{ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 127; return 0; } |
be6245373 [ALSA] Remove xxx... |
578 |
static int sscape_midi_get(struct snd_kcontrol *kctl, |
6fcfa3959 ALSA: sscape: cod... |
579 |
struct snd_ctl_elem_value *uctl) |
1da177e4c Linux-2.6.12-rc2 |
580 |
{ |
7779f75f0 ALSA: wss_lib: re... |
581 |
struct snd_wss *chip = snd_kcontrol_chip(kctl); |
be6245373 [ALSA] Remove xxx... |
582 |
struct snd_card *card = chip->card; |
1da177e4c Linux-2.6.12-rc2 |
583 584 585 586 |
register struct soundscape *s = get_card_soundscape(card); unsigned long flags; spin_lock_irqsave(&s->lock, flags); |
453e37b37 ALSA: sscape: dro... |
587 |
uctl->value.integer.value[0] = s->midi_vol; |
1da177e4c Linux-2.6.12-rc2 |
588 589 590 |
spin_unlock_irqrestore(&s->lock, flags); return 0; } |
be6245373 [ALSA] Remove xxx... |
591 |
static int sscape_midi_put(struct snd_kcontrol *kctl, |
6fcfa3959 ALSA: sscape: cod... |
592 |
struct snd_ctl_elem_value *uctl) |
1da177e4c Linux-2.6.12-rc2 |
593 |
{ |
7779f75f0 ALSA: wss_lib: re... |
594 |
struct snd_wss *chip = snd_kcontrol_chip(kctl); |
be6245373 [ALSA] Remove xxx... |
595 |
struct snd_card *card = chip->card; |
6fcfa3959 ALSA: sscape: cod... |
596 |
struct soundscape *s = get_card_soundscape(card); |
1da177e4c Linux-2.6.12-rc2 |
597 598 |
unsigned long flags; int change; |
6fcfa3959 ALSA: sscape: cod... |
599 |
unsigned char new_val; |
1da177e4c Linux-2.6.12-rc2 |
600 601 |
spin_lock_irqsave(&s->lock, flags); |
6fcfa3959 ALSA: sscape: cod... |
602 |
new_val = uctl->value.integer.value[0] & 127; |
1da177e4c Linux-2.6.12-rc2 |
603 604 605 606 607 608 609 610 611 612 613 614 |
/* * We need to put the board into HOST mode before we * can send any volume-changing HOST commands ... */ set_host_mode_unsafe(s->io_base); /* * To successfully change the MIDI volume setting, you seem to * have to write a volume command, write the new volume value, * and then perform another volume-related command. Perhaps the * first command is an "open" and the second command is a "close"? */ |
6fcfa3959 ALSA: sscape: cod... |
615 |
if (s->midi_vol == new_val) { |
1da177e4c Linux-2.6.12-rc2 |
616 617 618 |
change = 0; goto __skip_change; } |
6fcfa3959 ALSA: sscape: cod... |
619 620 621 622 623 624 |
change = host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) && host_write_ctrl_unsafe(s->io_base, new_val, 100) && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100) && host_write_ctrl_unsafe(s->io_base, new_val, 100); s->midi_vol = new_val; __skip_change: |
1da177e4c Linux-2.6.12-rc2 |
625 626 627 628 629 630 631 632 633 |
/* * Take the board out of HOST mode and back into MIDI mode ... */ set_midi_mode_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); return change; } |
3a84d6c94 ALSA: sound/isa: ... |
634 |
static const struct snd_kcontrol_new midi_mixer_ctl = { |
1da177e4c Linux-2.6.12-rc2 |
635 636 637 638 639 640 641 642 643 644 645 646 |
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "MIDI", .info = sscape_midi_info, .get = sscape_midi_get, .put = sscape_midi_put }; /* * The SoundScape can use two IRQs from a possible set of four. * These IRQs are encoded as bit patterns so that they can be * written to the control registers. */ |
1bff292e9 ALSA: isa: remove... |
647 |
static unsigned get_irq_config(int sscape_type, int irq) |
1da177e4c Linux-2.6.12-rc2 |
648 649 |
{ static const int valid_irq[] = { 9, 5, 7, 10 }; |
f0968e3f7 ALSA: sscape: add... |
650 |
static const int old_irq[] = { 9, 7, 5, 15 }; |
1da177e4c Linux-2.6.12-rc2 |
651 |
unsigned cfg; |
f0968e3f7 ALSA: sscape: add... |
652 653 654 655 656 657 658 659 660 |
if (sscape_type == MEDIA_FX) { for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg) if (irq == old_irq[cfg]) return cfg; } else { for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) if (irq == valid_irq[cfg]) return cfg; } |
1da177e4c Linux-2.6.12-rc2 |
661 662 663 |
return INVALID_IRQ; } |
1da177e4c Linux-2.6.12-rc2 |
664 665 666 667 |
/* * Perform certain arcane port-checks to see whether there * is a SoundScape board lurking behind the given ports. */ |
1bff292e9 ALSA: isa: remove... |
668 |
static int detect_sscape(struct soundscape *s, long wss_io) |
1da177e4c Linux-2.6.12-rc2 |
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 |
{ unsigned long flags; unsigned d; int retval = 0; spin_lock_irqsave(&s->lock, flags); /* * The following code is lifted from the original OSS driver, * and as I don't have a datasheet I cannot really comment * on what it is doing... */ if ((inb(HOST_CTRL_IO(s->io_base)) & 0x78) != 0) goto _done; d = inb(ODIE_ADDR_IO(s->io_base)) & 0xf0; if ((d & 0x80) != 0) goto _done; |
453e37b37 ALSA: sscape: dro... |
687 |
if (d == 0) |
1da177e4c Linux-2.6.12-rc2 |
688 |
s->ic_type = IC_ODIE; |
453e37b37 ALSA: sscape: dro... |
689 |
else if ((d & 0x60) != 0) |
1da177e4c Linux-2.6.12-rc2 |
690 |
s->ic_type = IC_OPUS; |
453e37b37 ALSA: sscape: dro... |
691 |
else |
1da177e4c Linux-2.6.12-rc2 |
692 693 694 695 696 697 698 699 700 |
goto _done; outb(0xfa, ODIE_ADDR_IO(s->io_base)); if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0a) goto _done; outb(0xfe, ODIE_ADDR_IO(s->io_base)); if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0e) goto _done; |
ec1e79493 [ALSA] sscape: su... |
701 702 703 704 |
outb(0xfe, ODIE_ADDR_IO(s->io_base)); d = inb(ODIE_DATA_IO(s->io_base)); if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e) |
1da177e4c Linux-2.6.12-rc2 |
705 |
goto _done; |
f0968e3f7 ALSA: sscape: add... |
706 707 |
if (s->ic_type == IC_OPUS) activate_ad1845_unsafe(s->io_base); |
ec1e79493 [ALSA] sscape: su... |
708 709 |
if (s->type == SSCAPE_VIVO) |
453e37b37 ALSA: sscape: dro... |
710 |
wss_io += 4; |
f0968e3f7 ALSA: sscape: add... |
711 |
|
6fcfa3959 ALSA: sscape: cod... |
712 |
d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); |
f0968e3f7 ALSA: sscape: add... |
713 714 715 716 717 718 719 720 721 722 |
sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); /* wait for WSS codec */ for (d = 0; d < 500; d++) { if ((inb(wss_io) & 0x80) == 0) break; spin_unlock_irqrestore(&s->lock, flags); msleep(1); spin_lock_irqsave(&s->lock, flags); } |
f0968e3f7 ALSA: sscape: add... |
723 724 725 726 727 728 729 730 731 732 733 734 |
if ((inb(wss_io) & 0x80) != 0) goto _done; if (inb(wss_io + 2) == 0xff) goto _done; d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d); if ((inb(wss_io) & 0x80) != 0) s->type = MEDIA_FX; |
6fcfa3959 ALSA: sscape: cod... |
735 |
d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); |
f0968e3f7 ALSA: sscape: add... |
736 |
sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); |
ec1e79493 [ALSA] sscape: su... |
737 738 |
/* wait for WSS codec */ for (d = 0; d < 500; d++) { |
453e37b37 ALSA: sscape: dro... |
739 |
if ((inb(wss_io) & 0x80) == 0) |
ec1e79493 [ALSA] sscape: su... |
740 741 742 743 744 |
break; spin_unlock_irqrestore(&s->lock, flags); msleep(1); spin_lock_irqsave(&s->lock, flags); } |
ec1e79493 [ALSA] sscape: su... |
745 |
|
1da177e4c Linux-2.6.12-rc2 |
746 747 748 749 |
/* * SoundScape successfully detected! */ retval = 1; |
6fcfa3959 ALSA: sscape: cod... |
750 |
_done: |
1da177e4c Linux-2.6.12-rc2 |
751 752 753 754 755 756 757 758 759 760 |
spin_unlock_irqrestore(&s->lock, flags); return retval; } /* * ALSA callback function, called when attempting to open the MIDI device. * Check that the MIDI firmware has been loaded, because we don't want * to crash the machine. Also check that someone isn't using the hardware * IOCTL device. */ |
6fcfa3959 ALSA: sscape: cod... |
761 |
static int mpu401_open(struct snd_mpu401 *mpu) |
1da177e4c Linux-2.6.12-rc2 |
762 |
{ |
1da177e4c Linux-2.6.12-rc2 |
763 |
if (!verify_mpu401(mpu)) { |
bcde1f8a8 ALSA: sscape: rem... |
764 765 766 767 |
snd_printk(KERN_ERR "sscape: MIDI disabled, " "please load firmware "); return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
768 |
} |
bcde1f8a8 ALSA: sscape: rem... |
769 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
770 771 772 |
} /* |
f5d0f820f ALSA: isa: fix sp... |
773 |
* Initialise an MPU-401 subdevice for MIDI support on the SoundScape. |
1da177e4c Linux-2.6.12-rc2 |
774 |
*/ |
1bff292e9 ALSA: isa: remove... |
775 776 |
static int create_mpu401(struct snd_card *card, int devnum, unsigned long port, int irq) |
1da177e4c Linux-2.6.12-rc2 |
777 778 |
{ struct soundscape *sscape = get_card_soundscape(card); |
be6245373 [ALSA] Remove xxx... |
779 |
struct snd_rawmidi *rawmidi; |
1da177e4c Linux-2.6.12-rc2 |
780 |
int err; |
6fcfa3959 ALSA: sscape: cod... |
781 |
err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port, |
dba8b4699 ALSA: mpu401: cle... |
782 |
MPU401_INFO_INTEGRATED, irq, &rawmidi); |
6fcfa3959 ALSA: sscape: cod... |
783 784 |
if (err == 0) { struct snd_mpu401 *mpu = rawmidi->private_data; |
1da177e4c Linux-2.6.12-rc2 |
785 786 |
mpu->open_input = mpu401_open; mpu->open_output = mpu401_open; |
1da177e4c Linux-2.6.12-rc2 |
787 |
mpu->private_data = sscape; |
1da177e4c Linux-2.6.12-rc2 |
788 789 790 791 792 793 794 795 796 |
initialise_mpu401(mpu); } return err; } /* |
1da177e4c Linux-2.6.12-rc2 |
797 798 799 800 801 |
* Create an AD1845 PCM subdevice on the SoundScape. The AD1845 * is very much like a CS4231, with a few extra bits. We will * try to support at least some of the extra bits by overriding * some of the CS4231 callback. */ |
1bff292e9 ALSA: isa: remove... |
802 803 |
static int create_ad1845(struct snd_card *card, unsigned port, int irq, int dma1, int dma2) |
1da177e4c Linux-2.6.12-rc2 |
804 805 |
{ register struct soundscape *sscape = get_card_soundscape(card); |
7779f75f0 ALSA: wss_lib: re... |
806 |
struct snd_wss *chip; |
1da177e4c Linux-2.6.12-rc2 |
807 |
int err; |
1cb0fdeba ALSA: sscape: for... |
808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
int codec_type = WSS_HW_DETECT; switch (sscape->type) { case MEDIA_FX: case SSCAPE: /* * There are some freak examples of early Soundscape cards * with CS4231 instead of AD1848/CS4248. Unfortunately, the * CS4231 works only in CS4248 compatibility mode on * these cards so force it. */ if (sscape->ic_type != IC_OPUS) codec_type = WSS_HW_AD1848; break; |
1da177e4c Linux-2.6.12-rc2 |
822 |
|
1cb0fdeba ALSA: sscape: for... |
823 |
case SSCAPE_VIVO: |
ec1e79493 [ALSA] sscape: su... |
824 |
port += 4; |
1cb0fdeba ALSA: sscape: for... |
825 826 827 828 |
break; default: break; } |
ec1e79493 [ALSA] sscape: su... |
829 |
|
7779f75f0 ALSA: wss_lib: re... |
830 |
err = snd_wss_create(card, port, -1, irq, dma1, dma2, |
1cb0fdeba ALSA: sscape: for... |
831 |
codec_type, WSS_HWSHARE_DMA1, &chip); |
4996bca98 [ALSA] sscape: dr... |
832 |
if (!err) { |
1da177e4c Linux-2.6.12-rc2 |
833 |
unsigned long flags; |
1da177e4c Linux-2.6.12-rc2 |
834 |
|
ec1e79493 [ALSA] sscape: su... |
835 |
if (sscape->type != SSCAPE_VIVO) { |
ec1e79493 [ALSA] sscape: su... |
836 837 838 839 840 |
/* * The input clock frequency on the SoundScape must * be 14.31818 MHz, because we must set this register * to get the playback to sound correct ... */ |
7779f75f0 ALSA: wss_lib: re... |
841 |
snd_wss_mce_up(chip); |
ec1e79493 [ALSA] sscape: su... |
842 |
spin_lock_irqsave(&chip->reg_lock, flags); |
199f79787 ALSA: wss-lib: mo... |
843 |
snd_wss_out(chip, AD1845_CLOCK, 0x20); |
ec1e79493 [ALSA] sscape: su... |
844 |
spin_unlock_irqrestore(&chip->reg_lock, flags); |
7779f75f0 ALSA: wss_lib: re... |
845 |
snd_wss_mce_down(chip); |
1da177e4c Linux-2.6.12-rc2 |
846 |
|
ec1e79493 [ALSA] sscape: su... |
847 |
} |
1da177e4c Linux-2.6.12-rc2 |
848 |
|
fa60c0656 ALSA: wss: Remove... |
849 |
err = snd_wss_pcm(chip, 0); |
ec1e79493 [ALSA] sscape: su... |
850 851 852 853 |
if (err < 0) { snd_printk(KERN_ERR "sscape: No PCM device " "for AD1845 chip "); |
1da177e4c Linux-2.6.12-rc2 |
854 855 |
goto _error; } |
7779f75f0 ALSA: wss_lib: re... |
856 |
err = snd_wss_mixer(chip); |
ec1e79493 [ALSA] sscape: su... |
857 858 859 860 |
if (err < 0) { snd_printk(KERN_ERR "sscape: No mixer device " "for AD1845 chip "); |
1da177e4c Linux-2.6.12-rc2 |
861 862 |
goto _error; } |
199f79787 ALSA: wss-lib: mo... |
863 |
if (chip->hardware != WSS_HW_AD1848) { |
fa60c0656 ALSA: wss: Remove... |
864 |
err = snd_wss_timer(chip, 0); |
199f79787 ALSA: wss-lib: mo... |
865 866 867 868 869 870 |
if (err < 0) { snd_printk(KERN_ERR "sscape: No timer device " "for AD1845 chip "); goto _error; } |
1da177e4c Linux-2.6.12-rc2 |
871 |
} |
ec1e79493 [ALSA] sscape: su... |
872 873 874 875 876 877 878 879 880 |
if (sscape->type != SSCAPE_VIVO) { err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip)); if (err < 0) { snd_printk(KERN_ERR "sscape: Could not create " "MIDI mixer control "); goto _error; } |
ec1e79493 [ALSA] sscape: su... |
881 |
} |
1da177e4c Linux-2.6.12-rc2 |
882 883 |
sscape->chip = chip; } |
6fcfa3959 ALSA: sscape: cod... |
884 |
_error: |
1da177e4c Linux-2.6.12-rc2 |
885 886 |
return err; } |
1da177e4c Linux-2.6.12-rc2 |
887 888 889 890 |
/* * Create an ALSA soundcard entry for the SoundScape, using * the given list of port, IRQ and DMA resources. */ |
1bff292e9 ALSA: isa: remove... |
891 |
static int create_sscape(int dev, struct snd_card *card) |
1da177e4c Linux-2.6.12-rc2 |
892 |
{ |
ec1e79493 [ALSA] sscape: su... |
893 894 |
struct soundscape *sscape = get_card_soundscape(card); unsigned dma_cfg; |
1da177e4c Linux-2.6.12-rc2 |
895 896 897 |
unsigned irq_cfg; unsigned mpu_irq_cfg; struct resource *io_res; |
ec1e79493 [ALSA] sscape: su... |
898 |
struct resource *wss_res; |
1da177e4c Linux-2.6.12-rc2 |
899 900 |
unsigned long flags; int err; |
1cb0fdeba ALSA: sscape: for... |
901 |
int val; |
f0968e3f7 ALSA: sscape: add... |
902 |
const char *name; |
1da177e4c Linux-2.6.12-rc2 |
903 904 905 906 907 |
/* * Grab IO ports that we will need to probe so that we * can detect and control this hardware ... */ |
453e37b37 ALSA: sscape: dro... |
908 |
io_res = request_region(port[dev], 8, "SoundScape"); |
ec1e79493 [ALSA] sscape: su... |
909 |
if (!io_res) { |
453e37b37 ALSA: sscape: dro... |
910 911 912 |
snd_printk(KERN_ERR "sscape: can't grab port 0x%lx ", port[dev]); |
1da177e4c Linux-2.6.12-rc2 |
913 914 |
return -EBUSY; } |
ec1e79493 [ALSA] sscape: su... |
915 916 917 918 919 920 921 922 923 924 925 |
wss_res = NULL; if (sscape->type == SSCAPE_VIVO) { wss_res = request_region(wss_port[dev], 4, "SoundScape"); if (!wss_res) { snd_printk(KERN_ERR "sscape: can't grab port 0x%lx ", wss_port[dev]); err = -EBUSY; goto _release_region; } } |
1da177e4c Linux-2.6.12-rc2 |
926 927 |
/* |
ec1e79493 [ALSA] sscape: su... |
928 |
* Grab one DMA channel ... |
1da177e4c Linux-2.6.12-rc2 |
929 |
*/ |
4996bca98 [ALSA] sscape: dr... |
930 931 |
err = request_dma(dma[dev], "SoundScape"); if (err < 0) { |
277e926c9 [ALSA] sscape - U... |
932 933 |
snd_printk(KERN_ERR "sscape: can't grab DMA %d ", dma[dev]); |
1da177e4c Linux-2.6.12-rc2 |
934 935 |
goto _release_region; } |
1da177e4c Linux-2.6.12-rc2 |
936 |
spin_lock_init(&sscape->lock); |
1da177e4c Linux-2.6.12-rc2 |
937 |
sscape->io_res = io_res; |
ec1e79493 [ALSA] sscape: su... |
938 |
sscape->wss_res = wss_res; |
453e37b37 ALSA: sscape: dro... |
939 |
sscape->io_base = port[dev]; |
1da177e4c Linux-2.6.12-rc2 |
940 |
|
453e37b37 ALSA: sscape: dro... |
941 |
if (!detect_sscape(sscape, wss_port[dev])) { |
bcde1f8a8 ALSA: sscape: rem... |
942 943 944 |
printk(KERN_ERR "sscape: hardware not detected at 0x%x ", sscape->io_base); |
1da177e4c Linux-2.6.12-rc2 |
945 |
err = -ENODEV; |
4996bca98 [ALSA] sscape: dr... |
946 |
goto _release_dma; |
1da177e4c Linux-2.6.12-rc2 |
947 |
} |
f0968e3f7 ALSA: sscape: add... |
948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 |
switch (sscape->type) { case MEDIA_FX: name = "MediaFX/SoundFX"; break; case SSCAPE: name = "Soundscape"; break; case SSCAPE_PNP: name = "Soundscape PnP"; break; case SSCAPE_VIVO: name = "Soundscape VIVO"; break; default: name = "unknown Soundscape"; break; } printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d ", name, sscape->io_base, irq[dev], dma[dev]); /* * Check that the user didn't pass us garbage data ... */ irq_cfg = get_irq_config(sscape->type, irq[dev]); if (irq_cfg == INVALID_IRQ) { snd_printk(KERN_ERR "sscape: Invalid IRQ %d ", irq[dev]); |
38be95dd3 ALSA: sound/isa/s... |
977 978 |
err = -ENXIO; goto _release_dma; |
f0968e3f7 ALSA: sscape: add... |
979 980 981 982 |
} mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]); if (mpu_irq_cfg == INVALID_IRQ) { |
bcde1f8a8 ALSA: sscape: rem... |
983 984 |
snd_printk(KERN_ERR "sscape: Invalid IRQ %d ", mpu_irq[dev]); |
38be95dd3 ALSA: sound/isa/s... |
985 986 |
err = -ENXIO; goto _release_dma; |
f0968e3f7 ALSA: sscape: add... |
987 |
} |
1da177e4c Linux-2.6.12-rc2 |
988 |
|
1da177e4c Linux-2.6.12-rc2 |
989 990 991 992 993 |
/* * Tell the on-board devices where their resources are (I think - * I can't be sure without a datasheet ... So many magic values!) */ spin_lock_irqsave(&sscape->lock, flags); |
1da177e4c Linux-2.6.12-rc2 |
994 995 996 997 998 999 1000 |
sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); /* * Enable and configure the DMA channels ... */ sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); |
f0968e3f7 ALSA: sscape: add... |
1001 |
dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70); |
1da177e4c Linux-2.6.12-rc2 |
1002 1003 |
sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); |
f0968e3f7 ALSA: sscape: add... |
1004 |
mpu_irq_cfg |= mpu_irq_cfg << 2; |
1cb0fdeba ALSA: sscape: for... |
1005 1006 1007 1008 |
val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7; if (joystick[dev]) val |= 8; sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10); |
f0968e3f7 ALSA: sscape: add... |
1009 |
sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); |
1da177e4c Linux-2.6.12-rc2 |
1010 |
sscape_write_unsafe(sscape->io_base, |
4996bca98 [ALSA] sscape: dr... |
1011 1012 |
GA_CDCFG_REG, 0x09 | DMA_8BIT | (dma[dev] << 4) | (irq_cfg << 1)); |
6fcfa3959 ALSA: sscape: cod... |
1013 1014 1015 1016 |
/* * Enable the master IRQ ... */ sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80); |
1da177e4c Linux-2.6.12-rc2 |
1017 1018 1019 1020 1021 1022 1023 |
spin_unlock_irqrestore(&sscape->lock, flags); /* * We have now enabled the codec chip, and so we should * detect the AD1845 device ... */ |
4996bca98 [ALSA] sscape: dr... |
1024 1025 1026 |
err = create_ad1845(card, wss_port[dev], irq[dev], dma[dev], dma2[dev]); if (err < 0) { |
bcde1f8a8 ALSA: sscape: rem... |
1027 1028 1029 1030 |
snd_printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d ", wss_port[dev], irq[dev]); |
4996bca98 [ALSA] sscape: dr... |
1031 |
goto _release_dma; |
1da177e4c Linux-2.6.12-rc2 |
1032 |
} |
acd471009 ALSA: sscape: con... |
1033 1034 1035 1036 1037 1038 1039 |
strcpy(card->driver, "SoundScape"); strcpy(card->shortname, name); snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d ", name, sscape->chip->port, sscape->chip->irq, sscape->chip->dma1, sscape->chip->dma2); |
1da177e4c Linux-2.6.12-rc2 |
1040 |
#define MIDI_DEVNUM 0 |
ec1e79493 [ALSA] sscape: su... |
1041 |
if (sscape->type != SSCAPE_VIVO) { |
acd471009 ALSA: sscape: con... |
1042 1043 1044 |
err = sscape_upload_bootblock(card); if (err >= 0) err = sscape_upload_microcode(card, err); |
1da177e4c Linux-2.6.12-rc2 |
1045 |
|
acd471009 ALSA: sscape: con... |
1046 1047 1048 1049 |
if (err == 0) { err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]); if (err < 0) { |
bcde1f8a8 ALSA: sscape: rem... |
1050 |
snd_printk(KERN_ERR "sscape: Failed to create " |
acd471009 ALSA: sscape: con... |
1051 1052 1053 1054 1055 1056 1057 |
"MPU-401 device at 0x%lx ", port[dev]); goto _release_dma; } /* |
acd471009 ALSA: sscape: con... |
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 |
* Initialize mixer */ spin_lock_irqsave(&sscape->lock, flags); sscape->midi_vol = 0; host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); host_write_ctrl_unsafe(sscape->io_base, sscape->midi_vol, 100); host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100); host_write_ctrl_unsafe(sscape->io_base, sscape->midi_vol, 100); host_write_ctrl_unsafe(sscape->io_base, CMD_SET_EXTMIDI, 100); host_write_ctrl_unsafe(sscape->io_base, 0, 100); host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100); set_midi_mode_unsafe(sscape->io_base); spin_unlock_irqrestore(&sscape->lock, flags); } |
ec1e79493 [ALSA] sscape: su... |
1079 |
} |
1da177e4c Linux-2.6.12-rc2 |
1080 1081 1082 1083 1084 1085 1086 1087 |
/* * Now that we have successfully created this sound card, * it is safe to store the pointer. * NOTE: we only register the sound card's "destructor" * function now that our "constructor" has completed. */ card->private_free = soundscape_free; |
1da177e4c Linux-2.6.12-rc2 |
1088 1089 |
return 0; |
4996bca98 [ALSA] sscape: dr... |
1090 |
_release_dma: |
277e926c9 [ALSA] sscape - U... |
1091 |
free_dma(dma[dev]); |
1da177e4c Linux-2.6.12-rc2 |
1092 |
|
4996bca98 [ALSA] sscape: dr... |
1093 |
_release_region: |
ec1e79493 [ALSA] sscape: su... |
1094 |
release_and_free_resource(wss_res); |
b1d5776d8 [ALSA] Remove vma... |
1095 |
release_and_free_resource(io_res); |
1da177e4c Linux-2.6.12-rc2 |
1096 1097 1098 |
return err; } |
1bff292e9 ALSA: isa: remove... |
1099 |
static int snd_sscape_match(struct device *pdev, unsigned int i) |
5e24c1c1c [ALSA] Port the r... |
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 |
{ /* * Make sure we were given ALL of the other parameters. */ if (port[i] == SNDRV_AUTO_PORT) return 0; if (irq[i] == SNDRV_AUTO_IRQ || mpu_irq[i] == SNDRV_AUTO_IRQ || dma[i] == SNDRV_AUTO_DMA) { printk(KERN_INFO |
6fcfa3959 ALSA: sscape: cod... |
1111 1112 1113 |
"sscape: insufficient parameters, " "need IO, IRQ, MPU-IRQ and DMA "); |
5e24c1c1c [ALSA] Port the r... |
1114 1115 1116 1117 1118 |
return 0; } return 1; } |
1bff292e9 ALSA: isa: remove... |
1119 |
static int snd_sscape_probe(struct device *pdev, unsigned int dev) |
277e926c9 [ALSA] sscape - U... |
1120 |
{ |
277e926c9 [ALSA] sscape - U... |
1121 |
struct snd_card *card; |
4996bca98 [ALSA] sscape: dr... |
1122 |
struct soundscape *sscape; |
277e926c9 [ALSA] sscape - U... |
1123 |
int ret; |
4323cc4d5 ALSA: isa: Conver... |
1124 1125 |
ret = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE, sizeof(struct soundscape), &card); |
c95eadd2f ALSA: Convert to ... |
1126 1127 |
if (ret < 0) return ret; |
4996bca98 [ALSA] sscape: dr... |
1128 1129 1130 |
sscape = get_card_soundscape(card); sscape->type = SSCAPE; |
277e926c9 [ALSA] sscape - U... |
1131 |
dma[dev] &= 0x03; |
acd471009 ALSA: sscape: con... |
1132 |
|
4996bca98 [ALSA] sscape: dr... |
1133 |
ret = create_sscape(dev, card); |
277e926c9 [ALSA] sscape - U... |
1134 |
if (ret < 0) |
4996bca98 [ALSA] sscape: dr... |
1135 |
goto _release_card; |
6fcfa3959 ALSA: sscape: cod... |
1136 1137 |
ret = snd_card_register(card); if (ret < 0) { |
bcde1f8a8 ALSA: sscape: rem... |
1138 1139 |
snd_printk(KERN_ERR "sscape: Failed to register sound card "); |
4996bca98 [ALSA] sscape: dr... |
1140 |
goto _release_card; |
277e926c9 [ALSA] sscape - U... |
1141 |
} |
5e24c1c1c [ALSA] Port the r... |
1142 |
dev_set_drvdata(pdev, card); |
277e926c9 [ALSA] sscape - U... |
1143 |
return 0; |
4996bca98 [ALSA] sscape: dr... |
1144 1145 1146 1147 |
_release_card: snd_card_free(card); return ret; |
277e926c9 [ALSA] sscape - U... |
1148 |
} |
1bff292e9 ALSA: isa: remove... |
1149 |
static int snd_sscape_remove(struct device *devptr, unsigned int dev) |
277e926c9 [ALSA] sscape - U... |
1150 |
{ |
5e24c1c1c [ALSA] Port the r... |
1151 |
snd_card_free(dev_get_drvdata(devptr)); |
277e926c9 [ALSA] sscape - U... |
1152 1153 |
return 0; } |
83c51c0ab [ALSA] isa_bus de... |
1154 |
#define DEV_NAME "sscape" |
277e926c9 [ALSA] sscape - U... |
1155 |
|
5e24c1c1c [ALSA] Port the r... |
1156 1157 |
static struct isa_driver snd_sscape_driver = { .match = snd_sscape_match, |
277e926c9 [ALSA] sscape - U... |
1158 |
.probe = snd_sscape_probe, |
1bff292e9 ALSA: isa: remove... |
1159 |
.remove = snd_sscape_remove, |
277e926c9 [ALSA] sscape - U... |
1160 1161 |
/* FIXME: suspend/resume */ .driver = { |
83c51c0ab [ALSA] isa_bus de... |
1162 |
.name = DEV_NAME |
277e926c9 [ALSA] sscape - U... |
1163 1164 |
}, }; |
1da177e4c Linux-2.6.12-rc2 |
1165 1166 |
#ifdef CONFIG_PNP |
1bff292e9 ALSA: isa: remove... |
1167 |
static inline int get_next_autoindex(int i) |
1da177e4c Linux-2.6.12-rc2 |
1168 |
{ |
277e926c9 [ALSA] sscape - U... |
1169 |
while (i < SNDRV_CARDS && port[i] != SNDRV_AUTO_PORT) |
1da177e4c Linux-2.6.12-rc2 |
1170 |
++i; |
1da177e4c Linux-2.6.12-rc2 |
1171 1172 |
return i; } |
1bff292e9 ALSA: isa: remove... |
1173 1174 |
static int sscape_pnp_detect(struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) |
1da177e4c Linux-2.6.12-rc2 |
1175 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1176 |
static int idx = 0; |
277e926c9 [ALSA] sscape - U... |
1177 1178 |
struct pnp_dev *dev; struct snd_card *card; |
4996bca98 [ALSA] sscape: dr... |
1179 |
struct soundscape *sscape; |
1da177e4c Linux-2.6.12-rc2 |
1180 1181 1182 1183 1184 1185 |
int ret; /* * Allow this function to fail *quietly* if all the ISA PnP * devices were configured using module parameters instead. */ |
6fcfa3959 ALSA: sscape: cod... |
1186 1187 |
idx = get_next_autoindex(idx); if (idx >= SNDRV_CARDS) |
1da177e4c Linux-2.6.12-rc2 |
1188 |
return -ENOSPC; |
1da177e4c Linux-2.6.12-rc2 |
1189 1190 |
/* |
1da177e4c Linux-2.6.12-rc2 |
1191 1192 |
* Check that we still have room for another sound card ... */ |
1da177e4c Linux-2.6.12-rc2 |
1193 |
dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL); |
6fcfa3959 ALSA: sscape: cod... |
1194 |
if (!dev) |
277e926c9 [ALSA] sscape - U... |
1195 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
1196 |
|
277e926c9 [ALSA] sscape - U... |
1197 1198 |
if (!pnp_is_active(dev)) { if (pnp_activate_dev(dev) < 0) { |
bcde1f8a8 ALSA: sscape: rem... |
1199 1200 |
snd_printk(KERN_INFO "sscape: device is inactive "); |
277e926c9 [ALSA] sscape - U... |
1201 |
return -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
1202 1203 |
} } |
277e926c9 [ALSA] sscape - U... |
1204 |
/* |
4996bca98 [ALSA] sscape: dr... |
1205 1206 1207 |
* Create a new ALSA sound card entry, in anticipation * of detecting our hardware ... */ |
4323cc4d5 ALSA: isa: Conver... |
1208 1209 1210 |
ret = snd_card_new(&pcard->card->dev, index[idx], id[idx], THIS_MODULE, sizeof(struct soundscape), &card); |
c95eadd2f ALSA: Convert to ... |
1211 1212 |
if (ret < 0) return ret; |
4996bca98 [ALSA] sscape: dr... |
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 |
sscape = get_card_soundscape(card); /* * Identify card model ... */ if (!strncmp("ENS4081", pid->id, 7)) sscape->type = SSCAPE_VIVO; else sscape->type = SSCAPE_PNP; |
4996bca98 [ALSA] sscape: dr... |
1223 |
/* |
277e926c9 [ALSA] sscape - U... |
1224 1225 1226 1227 1228 1229 |
* Read the correct parameters off the ISA PnP bus ... */ port[idx] = pnp_port_start(dev, 0); irq[idx] = pnp_irq(dev, 0); mpu_irq[idx] = pnp_irq(dev, 1); dma[idx] = pnp_dma(dev, 0) & 0x03; |
ec1e79493 [ALSA] sscape: su... |
1230 1231 1232 1233 1234 1235 1236 |
if (sscape->type == SSCAPE_PNP) { dma2[idx] = dma[idx]; wss_port[idx] = CODEC_IO(port[idx]); } else { wss_port[idx] = pnp_port_start(dev, 1); dma2[idx] = pnp_dma(dev, 1); } |
277e926c9 [ALSA] sscape - U... |
1237 |
|
4996bca98 [ALSA] sscape: dr... |
1238 |
ret = create_sscape(idx, card); |
277e926c9 [ALSA] sscape - U... |
1239 |
if (ret < 0) |
4996bca98 [ALSA] sscape: dr... |
1240 |
goto _release_card; |
6fcfa3959 ALSA: sscape: cod... |
1241 1242 |
ret = snd_card_register(card); if (ret < 0) { |
bcde1f8a8 ALSA: sscape: rem... |
1243 1244 |
snd_printk(KERN_ERR "sscape: Failed to register sound card "); |
4996bca98 [ALSA] sscape: dr... |
1245 |
goto _release_card; |
277e926c9 [ALSA] sscape - U... |
1246 1247 1248 1249 |
} pnp_set_card_drvdata(pcard, card); ++idx; |
4996bca98 [ALSA] sscape: dr... |
1250 |
return 0; |
277e926c9 [ALSA] sscape - U... |
1251 |
|
4996bca98 [ALSA] sscape: dr... |
1252 1253 |
_release_card: snd_card_free(card); |
1da177e4c Linux-2.6.12-rc2 |
1254 1255 |
return ret; } |
1bff292e9 ALSA: isa: remove... |
1256 |
static void sscape_pnp_remove(struct pnp_card_link *pcard) |
1da177e4c Linux-2.6.12-rc2 |
1257 |
{ |
277e926c9 [ALSA] sscape - U... |
1258 |
snd_card_free(pnp_get_card_drvdata(pcard)); |
1da177e4c Linux-2.6.12-rc2 |
1259 |
pnp_set_card_drvdata(pcard, NULL); |
1da177e4c Linux-2.6.12-rc2 |
1260 1261 1262 1263 1264 1265 1266 |
} static struct pnp_card_driver sscape_pnpc_driver = { .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, .name = "sscape", .id_table = sscape_pnpids, .probe = sscape_pnp_detect, |
1bff292e9 ALSA: isa: remove... |
1267 |
.remove = sscape_pnp_remove, |
1da177e4c Linux-2.6.12-rc2 |
1268 1269 1270 |
}; #endif /* CONFIG_PNP */ |
1da177e4c Linux-2.6.12-rc2 |
1271 1272 |
static int __init sscape_init(void) { |
609d76941 [ALSA] Fix probe ... |
1273 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
1274 |
|
609d76941 [ALSA] Fix probe ... |
1275 |
err = isa_register_driver(&snd_sscape_driver, SNDRV_CARDS); |
59b1b34f4 [ALSA] Fix compil... |
1276 |
#ifdef CONFIG_PNP |
609d76941 [ALSA] Fix probe ... |
1277 1278 1279 1280 1281 |
if (!err) isa_registered = 1; err = pnp_register_card_driver(&sscape_pnpc_driver); if (!err) |
f7a9275d9 [ALSA] unregister... |
1282 |
pnp_registered = 1; |
609d76941 [ALSA] Fix probe ... |
1283 1284 1285 |
if (isa_registered) err = 0; |
59b1b34f4 [ALSA] Fix compil... |
1286 |
#endif |
609d76941 [ALSA] Fix probe ... |
1287 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
1288 |
} |
5e24c1c1c [ALSA] Port the r... |
1289 1290 1291 1292 1293 |
static void __exit sscape_exit(void) { #ifdef CONFIG_PNP if (pnp_registered) pnp_unregister_card_driver(&sscape_pnpc_driver); |
609d76941 [ALSA] Fix probe ... |
1294 |
if (isa_registered) |
5e24c1c1c [ALSA] Port the r... |
1295 |
#endif |
609d76941 [ALSA] Fix probe ... |
1296 |
isa_unregister_driver(&snd_sscape_driver); |
5e24c1c1c [ALSA] Port the r... |
1297 |
} |
1da177e4c Linux-2.6.12-rc2 |
1298 1299 |
module_init(sscape_init); module_exit(sscape_exit); |