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