Blame view

sound/isa/sscape.c 32.1 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
acd471009   Krzysztof Helt   ALSA: sscape: con...
3
   *   Low-level ALSA driver for the ENSONIQ SoundScape
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
8
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/init.h>
277e926c9   Takashi Iwai   [ALSA] sscape - U...
10
  #include <linux/err.h>
37419584a   Arnd Bergmann   ALSA: sscape: add...
11
  #include <linux/io.h>
5e24c1c1c   Takashi Iwai   [ALSA] Port the r...
12
  #include <linux/isa.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/delay.h>
acd471009   Krzysztof Helt   ALSA: sscape: con...
14
  #include <linux/firmware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/pnp.h>
  #include <linux/spinlock.h>
65a772172   Paul Gortmaker   sound: fix driver...
17
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  #include <asm/dma.h>
  #include <sound/core.h>
61ef19d7e   Krzysztof Helt   ALSA: wss_lib: re...
20
  #include <sound/wss.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  #include <sound/mpu401.h>
  #include <sound/initval.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  
  MODULE_AUTHOR("Chris Rankin");
acd471009   Krzysztof Helt   ALSA: sscape: con...
25
  MODULE_DESCRIPTION("ENSONIQ SoundScape driver");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  MODULE_LICENSE("GPL");
acd471009   Krzysztof Helt   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   Linus Torvalds   Linux-2.6.12-rc2
33

ed76f652d   Takashi Iwai   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   Linus Torvalds   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   David Howells   Annotate hardware...
49
  module_param_hw_array(port, long, ioport, NULL, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  MODULE_PARM_DESC(port, "Port # for SoundScape driver.");
e992ef570   David Howells   Annotate hardware...
51
  module_param_hw_array(wss_port, long, ioport, NULL, 0444);
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
52
  MODULE_PARM_DESC(wss_port, "WSS Port # for SoundScape driver.");
e992ef570   David Howells   Annotate hardware...
53
  module_param_hw_array(irq, int, irq, NULL, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver.");
e992ef570   David Howells   Annotate hardware...
55
  module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # for SoundScape driver.");
e992ef570   David Howells   Annotate hardware...
57
  module_param_hw_array(dma, int, dma, NULL, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  MODULE_PARM_DESC(dma, "DMA # for SoundScape driver.");
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
59

e992ef570   David Howells   Annotate hardware...
60
  module_param_hw_array(dma2, int, dma, NULL, 0444);
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
61
  MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver.");
1cb0fdeba   Krzysztof Helt   ALSA: sscape: for...
62
63
  module_param_array(joystick, bool, NULL, 0444);
  MODULE_PARM_DESC(joystick, "Enable gameport.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  #ifdef CONFIG_PNP
609d76941   Rene Herman   [ALSA] Fix probe ...
65
  static int isa_registered;
59b1b34f4   Takashi Iwai   [ALSA] Fix compil...
66
  static int pnp_registered;
609d76941   Rene Herman   [ALSA] Fix probe ...
67

05e20b265   Arvind Yadav   ALSA: sscape: con...
68
  static const struct pnp_card_device_id sscape_pnpids[] = {
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
69
70
  	{ .id = "ENS3081", .devs = { { "ENS0000" } } }, /* Soundscape PnP */
  	{ .id = "ENS4081", .devs = { { "ENS1011" } } },	/* VIVO90 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
  	{ .id = "" }	/* end */
  };
  
  MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

1da177e4c   Linus Torvalds   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   Krzysztof Helt   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   Linus Torvalds   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   Krzysztof Helt   [ALSA] sscape: dr...
111
  enum card_type {
f0968e3f7   Krzysztof Helt   ALSA: sscape: add...
112
113
  	MEDIA_FX,	/* Sequoia S-1000 */
  	SSCAPE,		/* Sequoia S-2000 */
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
114
115
116
  	SSCAPE_PNP,
  	SSCAPE_VIVO,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
  struct soundscape {
  	spinlock_t lock;
  	unsigned io_base;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  	int ic_type;
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
121
  	enum card_type type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  	struct resource *io_res;
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
123
  	struct resource *wss_res;
7779f75f0   Krzysztof Helt   ALSA: wss_lib: re...
124
  	struct snd_wss *chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
  	unsigned char midi_vol;
  };
  
  #define INVALID_IRQ  ((unsigned)-1)
be6245373   Takashi Iwai   [ALSA] Remove xxx...
130
  static inline struct soundscape *get_card_soundscape(struct snd_card *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
  {
  	return (struct soundscape *) (c->private_data);
  }
1da177e4c   Linus Torvalds   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   Takashi Iwai   ALSA: isa: Avoid ...
139
140
  static struct snd_dma_buffer *get_dmabuf(struct soundscape *s,
  					 struct snd_dma_buffer *buf,
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
141
  					 unsigned long size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
  {
  	if (buf) {
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
144
  		if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV,
0b6a2c9cf   Takashi Iwai   ALSA: isa: Avoid ...
145
  						 s->chip->card->dev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  						 size, buf) < 0) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
147
148
149
150
  			snd_printk(KERN_ERR "sscape: Failed to allocate "
  					    "%lu bytes for DMA
  ",
  					    size);
1da177e4c   Linus Torvalds   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   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
171
172
  static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg,
  				       unsigned char val)
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
182
183
  static void sscape_write(struct soundscape *s, enum GA_REG reg,
  			 unsigned char val)
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
196
197
  static inline unsigned char sscape_read_unsafe(unsigned io_base,
  					       enum GA_REG reg)
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
226
  	if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  		data = inb(HOST_DATA_IO(io_base));
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
269
  				  unsigned timeout)
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
288
  static inline int verify_mpu401(const struct snd_mpu401 *mpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  {
c9864fd30   Krzysztof Helt   ALSA: sscape: use...
290
  	return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
  }
  
  /*
f5d0f820f   Liang Wang   ALSA: isa: fix sp...
294
   * This is apparently the standard way to initialise an MPU-401
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
   */
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
296
  static inline void initialise_mpu401(const struct snd_mpu401 *mpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  {
c9864fd30   Krzysztof Helt   ALSA: sscape: use...
298
  	outb(0, MPU401D(mpu));
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
306
  static void activate_ad1845_unsafe(unsigned io_base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  {
6fcfa3959   Krzysztof Helt   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   Linus Torvalds   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   Takashi Iwai   [ALSA] Remove xxx...
316
  static void soundscape_free(struct snd_card *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  {
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
318
  	struct soundscape *sscape = get_card_soundscape(c);
b1d5776d8   Takashi Iwai   [ALSA] Remove vma...
319
  	release_and_free_resource(sscape->io_res);
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
320
  	release_and_free_resource(sscape->wss_res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
324
  	free_dma(sscape->chip->dma1);
  }
  
  /*
f5d0f820f   Liang Wang   ALSA: isa: fix sp...
325
   * Tell the SoundScape to begin a DMA transfer using the given channel.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
   * All locking issues are left to the caller.
   */
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
328
  static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  {
6fcfa3959   Krzysztof Helt   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   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
340
341
  static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg,
  				  unsigned timeout)
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
347
  	return sscape_read_unsafe(io_base, reg) & 0x01;
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: fix...
359
360
361
  	unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
  
  	do {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  		unsigned long flags;
acd471009   Krzysztof Helt   ALSA: sscape: con...
363
  		int x;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  		spin_lock_irqsave(&s->lock, flags);
acd471009   Krzysztof Helt   ALSA: sscape: con...
366
  		x = host_read_unsafe(s->io_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  		spin_unlock_irqrestore(&s->lock, flags);
acd471009   Krzysztof Helt   ALSA: sscape: con...
368
  		if (x == 0xfe || x == 0xff)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  			return 1;
554b91ede   Krzysztof Helt   ALSA: sscape: fix...
370
371
  		msleep(10);
  	} while (time_before(jiffies, end_time));
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: fix...
385
386
387
  	unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
  
  	do {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  		unsigned long flags;
acd471009   Krzysztof Helt   ALSA: sscape: con...
389
  		int x;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  		spin_lock_irqsave(&s->lock, flags);
acd471009   Krzysztof Helt   ALSA: sscape: con...
392
  		x = host_read_unsafe(s->io_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
  		spin_unlock_irqrestore(&s->lock, flags);
  		if (x == 0xfe)
  			return 1;
554b91ede   Krzysztof Helt   ALSA: sscape: fix...
396
397
  		msleep(10);
  	} while (time_before(jiffies, end_time));
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
405
406
  static int upload_dma_data(struct soundscape *s, const unsigned char *data,
  			   size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
  {
  	unsigned long flags;
  	struct snd_dma_buffer dma;
  	int ret;
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
411
  	unsigned char val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412

0b6a2c9cf   Takashi Iwai   ALSA: isa: Avoid ...
413
  	if (!get_dmabuf(s, &dma, PAGE_ALIGN(32 * 1024)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
418
419
420
  		return -ENOMEM;
  
  	spin_lock_irqsave(&s->lock, flags);
  
  	/*
  	 * Reset the board ...
  	 */
6fcfa3959   Krzysztof Helt   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   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
  
  	/*
  	 * Enable the DMA channels and configure them ...
  	 */
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
427
428
  	val = (s->chip->dma1 << 4) | DMA_8BIT;
  	sscape_write_unsafe(s->io_base, GA_DMAA_REG, val);
1da177e4c   Linus Torvalds   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   Krzysztof Helt   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   Linus Torvalds   Linux-2.6.12-rc2
436
437
  
  	/*
acd471009   Krzysztof Helt   ALSA: sscape: con...
438
  	 * Upload the firmware to the SoundScape
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
  	 * board through the DMA channel ...
  	 */
  	while (size != 0) {
  		unsigned long len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
  		len = min(size, dma.bytes);
acd471009   Krzysztof Helt   ALSA: sscape: con...
444
  		memcpy(dma.area, data, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
  		data += len;
  		size -= len;
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
451
  			 * Don't forget to release this spinlock we're holding
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
  			 */
  			spin_unlock_irqrestore(&s->lock, flags);
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
454
455
456
  			snd_printk(KERN_ERR
  					"sscape: DMA upload has timed out
  ");
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: con...
463
  	outb(0x0, s->io_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
466
467
  
  	/*
  	 * Boot the board ... (I think)
  	 */
6fcfa3959   Krzysztof Helt   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   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: fix...
478
  	if (!obp_startup_ack(s, 5000)) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
479
480
481
  		snd_printk(KERN_ERR "sscape: No response "
  				    "from on-board processor after upload
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  		ret = -EAGAIN;
554b91ede   Krzysztof Helt   ALSA: sscape: fix...
483
  	} else if (!host_startup_ack(s, 5000)) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
484
485
486
  		snd_printk(KERN_ERR
  				"sscape: SoundScape failed to initialise
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  		ret = -EAGAIN;
  	}
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
489
  _release_dma:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
  	/*
  	 * NOTE!!! We are NOT holding any spinlocks at this point !!!
  	 */
acd471009   Krzysztof Helt   ALSA: sscape: con...
493
  	sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70));
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
503
   */
acd471009   Krzysztof Helt   ALSA: sscape: con...
504
  static int sscape_upload_bootblock(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  {
acd471009   Krzysztof Helt   ALSA: sscape: con...
506
  	struct soundscape *sscape = get_card_soundscape(card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  	unsigned long flags;
acd471009   Krzysztof Helt   ALSA: sscape: con...
508
  	const struct firmware *init_fw = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  	int data = 0;
  	int ret;
acd471009   Krzysztof Helt   ALSA: sscape: con...
511
512
  	ret = request_firmware(&init_fw, "scope.cod", card->dev);
  	if (ret < 0) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
513
  		snd_printk(KERN_ERR "sscape: Error loading scope.cod");
acd471009   Krzysztof Helt   ALSA: sscape: con...
514
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  	}
acd471009   Krzysztof Helt   ALSA: sscape: con...
516
  	ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517

acd471009   Krzysztof Helt   ALSA: sscape: con...
518
  	release_firmware(init_fw);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519

acd471009   Krzysztof Helt   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   Linus Torvalds   Linux-2.6.12-rc2
523

acd471009   Krzysztof Helt   ALSA: sscape: con...
524
525
  	if (data & 0x10)
  		sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  	spin_unlock_irqrestore(&sscape->lock, flags);
acd471009   Krzysztof Helt   ALSA: sscape: con...
528
529
  	data &= 0xf;
  	if (ret == 0 && data > 7) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
530
531
532
  		snd_printk(KERN_ERR
  				"sscape: timeout reading firmware version
  ");
acd471009   Krzysztof Helt   ALSA: sscape: con...
533
534
  		ret = -EAGAIN;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535

acd471009   Krzysztof Helt   ALSA: sscape: con...
536
  	return (ret == 0) ? data : ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
  }
  
  /*
acd471009   Krzysztof Helt   ALSA: sscape: con...
540
   * Upload the microcode into the SoundScape.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
   */
acd471009   Krzysztof Helt   ALSA: sscape: con...
542
  static int sscape_upload_microcode(struct snd_card *card, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  {
acd471009   Krzysztof Helt   ALSA: sscape: con...
544
545
546
  	struct soundscape *sscape = get_card_soundscape(card);
  	const struct firmware *init_fw = NULL;
  	char name[14];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  	int err;
acd471009   Krzysztof Helt   ALSA: sscape: con...
548
  	snprintf(name, sizeof(name), "sndscape.co%d", version);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549

acd471009   Krzysztof Helt   ALSA: sscape: con...
550
551
  	err = request_firmware(&init_fw, name, card->dev);
  	if (err < 0) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
552
553
  		snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d",
  				version);
acd471009   Krzysztof Helt   ALSA: sscape: con...
554
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  	}
acd471009   Krzysztof Helt   ALSA: sscape: con...
556
557
  	err = upload_dma_data(sscape, init_fw->data, init_fw->size);
  	if (err == 0)
dc5027a72   William Breathitt Gray   ALSA: sscape: Use...
558
559
  		snd_printk(KERN_INFO "sscape: MIDI firmware loaded %zu KBs
  ",
acd471009   Krzysztof Helt   ALSA: sscape: con...
560
  				init_fw->size >> 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561

acd471009   Krzysztof Helt   ALSA: sscape: con...
562
  	release_firmware(init_fw);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
  
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
  /*
   * Mixer control for the SoundScape's MIDI device.
   */
be6245373   Takashi Iwai   [ALSA] Remove xxx...
569
  static int sscape_midi_info(struct snd_kcontrol *ctl,
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
570
  			    struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   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   Takashi Iwai   [ALSA] Remove xxx...
578
  static int sscape_midi_get(struct snd_kcontrol *kctl,
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
579
  			   struct snd_ctl_elem_value *uctl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  {
7779f75f0   Krzysztof Helt   ALSA: wss_lib: re...
581
  	struct snd_wss *chip = snd_kcontrol_chip(kctl);
be6245373   Takashi Iwai   [ALSA] Remove xxx...
582
  	struct snd_card *card = chip->card;
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: dro...
587
  	uctl->value.integer.value[0] = s->midi_vol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
  	spin_unlock_irqrestore(&s->lock, flags);
  	return 0;
  }
be6245373   Takashi Iwai   [ALSA] Remove xxx...
591
  static int sscape_midi_put(struct snd_kcontrol *kctl,
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
592
  			   struct snd_ctl_elem_value *uctl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
  {
7779f75f0   Krzysztof Helt   ALSA: wss_lib: re...
594
  	struct snd_wss *chip = snd_kcontrol_chip(kctl);
be6245373   Takashi Iwai   [ALSA] Remove xxx...
595
  	struct snd_card *card = chip->card;
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
596
  	struct soundscape *s = get_card_soundscape(card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
  	unsigned long flags;
  	int change;
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
599
  	unsigned char new_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
  
  	spin_lock_irqsave(&s->lock, flags);
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
602
  	new_val = uctl->value.integer.value[0] & 127;
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
615
  	if (s->midi_vol == new_val) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
  		change = 0;
  		goto __skip_change;
  	}
6fcfa3959   Krzysztof Helt   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   Linus Torvalds   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   Bhumika Goyal   ALSA: sound/isa: ...
634
  static const struct snd_kcontrol_new midi_mixer_ctl = {
1da177e4c   Linus Torvalds   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   Bill Pemberton   ALSA: isa: remove...
647
  static unsigned get_irq_config(int sscape_type, int irq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
  {
  	static const int valid_irq[] = { 9, 5, 7, 10 };
f0968e3f7   Krzysztof Helt   ALSA: sscape: add...
650
  	static const int old_irq[] = { 9, 7, 5, 15 };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  	unsigned cfg;
f0968e3f7   Krzysztof Helt   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   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
  
  	return INVALID_IRQ;
  }
1da177e4c   Linus Torvalds   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   Bill Pemberton   ALSA: isa: remove...
668
  static int detect_sscape(struct soundscape *s, long wss_io)
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: dro...
687
  	if (d == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  		s->ic_type = IC_ODIE;
453e37b37   Krzysztof Helt   ALSA: sscape: dro...
689
  	else if ((d & 0x60) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
  		s->ic_type = IC_OPUS;
453e37b37   Krzysztof Helt   ALSA: sscape: dro...
691
  	else
1da177e4c   Linus Torvalds   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   Krzysztof Helt   [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   Linus Torvalds   Linux-2.6.12-rc2
705
  		goto _done;
f0968e3f7   Krzysztof Helt   ALSA: sscape: add...
706
707
  	if (s->ic_type == IC_OPUS)
  		activate_ad1845_unsafe(s->io_base);
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
708
709
  
  	if (s->type == SSCAPE_VIVO)
453e37b37   Krzysztof Helt   ALSA: sscape: dro...
710
  		wss_io += 4;
f0968e3f7   Krzysztof Helt   ALSA: sscape: add...
711

6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
712
  	d  = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
f0968e3f7   Krzysztof Helt   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   Krzysztof Helt   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   Krzysztof Helt   ALSA: sscape: cod...
735
  	d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
f0968e3f7   Krzysztof Helt   ALSA: sscape: add...
736
  	sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
737
738
  	/* wait for WSS codec */
  	for (d = 0; d < 500; d++) {
453e37b37   Krzysztof Helt   ALSA: sscape: dro...
739
  		if ((inb(wss_io) & 0x80) == 0)
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
740
741
742
743
744
  			break;
  		spin_unlock_irqrestore(&s->lock, flags);
  		msleep(1);
  		spin_lock_irqsave(&s->lock, flags);
  	}
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
745

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
749
  	/*
  	 * SoundScape successfully detected!
  	 */
  	retval = 1;
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
750
  _done:
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
761
  static int mpu401_open(struct snd_mpu401 *mpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  	if (!verify_mpu401(mpu)) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
764
765
766
767
  		snd_printk(KERN_ERR "sscape: MIDI disabled, "
  				    "please load firmware
  ");
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  	}
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
769
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
  }
  
  /*
f5d0f820f   Liang Wang   ALSA: isa: fix sp...
773
   * Initialise an MPU-401 subdevice for MIDI support on the SoundScape.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
   */
1bff292e9   Bill Pemberton   ALSA: isa: remove...
775
776
  static int create_mpu401(struct snd_card *card, int devnum,
  			 unsigned long port, int irq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
  {
  	struct soundscape *sscape = get_card_soundscape(card);
be6245373   Takashi Iwai   [ALSA] Remove xxx...
779
  	struct snd_rawmidi *rawmidi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  	int err;
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
781
  	err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port,
dba8b4699   Clemens Ladisch   ALSA: mpu401: cle...
782
  				  MPU401_INFO_INTEGRATED, irq, &rawmidi);
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
783
784
  	if (err == 0) {
  		struct snd_mpu401 *mpu = rawmidi->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
  		mpu->open_input = mpu401_open;
  		mpu->open_output = mpu401_open;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  		mpu->private_data = sscape;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
790
791
792
793
794
795
796
  
  		initialise_mpu401(mpu);
  	}
  
  	return err;
  }
  
  
  /*
1da177e4c   Linus Torvalds   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   Bill Pemberton   ALSA: isa: remove...
802
803
  static int create_ad1845(struct snd_card *card, unsigned port,
  			 int irq, int dma1, int dma2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
  {
  	register struct soundscape *sscape = get_card_soundscape(card);
7779f75f0   Krzysztof Helt   ALSA: wss_lib: re...
806
  	struct snd_wss *chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	int err;
1cb0fdeba   Krzysztof Helt   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   Linus Torvalds   Linux-2.6.12-rc2
822

1cb0fdeba   Krzysztof Helt   ALSA: sscape: for...
823
  	case SSCAPE_VIVO:
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
824
  		port += 4;
1cb0fdeba   Krzysztof Helt   ALSA: sscape: for...
825
826
827
828
  		break;
  	default:
  		break;
  	}
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
829

7779f75f0   Krzysztof Helt   ALSA: wss_lib: re...
830
  	err = snd_wss_create(card, port, -1, irq, dma1, dma2,
1cb0fdeba   Krzysztof Helt   ALSA: sscape: for...
831
  			     codec_type, WSS_HWSHARE_DMA1, &chip);
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
832
  	if (!err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  		unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834

ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
835
  		if (sscape->type != SSCAPE_VIVO) {
ec1e79493   Krzysztof Helt   [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   Krzysztof Helt   ALSA: wss_lib: re...
841
  			snd_wss_mce_up(chip);
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
842
  			spin_lock_irqsave(&chip->reg_lock, flags);
199f79787   Krzysztof Helt   ALSA: wss-lib: mo...
843
  			snd_wss_out(chip, AD1845_CLOCK, 0x20);
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
844
  			spin_unlock_irqrestore(&chip->reg_lock, flags);
7779f75f0   Krzysztof Helt   ALSA: wss_lib: re...
845
  			snd_wss_mce_down(chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846

ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
847
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848

fa60c0656   Lars-Peter Clausen   ALSA: wss: Remove...
849
  		err = snd_wss_pcm(chip, 0);
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
850
851
852
853
  		if (err < 0) {
  			snd_printk(KERN_ERR "sscape: No PCM device "
  					    "for AD1845 chip
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
855
  			goto _error;
  		}
7779f75f0   Krzysztof Helt   ALSA: wss_lib: re...
856
  		err = snd_wss_mixer(chip);
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
857
858
859
860
  		if (err < 0) {
  			snd_printk(KERN_ERR "sscape: No mixer device "
  					    "for AD1845 chip
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
  			goto _error;
  		}
199f79787   Krzysztof Helt   ALSA: wss-lib: mo...
863
  		if (chip->hardware != WSS_HW_AD1848) {
fa60c0656   Lars-Peter Clausen   ALSA: wss: Remove...
864
  			err = snd_wss_timer(chip, 0);
199f79787   Krzysztof Helt   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   Linus Torvalds   Linux-2.6.12-rc2
871
  		}
ec1e79493   Krzysztof Helt   [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   Krzysztof Helt   [ALSA] sscape: su...
881
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
  		sscape->chip = chip;
  	}
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
884
  _error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
  	return err;
  }
1da177e4c   Linus Torvalds   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   Bill Pemberton   ALSA: isa: remove...
891
  static int create_sscape(int dev, struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  {
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
893
894
  	struct soundscape *sscape = get_card_soundscape(card);
  	unsigned dma_cfg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
  	unsigned irq_cfg;
  	unsigned mpu_irq_cfg;
  	struct resource *io_res;
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
898
  	struct resource *wss_res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
  	unsigned long flags;
  	int err;
1cb0fdeba   Krzysztof Helt   ALSA: sscape: for...
901
  	int val;
f0968e3f7   Krzysztof Helt   ALSA: sscape: add...
902
  	const char *name;
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: dro...
908
  	io_res = request_region(port[dev], 8, "SoundScape");
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
909
  	if (!io_res) {
453e37b37   Krzysztof Helt   ALSA: sscape: dro...
910
911
912
  		snd_printk(KERN_ERR
  			   "sscape: can't grab port 0x%lx
  ", port[dev]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
  		return -EBUSY;
  	}
ec1e79493   Krzysztof Helt   [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   Linus Torvalds   Linux-2.6.12-rc2
926
927
  
  	/*
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
928
  	 * Grab one DMA channel ...
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
  	 */
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
930
931
  	err = request_dma(dma[dev], "SoundScape");
  	if (err < 0) {
277e926c9   Takashi Iwai   [ALSA] sscape - U...
932
933
  		snd_printk(KERN_ERR "sscape: can't grab DMA %d
  ", dma[dev]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
935
  		goto _release_region;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
  	spin_lock_init(&sscape->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
  	sscape->io_res = io_res;
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
938
  	sscape->wss_res = wss_res;
453e37b37   Krzysztof Helt   ALSA: sscape: dro...
939
  	sscape->io_base = port[dev];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940

453e37b37   Krzysztof Helt   ALSA: sscape: dro...
941
  	if (!detect_sscape(sscape, wss_port[dev])) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
942
943
944
  		printk(KERN_ERR "sscape: hardware not detected at 0x%x
  ",
  			sscape->io_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  		err = -ENODEV;
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
946
  		goto _release_dma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
  	}
f0968e3f7   Krzysztof Helt   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   Julia Lawall   ALSA: sound/isa/s...
977
978
  		err = -ENXIO;
  		goto _release_dma;
f0968e3f7   Krzysztof Helt   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   Krzysztof Helt   ALSA: sscape: rem...
983
984
  		snd_printk(KERN_ERR "sscape: Invalid IRQ %d
  ", mpu_irq[dev]);
38be95dd3   Julia Lawall   ALSA: sound/isa/s...
985
986
  		err = -ENXIO;
  		goto _release_dma;
f0968e3f7   Krzysztof Helt   ALSA: sscape: add...
987
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988

1da177e4c   Linus Torvalds   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   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: add...
1001
  	dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: add...
1004
  	mpu_irq_cfg |= mpu_irq_cfg << 2;
1cb0fdeba   Krzysztof Helt   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   Krzysztof Helt   ALSA: sscape: add...
1009
  	sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  	sscape_write_unsafe(sscape->io_base,
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1011
1012
  			    GA_CDCFG_REG, 0x09 | DMA_8BIT
  			    | (dma[dev] << 4) | (irq_cfg << 1));
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
1013
1014
1015
1016
  	/*
  	 * Enable the master IRQ ...
  	 */
  	sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80);
1da177e4c   Linus Torvalds   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   Krzysztof Helt   [ALSA] sscape: dr...
1024
1025
1026
  	err = create_ad1845(card, wss_port[dev], irq[dev],
  			    dma[dev], dma2[dev]);
  	if (err < 0) {
bcde1f8a8   Krzysztof Helt   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   Krzysztof Helt   [ALSA] sscape: dr...
1031
  		goto _release_dma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
  	}
acd471009   Krzysztof Helt   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   Linus Torvalds   Linux-2.6.12-rc2
1040
  #define MIDI_DEVNUM  0
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
1041
  	if (sscape->type != SSCAPE_VIVO) {
acd471009   Krzysztof Helt   ALSA: sscape: con...
1042
1043
1044
  		err = sscape_upload_bootblock(card);
  		if (err >= 0)
  			err = sscape_upload_microcode(card, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045

acd471009   Krzysztof Helt   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   Krzysztof Helt   ALSA: sscape: rem...
1050
  				snd_printk(KERN_ERR "sscape: Failed to create "
acd471009   Krzysztof Helt   ALSA: sscape: con...
1051
1052
1053
1054
1055
1056
1057
  						"MPU-401 device at 0x%lx
  ",
  						port[dev]);
  				goto _release_dma;
  			}
  
  			/*
acd471009   Krzysztof Helt   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   Krzysztof Helt   [ALSA] sscape: su...
1079
  	}
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
  
  	return 0;
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1090
  _release_dma:
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1091
  	free_dma(dma[dev]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092

4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1093
  _release_region:
ec1e79493   Krzysztof Helt   [ALSA] sscape: su...
1094
  	release_and_free_resource(wss_res);
b1d5776d8   Takashi Iwai   [ALSA] Remove vma...
1095
  	release_and_free_resource(io_res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
1097
1098
  
  	return err;
  }
1bff292e9   Bill Pemberton   ALSA: isa: remove...
1099
  static int snd_sscape_match(struct device *pdev, unsigned int i)
5e24c1c1c   Takashi Iwai   [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   Krzysztof Helt   ALSA: sscape: cod...
1111
1112
1113
  		       "sscape: insufficient parameters, "
  		       "need IO, IRQ, MPU-IRQ and DMA
  ");
5e24c1c1c   Takashi Iwai   [ALSA] Port the r...
1114
1115
1116
1117
1118
  		return 0;
  	}
  
  	return 1;
  }
1bff292e9   Bill Pemberton   ALSA: isa: remove...
1119
  static int snd_sscape_probe(struct device *pdev, unsigned int dev)
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1120
  {
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1121
  	struct snd_card *card;
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1122
  	struct soundscape *sscape;
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1123
  	int ret;
4323cc4d5   Takashi Iwai   ALSA: isa: Conver...
1124
1125
  	ret = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
  			   sizeof(struct soundscape), &card);
c95eadd2f   Takashi Iwai   ALSA: Convert to ...
1126
1127
  	if (ret < 0)
  		return ret;
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1128
1129
1130
  
  	sscape = get_card_soundscape(card);
  	sscape->type = SSCAPE;
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1131
  	dma[dev] &= 0x03;
acd471009   Krzysztof Helt   ALSA: sscape: con...
1132

4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1133
  	ret = create_sscape(dev, card);
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1134
  	if (ret < 0)
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1135
  		goto _release_card;
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
1136
1137
  	ret = snd_card_register(card);
  	if (ret < 0) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
1138
1139
  		snd_printk(KERN_ERR "sscape: Failed to register sound card
  ");
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1140
  		goto _release_card;
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1141
  	}
5e24c1c1c   Takashi Iwai   [ALSA] Port the r...
1142
  	dev_set_drvdata(pdev, card);
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1143
  	return 0;
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1144
1145
1146
1147
  
  _release_card:
  	snd_card_free(card);
  	return ret;
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1148
  }
1bff292e9   Bill Pemberton   ALSA: isa: remove...
1149
  static int snd_sscape_remove(struct device *devptr, unsigned int dev)
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1150
  {
5e24c1c1c   Takashi Iwai   [ALSA] Port the r...
1151
  	snd_card_free(dev_get_drvdata(devptr));
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1152
1153
  	return 0;
  }
83c51c0ab   Rene Herman   [ALSA] isa_bus de...
1154
  #define DEV_NAME "sscape"
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1155

5e24c1c1c   Takashi Iwai   [ALSA] Port the r...
1156
1157
  static struct isa_driver snd_sscape_driver = {
  	.match		= snd_sscape_match,
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1158
  	.probe		= snd_sscape_probe,
1bff292e9   Bill Pemberton   ALSA: isa: remove...
1159
  	.remove		= snd_sscape_remove,
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1160
1161
  	/* FIXME: suspend/resume */
  	.driver		= {
83c51c0ab   Rene Herman   [ALSA] isa_bus de...
1162
  		.name	= DEV_NAME
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1163
1164
  	},
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
  
  #ifdef CONFIG_PNP
1bff292e9   Bill Pemberton   ALSA: isa: remove...
1167
  static inline int get_next_autoindex(int i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
  {
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1169
  	while (i < SNDRV_CARDS && port[i] != SNDRV_AUTO_PORT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
  		++i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
  	return i;
  }
1bff292e9   Bill Pemberton   ALSA: isa: remove...
1173
1174
  static int sscape_pnp_detect(struct pnp_card_link *pcard,
  			     const struct pnp_card_device_id *pid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
  	static int idx = 0;
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1177
1178
  	struct pnp_dev *dev;
  	struct snd_card *card;
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1179
  	struct soundscape *sscape;
1da177e4c   Linus Torvalds   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   Krzysztof Helt   ALSA: sscape: cod...
1186
1187
  	idx = get_next_autoindex(idx);
  	if (idx >= SNDRV_CARDS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188
  		return -ENOSPC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
1192
  	 * Check that we still have room for another sound card ...
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
  	dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
1194
  	if (!dev)
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1195
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196

277e926c9   Takashi Iwai   [ALSA] sscape - U...
1197
1198
  	if (!pnp_is_active(dev)) {
  		if (pnp_activate_dev(dev) < 0) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
1199
1200
  			snd_printk(KERN_INFO "sscape: device is inactive
  ");
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1201
  			return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1202
1203
  		}
  	}
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1204
  	/*
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1205
1206
1207
  	 * Create a new ALSA sound card entry, in anticipation
  	 * of detecting our hardware ...
  	 */
4323cc4d5   Takashi Iwai   ALSA: isa: Conver...
1208
1209
1210
  	ret = snd_card_new(&pcard->card->dev,
  			   index[idx], id[idx], THIS_MODULE,
  			   sizeof(struct soundscape), &card);
c95eadd2f   Takashi Iwai   ALSA: Convert to ...
1211
1212
  	if (ret < 0)
  		return ret;
4996bca98   Krzysztof Helt   [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   Krzysztof Helt   [ALSA] sscape: dr...
1223
  	/*
277e926c9   Takashi Iwai   [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   Krzysztof Helt   [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   Takashi Iwai   [ALSA] sscape - U...
1237

4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1238
  	ret = create_sscape(idx, card);
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1239
  	if (ret < 0)
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1240
  		goto _release_card;
6fcfa3959   Krzysztof Helt   ALSA: sscape: cod...
1241
1242
  	ret = snd_card_register(card);
  	if (ret < 0) {
bcde1f8a8   Krzysztof Helt   ALSA: sscape: rem...
1243
1244
  		snd_printk(KERN_ERR "sscape: Failed to register sound card
  ");
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1245
  		goto _release_card;
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1246
1247
1248
1249
  	}
  
  	pnp_set_card_drvdata(pcard, card);
  	++idx;
4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1250
  	return 0;
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1251

4996bca98   Krzysztof Helt   [ALSA] sscape: dr...
1252
1253
  _release_card:
  	snd_card_free(card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254
1255
  	return ret;
  }
1bff292e9   Bill Pemberton   ALSA: isa: remove...
1256
  static void sscape_pnp_remove(struct pnp_card_link *pcard)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1257
  {
277e926c9   Takashi Iwai   [ALSA] sscape - U...
1258
  	snd_card_free(pnp_get_card_drvdata(pcard));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259
  	pnp_set_card_drvdata(pcard, NULL);
1da177e4c   Linus Torvalds   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   Bill Pemberton   ALSA: isa: remove...
1267
  	.remove = sscape_pnp_remove,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
1269
1270
  };
  
  #endif /* CONFIG_PNP */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
  static int __init sscape_init(void)
  {
609d76941   Rene Herman   [ALSA] Fix probe ...
1273
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274

609d76941   Rene Herman   [ALSA] Fix probe ...
1275
  	err = isa_register_driver(&snd_sscape_driver, SNDRV_CARDS);
59b1b34f4   Takashi Iwai   [ALSA] Fix compil...
1276
  #ifdef CONFIG_PNP
609d76941   Rene Herman   [ALSA] Fix probe ...
1277
1278
1279
1280
1281
  	if (!err)
  		isa_registered = 1;
  
  	err = pnp_register_card_driver(&sscape_pnpc_driver);
  	if (!err)
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1282
  		pnp_registered = 1;
609d76941   Rene Herman   [ALSA] Fix probe ...
1283
1284
1285
  
  	if (isa_registered)
  		err = 0;
59b1b34f4   Takashi Iwai   [ALSA] Fix compil...
1286
  #endif
609d76941   Rene Herman   [ALSA] Fix probe ...
1287
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
  }
5e24c1c1c   Takashi Iwai   [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   Rene Herman   [ALSA] Fix probe ...
1294
  	if (isa_registered)
5e24c1c1c   Takashi Iwai   [ALSA] Port the r...
1295
  #endif
609d76941   Rene Herman   [ALSA] Fix probe ...
1296
  		isa_unregister_driver(&snd_sscape_driver);
5e24c1c1c   Takashi Iwai   [ALSA] Port the r...
1297
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
1299
  module_init(sscape_init);
  module_exit(sscape_exit);