blob: c739374af20e547219d89a9ad6e2d4ad63fa3204 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Krzysztof Heltacd471002009-10-01 00:10:34 +02002 * Low-level ALSA driver for the ENSONIQ SoundScape
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Copyright (c) by Chris Rankin
4 *
5 * This driver was written in part using information obtained from
6 * the OSS/Free SoundScape driver, written by Hannu Savolainen.
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/init.h>
Takashi Iwai277e9262005-11-17 17:13:12 +010025#include <linux/err.h>
Takashi Iwai5e24c1c2007-02-22 12:50:54 +010026#include <linux/isa.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/delay.h>
Krzysztof Heltacd471002009-10-01 00:10:34 +020028#include <linux/firmware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/pnp.h>
30#include <linux/spinlock.h>
31#include <linux/moduleparam.h>
32#include <asm/dma.h>
33#include <sound/core.h>
Krzysztof Helt61ef19d2008-07-31 21:02:42 +020034#include <sound/wss.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <sound/mpu401.h>
36#include <sound/initval.h>
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39MODULE_AUTHOR("Chris Rankin");
Krzysztof Heltacd471002009-10-01 00:10:34 +020040MODULE_DESCRIPTION("ENSONIQ SoundScape driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -070041MODULE_LICENSE("GPL");
Krzysztof Heltacd471002009-10-01 00:10:34 +020042MODULE_FIRMWARE("sndscape.co0");
43MODULE_FIRMWARE("sndscape.co1");
44MODULE_FIRMWARE("sndscape.co2");
45MODULE_FIRMWARE("sndscape.co3");
46MODULE_FIRMWARE("sndscape.co4");
47MODULE_FIRMWARE("scope.cod");
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX;
50static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR;
Krzysztof Helt4996bca2007-09-17 16:23:13 +020051static long port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
52static long wss_port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
54static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
55static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA;
Krzysztof Helt4996bca2007-09-17 16:23:13 +020056static int dma2[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58module_param_array(index, int, NULL, 0444);
59MODULE_PARM_DESC(index, "Index number for SoundScape soundcard");
60
61module_param_array(id, charp, NULL, 0444);
62MODULE_PARM_DESC(id, "Description for SoundScape card");
63
64module_param_array(port, long, NULL, 0444);
65MODULE_PARM_DESC(port, "Port # for SoundScape driver.");
66
Krzysztof Helt4996bca2007-09-17 16:23:13 +020067module_param_array(wss_port, long, NULL, 0444);
68MODULE_PARM_DESC(wss_port, "WSS Port # for SoundScape driver.");
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070module_param_array(irq, int, NULL, 0444);
71MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver.");
72
73module_param_array(mpu_irq, int, NULL, 0444);
74MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # for SoundScape driver.");
75
76module_param_array(dma, int, NULL, 0444);
77MODULE_PARM_DESC(dma, "DMA # for SoundScape driver.");
Clemens Ladischf7a92752005-12-07 09:13:42 +010078
Krzysztof Helt4996bca2007-09-17 16:23:13 +020079module_param_array(dma2, int, NULL, 0444);
80MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver.");
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082#ifdef CONFIG_PNP
Rene Herman609d7692007-05-15 11:42:56 +020083static int isa_registered;
Takashi Iwai59b1b342006-01-04 15:06:44 +010084static int pnp_registered;
Rene Herman609d7692007-05-15 11:42:56 +020085
Linus Torvalds1da177e2005-04-16 15:20:36 -070086static struct pnp_card_device_id sscape_pnpids[] = {
Krzysztof Helt4996bca2007-09-17 16:23:13 +020087 { .id = "ENS3081", .devs = { { "ENS0000" } } }, /* Soundscape PnP */
88 { .id = "ENS4081", .devs = { { "ENS1011" } } }, /* VIVO90 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 { .id = "" } /* end */
90};
91
92MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
93#endif
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#define HOST_CTRL_IO(i) ((i) + 2)
97#define HOST_DATA_IO(i) ((i) + 3)
98#define ODIE_ADDR_IO(i) ((i) + 4)
99#define ODIE_DATA_IO(i) ((i) + 5)
100#define CODEC_IO(i) ((i) + 8)
101
102#define IC_ODIE 1
103#define IC_OPUS 2
104
105#define RX_READY 0x01
106#define TX_READY 0x02
107
108#define CMD_ACK 0x80
109#define CMD_SET_MIDI_VOL 0x84
110#define CMD_GET_MIDI_VOL 0x85
111#define CMD_XXX_MIDI_VOL 0x86
112#define CMD_SET_EXTMIDI 0x8a
113#define CMD_GET_EXTMIDI 0x8b
114#define CMD_SET_MT32 0x8c
115#define CMD_GET_MT32 0x8d
116
117enum GA_REG {
118 GA_INTSTAT_REG = 0,
119 GA_INTENA_REG,
120 GA_DMAA_REG,
121 GA_DMAB_REG,
122 GA_INTCFG_REG,
123 GA_DMACFG_REG,
124 GA_CDCFG_REG,
125 GA_SMCFGA_REG,
126 GA_SMCFGB_REG,
127 GA_HMCTL_REG
128};
129
130#define DMA_8BIT 0x80
131
132
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200133enum card_type {
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200134 MEDIA_FX, /* Sequoia S-1000 */
135 SSCAPE, /* Sequoia S-2000 */
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200136 SSCAPE_PNP,
137 SSCAPE_VIVO,
138};
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140struct soundscape {
141 spinlock_t lock;
142 unsigned io_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 int ic_type;
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200144 enum card_type type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 struct resource *io_res;
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200146 struct resource *wss_res;
Krzysztof Helt7779f752008-07-31 21:03:41 +0200147 struct snd_wss *chip;
Takashi Iwaibe624532005-11-17 14:42:05 +0100148 struct snd_mpu401 *mpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 unsigned char midi_vol;
151};
152
153#define INVALID_IRQ ((unsigned)-1)
154
155
Takashi Iwaibe624532005-11-17 14:42:05 +0100156static inline struct soundscape *get_card_soundscape(struct snd_card *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
158 return (struct soundscape *) (c->private_data);
159}
160
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161/*
162 * Allocates some kernel memory that we can use for DMA.
163 * I think this means that the memory has to map to
164 * contiguous pages of physical memory.
165 */
166static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size)
167{
168 if (buf) {
169 if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(),
170 size, buf) < 0) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200171 snd_printk(KERN_ERR "sscape: Failed to allocate "
172 "%lu bytes for DMA\n",
173 size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 return NULL;
175 }
176 }
177
178 return buf;
179}
180
181/*
182 * Release the DMA-able kernel memory ...
183 */
184static void free_dmabuf(struct snd_dma_buffer *buf)
185{
186 if (buf && buf->area)
187 snd_dma_free_pages(buf);
188}
189
190
191/*
192 * This function writes to the SoundScape's control registers,
193 * but doesn't do any locking. It's up to the caller to do that.
194 * This is why this function is "unsafe" ...
195 */
196static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val)
197{
198 outb(reg, ODIE_ADDR_IO(io_base));
199 outb(val, ODIE_DATA_IO(io_base));
200}
201
202/*
203 * Write to the SoundScape's control registers, and do the
204 * necessary locking ...
205 */
206static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val)
207{
208 unsigned long flags;
209
210 spin_lock_irqsave(&s->lock, flags);
211 sscape_write_unsafe(s->io_base, reg, val);
212 spin_unlock_irqrestore(&s->lock, flags);
213}
214
215/*
216 * Read from the SoundScape's control registers, but leave any
217 * locking to the caller. This is why the function is "unsafe" ...
218 */
219static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg)
220{
221 outb(reg, ODIE_ADDR_IO(io_base));
222 return inb(ODIE_DATA_IO(io_base));
223}
224
225/*
226 * Puts the SoundScape into "host" mode, as compared to "MIDI" mode
227 */
228static inline void set_host_mode_unsafe(unsigned io_base)
229{
230 outb(0x0, HOST_CTRL_IO(io_base));
231}
232
233/*
234 * Puts the SoundScape into "MIDI" mode, as compared to "host" mode
235 */
236static inline void set_midi_mode_unsafe(unsigned io_base)
237{
238 outb(0x3, HOST_CTRL_IO(io_base));
239}
240
241/*
242 * Read the SoundScape's host-mode control register, but leave
243 * any locking issues to the caller ...
244 */
245static inline int host_read_unsafe(unsigned io_base)
246{
247 int data = -1;
248 if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) {
249 data = inb(HOST_DATA_IO(io_base));
250 }
251
252 return data;
253}
254
255/*
256 * Read the SoundScape's host-mode control register, performing
257 * a limited amount of busy-waiting if the register isn't ready.
258 * Also leaves all locking-issues to the caller ...
259 */
260static int host_read_ctrl_unsafe(unsigned io_base, unsigned timeout)
261{
262 int data;
263
264 while (((data = host_read_unsafe(io_base)) < 0) && (timeout != 0)) {
265 udelay(100);
266 --timeout;
267 } /* while */
268
269 return data;
270}
271
272/*
273 * Write to the SoundScape's host-mode control registers, but
274 * leave any locking issues to the caller ...
275 */
276static inline int host_write_unsafe(unsigned io_base, unsigned char data)
277{
278 if ((inb(HOST_CTRL_IO(io_base)) & TX_READY) != 0) {
279 outb(data, HOST_DATA_IO(io_base));
280 return 1;
281 }
282
283 return 0;
284}
285
286/*
287 * Write to the SoundScape's host-mode control registers, performing
288 * a limited amount of busy-waiting if the register isn't ready.
289 * Also leaves all locking-issues to the caller ...
290 */
291static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
292 unsigned timeout)
293{
294 int err;
295
296 while (!(err = host_write_unsafe(io_base, data)) && (timeout != 0)) {
297 udelay(100);
298 --timeout;
299 } /* while */
300
301 return err;
302}
303
304
305/*
306 * Check that the MIDI subsystem is operational. If it isn't,
307 * then we will hang the computer if we try to use it ...
308 *
309 * NOTE: This check is based upon observation, not documentation.
310 */
Takashi Iwaibe624532005-11-17 14:42:05 +0100311static inline int verify_mpu401(const struct snd_mpu401 * mpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Krzysztof Heltc9864fd2009-01-21 08:19:27 +0100313 return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
315
316/*
317 * This is apparently the standard way to initailise an MPU-401
318 */
Takashi Iwaibe624532005-11-17 14:42:05 +0100319static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
Krzysztof Heltc9864fd2009-01-21 08:19:27 +0100321 outb(0, MPU401D(mpu));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
324/*
325 * Tell the SoundScape to activate the AD1845 chip (I think).
326 * The AD1845 detection fails if we *don't* do this, so I
327 * think that this is a good idea ...
328 */
329static inline void activate_ad1845_unsafe(unsigned io_base)
330{
331 sscape_write_unsafe(io_base, GA_HMCTL_REG, (sscape_read_unsafe(io_base, GA_HMCTL_REG) & 0xcf) | 0x10);
332 sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80);
333}
334
335/*
336 * Do the necessary ALSA-level cleanup to deallocate our driver ...
337 */
Takashi Iwaibe624532005-11-17 14:42:05 +0100338static void soundscape_free(struct snd_card *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200340 struct soundscape *sscape = get_card_soundscape(c);
Takashi Iwaib1d57762005-10-10 11:56:31 +0200341 release_and_free_resource(sscape->io_res);
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200342 release_and_free_resource(sscape->wss_res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 free_dma(sscape->chip->dma1);
344}
345
346/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 * Tell the SoundScape to begin a DMA tranfer using the given channel.
348 * All locking issues are left to the caller.
349 */
350static inline void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
351{
352 sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01);
353 sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe);
354}
355
356/*
357 * Wait for a DMA transfer to complete. This is a "limited busy-wait",
358 * and all locking issues are left to the caller.
359 */
360static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout)
361{
362 while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) {
363 udelay(100);
364 --timeout;
365 } /* while */
366
367 return (sscape_read_unsafe(io_base, reg) & 0x01);
368}
369
370/*
371 * Wait for the On-Board Processor to return its start-up
372 * acknowledgement sequence. This wait is too long for
373 * us to perform "busy-waiting", and so we must sleep.
374 * This in turn means that we must not be holding any
375 * spinlocks when we call this function.
376 */
377static int obp_startup_ack(struct soundscape *s, unsigned timeout)
378{
Krzysztof Helt554b91e2009-01-12 21:25:04 +0100379 unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
380
381 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 unsigned long flags;
Krzysztof Heltacd471002009-10-01 00:10:34 +0200383 int x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 spin_lock_irqsave(&s->lock, flags);
Krzysztof Heltacd471002009-10-01 00:10:34 +0200386 x = host_read_unsafe(s->io_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 spin_unlock_irqrestore(&s->lock, flags);
Krzysztof Heltacd471002009-10-01 00:10:34 +0200388 if (x == 0xfe || x == 0xff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return 1;
390
Krzysztof Helt554b91e2009-01-12 21:25:04 +0100391 msleep(10);
392 } while (time_before(jiffies, end_time));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394 return 0;
395}
396
397/*
398 * Wait for the host to return its start-up acknowledgement
399 * sequence. This wait is too long for us to perform
400 * "busy-waiting", and so we must sleep. This in turn means
401 * that we must not be holding any spinlocks when we call
402 * this function.
403 */
404static int host_startup_ack(struct soundscape *s, unsigned timeout)
405{
Krzysztof Helt554b91e2009-01-12 21:25:04 +0100406 unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
407
408 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 unsigned long flags;
Krzysztof Heltacd471002009-10-01 00:10:34 +0200410 int x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 spin_lock_irqsave(&s->lock, flags);
Krzysztof Heltacd471002009-10-01 00:10:34 +0200413 x = host_read_unsafe(s->io_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 spin_unlock_irqrestore(&s->lock, flags);
415 if (x == 0xfe)
416 return 1;
417
Krzysztof Helt554b91e2009-01-12 21:25:04 +0100418 msleep(10);
419 } while (time_before(jiffies, end_time));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 return 0;
422}
423
424/*
425 * Upload a byte-stream into the SoundScape using DMA channel A.
426 */
427static int upload_dma_data(struct soundscape *s,
Krzysztof Heltacd471002009-10-01 00:10:34 +0200428 const unsigned char *data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 size_t size)
430{
431 unsigned long flags;
432 struct snd_dma_buffer dma;
433 int ret;
434
Krzysztof Heltacd471002009-10-01 00:10:34 +0200435 if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 return -ENOMEM;
437
438 spin_lock_irqsave(&s->lock, flags);
439
440 /*
441 * Reset the board ...
442 */
443 sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f);
444
445 /*
446 * Enable the DMA channels and configure them ...
447 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT);
449 sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20);
450
451 /*
452 * Take the board out of reset ...
453 */
454 sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80);
455
456 /*
Krzysztof Heltacd471002009-10-01 00:10:34 +0200457 * Upload the firmware to the SoundScape
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 * board through the DMA channel ...
459 */
460 while (size != 0) {
461 unsigned long len;
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 len = min(size, dma.bytes);
Krzysztof Heltacd471002009-10-01 00:10:34 +0200464 memcpy(dma.area, data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 data += len;
466 size -= len;
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE);
469 sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG);
470 if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) {
471 /*
472 * Don't forget to release this spinlock we're holding ...
473 */
474 spin_unlock_irqrestore(&s->lock, flags);
475
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200476 snd_printk(KERN_ERR
477 "sscape: DMA upload has timed out\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 ret = -EAGAIN;
479 goto _release_dma;
480 }
481 } /* while */
482
483 set_host_mode_unsafe(s->io_base);
Krzysztof Heltacd471002009-10-01 00:10:34 +0200484 outb(0x0, s->io_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 /*
487 * Boot the board ... (I think)
488 */
489 sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40);
490 spin_unlock_irqrestore(&s->lock, flags);
491
492 /*
493 * If all has gone well, then the board should acknowledge
494 * the new upload and tell us that it has rebooted OK. We
495 * give it 5 seconds (max) ...
496 */
497 ret = 0;
Krzysztof Helt554b91e2009-01-12 21:25:04 +0100498 if (!obp_startup_ack(s, 5000)) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200499 snd_printk(KERN_ERR "sscape: No response "
500 "from on-board processor after upload\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 ret = -EAGAIN;
Krzysztof Helt554b91e2009-01-12 21:25:04 +0100502 } else if (!host_startup_ack(s, 5000)) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200503 snd_printk(KERN_ERR
504 "sscape: SoundScape failed to initialise\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ret = -EAGAIN;
506 }
507
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200508_release_dma:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 /*
510 * NOTE!!! We are NOT holding any spinlocks at this point !!!
511 */
Krzysztof Heltacd471002009-10-01 00:10:34 +0200512 sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 free_dmabuf(&dma);
514
515 return ret;
516}
517
518/*
519 * Upload the bootblock(?) into the SoundScape. The only
520 * purpose of this block of code seems to be to tell
521 * us which version of the microcode we should be using.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 */
Krzysztof Heltacd471002009-10-01 00:10:34 +0200523static int sscape_upload_bootblock(struct snd_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
Krzysztof Heltacd471002009-10-01 00:10:34 +0200525 struct soundscape *sscape = get_card_soundscape(card);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 unsigned long flags;
Krzysztof Heltacd471002009-10-01 00:10:34 +0200527 const struct firmware *init_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 int data = 0;
529 int ret;
530
Krzysztof Heltacd471002009-10-01 00:10:34 +0200531 ret = request_firmware(&init_fw, "scope.cod", card->dev);
532 if (ret < 0) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200533 snd_printk(KERN_ERR "sscape: Error loading scope.cod");
Krzysztof Heltacd471002009-10-01 00:10:34 +0200534 return ret;
535 }
536 ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
537
538 release_firmware(init_fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
540 spin_lock_irqsave(&sscape->lock, flags);
Krzysztof Heltacd471002009-10-01 00:10:34 +0200541 if (ret == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 data = host_read_ctrl_unsafe(sscape->io_base, 100);
Krzysztof Heltacd471002009-10-01 00:10:34 +0200543
544 if (data & 0x10)
545 sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f);
546
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 spin_unlock_irqrestore(&sscape->lock, flags);
548
Krzysztof Heltacd471002009-10-01 00:10:34 +0200549 data &= 0xf;
550 if (ret == 0 && data > 7) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200551 snd_printk(KERN_ERR
552 "sscape: timeout reading firmware version\n");
Krzysztof Heltacd471002009-10-01 00:10:34 +0200553 ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 }
555
Krzysztof Heltacd471002009-10-01 00:10:34 +0200556 return (ret == 0) ? data : ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557}
558
559/*
Krzysztof Heltacd471002009-10-01 00:10:34 +0200560 * Upload the microcode into the SoundScape.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 */
Krzysztof Heltacd471002009-10-01 00:10:34 +0200562static int sscape_upload_microcode(struct snd_card *card, int version)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
Krzysztof Heltacd471002009-10-01 00:10:34 +0200564 struct soundscape *sscape = get_card_soundscape(card);
565 const struct firmware *init_fw = NULL;
566 char name[14];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 int err;
568
Krzysztof Heltacd471002009-10-01 00:10:34 +0200569 snprintf(name, sizeof(name), "sndscape.co%d", version);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Krzysztof Heltacd471002009-10-01 00:10:34 +0200571 err = request_firmware(&init_fw, name, card->dev);
572 if (err < 0) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200573 snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d",
574 version);
Krzysztof Heltacd471002009-10-01 00:10:34 +0200575 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 }
Krzysztof Heltacd471002009-10-01 00:10:34 +0200577 err = upload_dma_data(sscape, init_fw->data, init_fw->size);
578 if (err == 0)
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200579 snd_printk(KERN_INFO "sscape: MIDI firmware loaded %d KBs\n",
Krzysztof Heltacd471002009-10-01 00:10:34 +0200580 init_fw->size >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Krzysztof Heltacd471002009-10-01 00:10:34 +0200582 release_firmware(init_fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
584 return err;
585}
586
587/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 * Mixer control for the SoundScape's MIDI device.
589 */
Takashi Iwaibe624532005-11-17 14:42:05 +0100590static int sscape_midi_info(struct snd_kcontrol *ctl,
591 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
593 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
594 uinfo->count = 1;
595 uinfo->value.integer.min = 0;
596 uinfo->value.integer.max = 127;
597 return 0;
598}
599
Takashi Iwaibe624532005-11-17 14:42:05 +0100600static int sscape_midi_get(struct snd_kcontrol *kctl,
601 struct snd_ctl_elem_value *uctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
Krzysztof Helt7779f752008-07-31 21:03:41 +0200603 struct snd_wss *chip = snd_kcontrol_chip(kctl);
Takashi Iwaibe624532005-11-17 14:42:05 +0100604 struct snd_card *card = chip->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 register struct soundscape *s = get_card_soundscape(card);
606 unsigned long flags;
607
608 spin_lock_irqsave(&s->lock, flags);
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100609 uctl->value.integer.value[0] = s->midi_vol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 spin_unlock_irqrestore(&s->lock, flags);
611 return 0;
612}
613
Takashi Iwaibe624532005-11-17 14:42:05 +0100614static int sscape_midi_put(struct snd_kcontrol *kctl,
615 struct snd_ctl_elem_value *uctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
Krzysztof Helt7779f752008-07-31 21:03:41 +0200617 struct snd_wss *chip = snd_kcontrol_chip(kctl);
Takashi Iwaibe624532005-11-17 14:42:05 +0100618 struct snd_card *card = chip->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 register struct soundscape *s = get_card_soundscape(card);
620 unsigned long flags;
621 int change;
622
623 spin_lock_irqsave(&s->lock, flags);
624
625 /*
626 * We need to put the board into HOST mode before we
627 * can send any volume-changing HOST commands ...
628 */
629 set_host_mode_unsafe(s->io_base);
630
631 /*
632 * To successfully change the MIDI volume setting, you seem to
633 * have to write a volume command, write the new volume value,
634 * and then perform another volume-related command. Perhaps the
635 * first command is an "open" and the second command is a "close"?
636 */
637 if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) {
638 change = 0;
639 goto __skip_change;
640 }
641 change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
642 && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100)
643 && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100));
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100644 s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 __skip_change:
646
647 /*
648 * Take the board out of HOST mode and back into MIDI mode ...
649 */
650 set_midi_mode_unsafe(s->io_base);
651
652 spin_unlock_irqrestore(&s->lock, flags);
653 return change;
654}
655
Takashi Iwaibe624532005-11-17 14:42:05 +0100656static struct snd_kcontrol_new midi_mixer_ctl = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
658 .name = "MIDI",
659 .info = sscape_midi_info,
660 .get = sscape_midi_get,
661 .put = sscape_midi_put
662};
663
664/*
665 * The SoundScape can use two IRQs from a possible set of four.
666 * These IRQs are encoded as bit patterns so that they can be
667 * written to the control registers.
668 */
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200669static unsigned __devinit get_irq_config(int sscape_type, int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 static const int valid_irq[] = { 9, 5, 7, 10 };
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200672 static const int old_irq[] = { 9, 7, 5, 15 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 unsigned cfg;
674
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200675 if (sscape_type == MEDIA_FX) {
676 for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg)
677 if (irq == old_irq[cfg])
678 return cfg;
679 } else {
680 for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg)
681 if (irq == valid_irq[cfg])
682 return cfg;
683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 return INVALID_IRQ;
686}
687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688/*
689 * Perform certain arcane port-checks to see whether there
690 * is a SoundScape board lurking behind the given ports.
691 */
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100692static int __devinit detect_sscape(struct soundscape *s, long wss_io)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
694 unsigned long flags;
695 unsigned d;
696 int retval = 0;
697
698 spin_lock_irqsave(&s->lock, flags);
699
700 /*
701 * The following code is lifted from the original OSS driver,
702 * and as I don't have a datasheet I cannot really comment
703 * on what it is doing...
704 */
705 if ((inb(HOST_CTRL_IO(s->io_base)) & 0x78) != 0)
706 goto _done;
707
708 d = inb(ODIE_ADDR_IO(s->io_base)) & 0xf0;
709 if ((d & 0x80) != 0)
710 goto _done;
711
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100712 if (d == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 s->ic_type = IC_ODIE;
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100714 else if ((d & 0x60) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 s->ic_type = IC_OPUS;
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100716 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 goto _done;
718
719 outb(0xfa, ODIE_ADDR_IO(s->io_base));
720 if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0a)
721 goto _done;
722
723 outb(0xfe, ODIE_ADDR_IO(s->io_base));
724 if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0e)
725 goto _done;
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200726
727 outb(0xfe, ODIE_ADDR_IO(s->io_base));
728 d = inb(ODIE_DATA_IO(s->io_base));
729 if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 goto _done;
731
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200732 if (s->ic_type == IC_OPUS)
733 activate_ad1845_unsafe(s->io_base);
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200734
735 if (s->type == SSCAPE_VIVO)
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100736 wss_io += 4;
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200737
738 d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
739 sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
740
741 /* wait for WSS codec */
742 for (d = 0; d < 500; d++) {
743 if ((inb(wss_io) & 0x80) == 0)
744 break;
745 spin_unlock_irqrestore(&s->lock, flags);
746 msleep(1);
747 spin_lock_irqsave(&s->lock, flags);
748 }
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200749
750 if ((inb(wss_io) & 0x80) != 0)
751 goto _done;
752
753 if (inb(wss_io + 2) == 0xff)
754 goto _done;
755
756 d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
757 sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d);
758
759 if ((inb(wss_io) & 0x80) != 0)
760 s->type = MEDIA_FX;
761
762 d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
763 sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200764 /* wait for WSS codec */
765 for (d = 0; d < 500; d++) {
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100766 if ((inb(wss_io) & 0x80) == 0)
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200767 break;
768 spin_unlock_irqrestore(&s->lock, flags);
769 msleep(1);
770 spin_lock_irqsave(&s->lock, flags);
771 }
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 /*
774 * SoundScape successfully detected!
775 */
776 retval = 1;
777
778 _done:
779 spin_unlock_irqrestore(&s->lock, flags);
780 return retval;
781}
782
783/*
784 * ALSA callback function, called when attempting to open the MIDI device.
785 * Check that the MIDI firmware has been loaded, because we don't want
786 * to crash the machine. Also check that someone isn't using the hardware
787 * IOCTL device.
788 */
Takashi Iwaibe624532005-11-17 14:42:05 +0100789static int mpu401_open(struct snd_mpu401 * mpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 if (!verify_mpu401(mpu)) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200792 snd_printk(KERN_ERR "sscape: MIDI disabled, "
793 "please load firmware\n");
794 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 }
796
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200797 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798}
799
800/*
801 * Initialse an MPU-401 subdevice for MIDI support on the SoundScape.
802 */
Takashi Iwaibe624532005-11-17 14:42:05 +0100803static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned long port, int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
805 struct soundscape *sscape = get_card_soundscape(card);
Takashi Iwaibe624532005-11-17 14:42:05 +0100806 struct snd_rawmidi *rawmidi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 int err;
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if ((err = snd_mpu401_uart_new(card, devnum,
810 MPU401_HW_MPU401,
Takashi Iwai302e4c22006-05-23 13:24:30 +0200811 port, MPU401_INFO_INTEGRATED,
Thomas Gleixner65ca68b2006-07-01 19:29:46 -0700812 irq, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 &rawmidi)) == 0) {
Takashi Iwaibe624532005-11-17 14:42:05 +0100814 struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 mpu->open_input = mpu401_open;
816 mpu->open_output = mpu401_open;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 mpu->private_data = sscape;
818 sscape->mpu = mpu;
819
820 initialise_mpu401(mpu);
821 }
822
823 return err;
824}
825
826
827/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 * Create an AD1845 PCM subdevice on the SoundScape. The AD1845
829 * is very much like a CS4231, with a few extra bits. We will
830 * try to support at least some of the extra bits by overriding
831 * some of the CS4231 callback.
832 */
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200833static int __devinit create_ad1845(struct snd_card *card, unsigned port,
834 int irq, int dma1, int dma2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835{
836 register struct soundscape *sscape = get_card_soundscape(card);
Krzysztof Helt7779f752008-07-31 21:03:41 +0200837 struct snd_wss *chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 int err;
839
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200840 if (sscape->type == SSCAPE_VIVO)
841 port += 4;
842
Krzysztof Helt7779f752008-07-31 21:03:41 +0200843 err = snd_wss_create(card, port, -1, irq, dma1, dma2,
844 WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip);
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200845 if (!err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 unsigned long flags;
Takashi Iwaibe624532005-11-17 14:42:05 +0100847 struct snd_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849/*
850 * It turns out that the PLAYBACK_ENABLE bit is set
851 * by the lowlevel driver ...
852 *
853#define AD1845_IFACE_CONFIG \
854 (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)
Krzysztof Helt7779f752008-07-31 21:03:41 +0200855 snd_wss_mce_up(chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 spin_lock_irqsave(&chip->reg_lock, flags);
Krzysztof Helt7779f752008-07-31 21:03:41 +0200857 snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 spin_unlock_irqrestore(&chip->reg_lock, flags);
Krzysztof Helt7779f752008-07-31 21:03:41 +0200859 snd_wss_mce_down(chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 */
861
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200862 if (sscape->type != SSCAPE_VIVO) {
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200863 /*
864 * The input clock frequency on the SoundScape must
865 * be 14.31818 MHz, because we must set this register
866 * to get the playback to sound correct ...
867 */
Krzysztof Helt7779f752008-07-31 21:03:41 +0200868 snd_wss_mce_up(chip);
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200869 spin_lock_irqsave(&chip->reg_lock, flags);
Krzysztof Helt199f7972009-01-09 23:10:52 +0100870 snd_wss_out(chip, AD1845_CLOCK, 0x20);
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200871 spin_unlock_irqrestore(&chip->reg_lock, flags);
Krzysztof Helt7779f752008-07-31 21:03:41 +0200872 snd_wss_mce_down(chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Krzysztof Helt7779f752008-07-31 21:03:41 +0200876 err = snd_wss_pcm(chip, 0, &pcm);
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200877 if (err < 0) {
878 snd_printk(KERN_ERR "sscape: No PCM device "
879 "for AD1845 chip\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 goto _error;
881 }
882
Krzysztof Helt7779f752008-07-31 21:03:41 +0200883 err = snd_wss_mixer(chip);
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200884 if (err < 0) {
885 snd_printk(KERN_ERR "sscape: No mixer device "
886 "for AD1845 chip\n");
887 goto _error;
888 }
Krzysztof Helt199f7972009-01-09 23:10:52 +0100889 if (chip->hardware != WSS_HW_AD1848) {
890 err = snd_wss_timer(chip, 0, NULL);
891 if (err < 0) {
892 snd_printk(KERN_ERR "sscape: No timer device "
893 "for AD1845 chip\n");
894 goto _error;
895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 }
897
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200898 if (sscape->type != SSCAPE_VIVO) {
899 err = snd_ctl_add(card,
900 snd_ctl_new1(&midi_mixer_ctl, chip));
901 if (err < 0) {
902 snd_printk(KERN_ERR "sscape: Could not create "
903 "MIDI mixer control\n");
904 goto _error;
905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 }
907
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 sscape->chip = chip;
909 }
910
911 _error:
912 return err;
913}
914
915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916/*
917 * Create an ALSA soundcard entry for the SoundScape, using
918 * the given list of port, IRQ and DMA resources.
919 */
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200920static int __devinit create_sscape(int dev, struct snd_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200922 struct soundscape *sscape = get_card_soundscape(card);
923 unsigned dma_cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 unsigned irq_cfg;
925 unsigned mpu_irq_cfg;
926 struct resource *io_res;
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200927 struct resource *wss_res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 unsigned long flags;
929 int err;
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200930 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 /*
933 * Grab IO ports that we will need to probe so that we
934 * can detect and control this hardware ...
935 */
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100936 io_res = request_region(port[dev], 8, "SoundScape");
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200937 if (!io_res) {
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100938 snd_printk(KERN_ERR
939 "sscape: can't grab port 0x%lx\n", port[dev]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 return -EBUSY;
941 }
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200942 wss_res = NULL;
943 if (sscape->type == SSCAPE_VIVO) {
944 wss_res = request_region(wss_port[dev], 4, "SoundScape");
945 if (!wss_res) {
946 snd_printk(KERN_ERR "sscape: can't grab port 0x%lx\n",
947 wss_port[dev]);
948 err = -EBUSY;
949 goto _release_region;
950 }
951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 /*
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200954 * Grab one DMA channel ...
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 */
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200956 err = request_dma(dma[dev], "SoundScape");
957 if (err < 0) {
Takashi Iwai277e9262005-11-17 17:13:12 +0100958 snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", dma[dev]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 goto _release_region;
960 }
961
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 spin_lock_init(&sscape->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 sscape->io_res = io_res;
Krzysztof Heltec1e7942007-09-17 17:57:37 +0200964 sscape->wss_res = wss_res;
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100965 sscape->io_base = port[dev];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Krzysztof Helt453e37b2009-02-04 17:41:32 +0100967 if (!detect_sscape(sscape, wss_port[dev])) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +0200968 printk(KERN_ERR "sscape: hardware not detected at 0x%x\n",
969 sscape->io_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 err = -ENODEV;
Krzysztof Helt4996bca2007-09-17 16:23:13 +0200971 goto _release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 }
973
Krzysztof Heltf0968e32009-09-27 23:08:40 +0200974 switch (sscape->type) {
975 case MEDIA_FX:
976 name = "MediaFX/SoundFX";
977 break;
978 case SSCAPE:
979 name = "Soundscape";
980 break;
981 case SSCAPE_PNP:
982 name = "Soundscape PnP";
983 break;
984 case SSCAPE_VIVO:
985 name = "Soundscape VIVO";
986 break;
987 default:
988 name = "unknown Soundscape";
989 break;
990 }
991
992 printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n",
993 name, sscape->io_base, irq[dev], dma[dev]);
994
995 /*
996 * Check that the user didn't pass us garbage data ...
997 */
998 irq_cfg = get_irq_config(sscape->type, irq[dev]);
999 if (irq_cfg == INVALID_IRQ) {
1000 snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
1001 return -ENXIO;
1002 }
1003
1004 mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]);
1005 if (mpu_irq_cfg == INVALID_IRQ) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +02001006 snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
Krzysztof Heltf0968e32009-09-27 23:08:40 +02001007 return -ENXIO;
1008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 /*
1011 * Tell the on-board devices where their resources are (I think -
1012 * I can't be sure without a datasheet ... So many magic values!)
1013 */
1014 spin_lock_irqsave(&sscape->lock, flags);
1015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */
1017 sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
1018 sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
1019
1020 /*
1021 * Enable and configure the DMA channels ...
1022 */
1023 sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
Krzysztof Heltf0968e32009-09-27 23:08:40 +02001024 dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
1026 sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
1027
Krzysztof Heltf0968e32009-09-27 23:08:40 +02001028 mpu_irq_cfg |= mpu_irq_cfg << 2;
1029 sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 sscape_write_unsafe(sscape->io_base,
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001031 GA_CDCFG_REG, 0x09 | DMA_8BIT
1032 | (dma[dev] << 4) | (irq_cfg << 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 spin_unlock_irqrestore(&sscape->lock, flags);
1035
1036 /*
1037 * We have now enabled the codec chip, and so we should
1038 * detect the AD1845 device ...
1039 */
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001040 err = create_ad1845(card, wss_port[dev], irq[dev],
1041 dma[dev], dma2[dev]);
1042 if (err < 0) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +02001043 snd_printk(KERN_ERR
1044 "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
1045 wss_port[dev], irq[dev]);
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001046 goto _release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
Krzysztof Heltacd471002009-10-01 00:10:34 +02001048 strcpy(card->driver, "SoundScape");
1049 strcpy(card->shortname, name);
1050 snprintf(card->longname, sizeof(card->longname),
1051 "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
1052 name, sscape->chip->port, sscape->chip->irq,
1053 sscape->chip->dma1, sscape->chip->dma2);
1054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055#define MIDI_DEVNUM 0
Krzysztof Heltec1e7942007-09-17 17:57:37 +02001056 if (sscape->type != SSCAPE_VIVO) {
Krzysztof Heltacd471002009-10-01 00:10:34 +02001057 err = sscape_upload_bootblock(card);
1058 if (err >= 0)
1059 err = sscape_upload_microcode(card, err);
1060
1061 if (err == 0) {
1062 err = create_mpu401(card, MIDI_DEVNUM, port[dev],
1063 mpu_irq[dev]);
1064 if (err < 0) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +02001065 snd_printk(KERN_ERR "sscape: Failed to create "
Krzysztof Heltacd471002009-10-01 00:10:34 +02001066 "MPU-401 device at 0x%lx\n",
1067 port[dev]);
1068 goto _release_dma;
1069 }
1070
1071 /*
1072 * Enable the master IRQ ...
1073 */
1074 sscape_write(sscape, GA_INTENA_REG, 0x80);
1075
1076 /*
1077 * Initialize mixer
1078 */
1079 spin_lock_irqsave(&sscape->lock, flags);
1080 sscape->midi_vol = 0;
1081 host_write_ctrl_unsafe(sscape->io_base,
1082 CMD_SET_MIDI_VOL, 100);
1083 host_write_ctrl_unsafe(sscape->io_base,
1084 sscape->midi_vol, 100);
1085 host_write_ctrl_unsafe(sscape->io_base,
1086 CMD_XXX_MIDI_VOL, 100);
1087 host_write_ctrl_unsafe(sscape->io_base,
1088 sscape->midi_vol, 100);
1089 host_write_ctrl_unsafe(sscape->io_base,
1090 CMD_SET_EXTMIDI, 100);
1091 host_write_ctrl_unsafe(sscape->io_base,
1092 0, 100);
1093 host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100);
1094
1095 set_midi_mode_unsafe(sscape->io_base);
1096 spin_unlock_irqrestore(&sscape->lock, flags);
Krzysztof Heltec1e7942007-09-17 17:57:37 +02001097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 }
1099
1100 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 * Now that we have successfully created this sound card,
1102 * it is safe to store the pointer.
1103 * NOTE: we only register the sound card's "destructor"
1104 * function now that our "constructor" has completed.
1105 */
1106 card->private_free = soundscape_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108 return 0;
1109
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001110_release_dma:
Takashi Iwai277e9262005-11-17 17:13:12 +01001111 free_dma(dma[dev]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001113_release_region:
Krzysztof Heltec1e7942007-09-17 17:57:37 +02001114 release_and_free_resource(wss_res);
Takashi Iwaib1d57762005-10-10 11:56:31 +02001115 release_and_free_resource(io_res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
1117 return err;
1118}
1119
1120
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001121static int __devinit snd_sscape_match(struct device *pdev, unsigned int i)
Takashi Iwai277e9262005-11-17 17:13:12 +01001122{
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001123 /*
1124 * Make sure we were given ALL of the other parameters.
1125 */
1126 if (port[i] == SNDRV_AUTO_PORT)
1127 return 0;
1128
1129 if (irq[i] == SNDRV_AUTO_IRQ ||
1130 mpu_irq[i] == SNDRV_AUTO_IRQ ||
1131 dma[i] == SNDRV_AUTO_DMA) {
1132 printk(KERN_INFO
1133 "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n");
1134 return 0;
1135 }
1136
1137 return 1;
1138}
1139
1140static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev)
1141{
Takashi Iwai277e9262005-11-17 17:13:12 +01001142 struct snd_card *card;
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001143 struct soundscape *sscape;
Takashi Iwai277e9262005-11-17 17:13:12 +01001144 int ret;
1145
Takashi Iwaic95eadd2008-12-28 16:43:35 +01001146 ret = snd_card_create(index[dev], id[dev], THIS_MODULE,
1147 sizeof(struct soundscape), &card);
1148 if (ret < 0)
1149 return ret;
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001150
1151 sscape = get_card_soundscape(card);
1152 sscape->type = SSCAPE;
1153
Takashi Iwai277e9262005-11-17 17:13:12 +01001154 dma[dev] &= 0x03;
Krzysztof Heltacd471002009-10-01 00:10:34 +02001155 snd_card_set_dev(card, pdev);
1156
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001157 ret = create_sscape(dev, card);
Takashi Iwai277e9262005-11-17 17:13:12 +01001158 if (ret < 0)
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001159 goto _release_card;
1160
Takashi Iwai277e9262005-11-17 17:13:12 +01001161 if ((ret = snd_card_register(card)) < 0) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +02001162 snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001163 goto _release_card;
Takashi Iwai277e9262005-11-17 17:13:12 +01001164 }
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001165 dev_set_drvdata(pdev, card);
Takashi Iwai277e9262005-11-17 17:13:12 +01001166 return 0;
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001167
1168_release_card:
1169 snd_card_free(card);
1170 return ret;
Takashi Iwai277e9262005-11-17 17:13:12 +01001171}
1172
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001173static int __devexit snd_sscape_remove(struct device *devptr, unsigned int dev)
Takashi Iwai277e9262005-11-17 17:13:12 +01001174{
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001175 snd_card_free(dev_get_drvdata(devptr));
1176 dev_set_drvdata(devptr, NULL);
Takashi Iwai277e9262005-11-17 17:13:12 +01001177 return 0;
1178}
1179
Rene Herman83c51c02007-03-20 11:33:46 +01001180#define DEV_NAME "sscape"
Takashi Iwai277e9262005-11-17 17:13:12 +01001181
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001182static struct isa_driver snd_sscape_driver = {
1183 .match = snd_sscape_match,
Takashi Iwai277e9262005-11-17 17:13:12 +01001184 .probe = snd_sscape_probe,
1185 .remove = __devexit_p(snd_sscape_remove),
1186 /* FIXME: suspend/resume */
1187 .driver = {
Rene Herman83c51c02007-03-20 11:33:46 +01001188 .name = DEV_NAME
Takashi Iwai277e9262005-11-17 17:13:12 +01001189 },
1190};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192#ifdef CONFIG_PNP
1193static inline int __devinit get_next_autoindex(int i)
1194{
Takashi Iwai277e9262005-11-17 17:13:12 +01001195 while (i < SNDRV_CARDS && port[i] != SNDRV_AUTO_PORT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 ++i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 return i;
1198}
1199
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
1202 const struct pnp_card_device_id *pid)
1203{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 static int idx = 0;
Takashi Iwai277e9262005-11-17 17:13:12 +01001205 struct pnp_dev *dev;
1206 struct snd_card *card;
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001207 struct soundscape *sscape;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 int ret;
1209
1210 /*
1211 * Allow this function to fail *quietly* if all the ISA PnP
1212 * devices were configured using module parameters instead.
1213 */
Takashi Iwai277e9262005-11-17 17:13:12 +01001214 if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 return -ENOSPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217 /*
1218 * We have found a candidate ISA PnP card. Now we
1219 * have to check that it has the devices that we
1220 * expect it to have.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
1223 /*
1224 * Check that we still have room for another sound card ...
1225 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
Takashi Iwai277e9262005-11-17 17:13:12 +01001227 if (! dev)
1228 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
Takashi Iwai277e9262005-11-17 17:13:12 +01001230 if (!pnp_is_active(dev)) {
1231 if (pnp_activate_dev(dev) < 0) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +02001232 snd_printk(KERN_INFO "sscape: device is inactive\n");
Takashi Iwai277e9262005-11-17 17:13:12 +01001233 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
1235 }
1236
Takashi Iwai277e9262005-11-17 17:13:12 +01001237 /*
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001238 * Create a new ALSA sound card entry, in anticipation
1239 * of detecting our hardware ...
1240 */
Takashi Iwaic95eadd2008-12-28 16:43:35 +01001241 ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
1242 sizeof(struct soundscape), &card);
1243 if (ret < 0)
1244 return ret;
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001245
1246 sscape = get_card_soundscape(card);
1247
1248 /*
1249 * Identify card model ...
1250 */
1251 if (!strncmp("ENS4081", pid->id, 7))
1252 sscape->type = SSCAPE_VIVO;
1253 else
1254 sscape->type = SSCAPE_PNP;
1255
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001256 /*
Takashi Iwai277e9262005-11-17 17:13:12 +01001257 * Read the correct parameters off the ISA PnP bus ...
1258 */
1259 port[idx] = pnp_port_start(dev, 0);
1260 irq[idx] = pnp_irq(dev, 0);
1261 mpu_irq[idx] = pnp_irq(dev, 1);
1262 dma[idx] = pnp_dma(dev, 0) & 0x03;
Krzysztof Heltec1e7942007-09-17 17:57:37 +02001263 if (sscape->type == SSCAPE_PNP) {
1264 dma2[idx] = dma[idx];
1265 wss_port[idx] = CODEC_IO(port[idx]);
1266 } else {
1267 wss_port[idx] = pnp_port_start(dev, 1);
1268 dma2[idx] = pnp_dma(dev, 1);
1269 }
Krzysztof Heltacd471002009-10-01 00:10:34 +02001270 snd_card_set_dev(card, &pcard->card->dev);
Takashi Iwai277e9262005-11-17 17:13:12 +01001271
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001272 ret = create_sscape(idx, card);
Takashi Iwai277e9262005-11-17 17:13:12 +01001273 if (ret < 0)
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001274 goto _release_card;
1275
Takashi Iwai277e9262005-11-17 17:13:12 +01001276 if ((ret = snd_card_register(card)) < 0) {
Krzysztof Heltbcde1f82009-10-02 18:41:29 +02001277 snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001278 goto _release_card;
Takashi Iwai277e9262005-11-17 17:13:12 +01001279 }
1280
1281 pnp_set_card_drvdata(pcard, card);
1282 ++idx;
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001283 return 0;
Takashi Iwai277e9262005-11-17 17:13:12 +01001284
Krzysztof Helt4996bca2007-09-17 16:23:13 +02001285_release_card:
1286 snd_card_free(card);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 return ret;
1288}
1289
1290static void __devexit sscape_pnp_remove(struct pnp_card_link * pcard)
1291{
Takashi Iwai277e9262005-11-17 17:13:12 +01001292 snd_card_free(pnp_get_card_drvdata(pcard));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 pnp_set_card_drvdata(pcard, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294}
1295
1296static struct pnp_card_driver sscape_pnpc_driver = {
1297 .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
1298 .name = "sscape",
1299 .id_table = sscape_pnpids,
1300 .probe = sscape_pnp_detect,
1301 .remove = __devexit_p(sscape_pnp_remove),
1302};
1303
1304#endif /* CONFIG_PNP */
1305
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306static int __init sscape_init(void)
1307{
Rene Herman609d7692007-05-15 11:42:56 +02001308 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
Rene Herman609d7692007-05-15 11:42:56 +02001310 err = isa_register_driver(&snd_sscape_driver, SNDRV_CARDS);
Takashi Iwai59b1b342006-01-04 15:06:44 +01001311#ifdef CONFIG_PNP
Rene Herman609d7692007-05-15 11:42:56 +02001312 if (!err)
1313 isa_registered = 1;
1314
1315 err = pnp_register_card_driver(&sscape_pnpc_driver);
1316 if (!err)
Clemens Ladischf7a92752005-12-07 09:13:42 +01001317 pnp_registered = 1;
Rene Herman609d7692007-05-15 11:42:56 +02001318
1319 if (isa_registered)
1320 err = 0;
Takashi Iwai59b1b342006-01-04 15:06:44 +01001321#endif
Rene Herman609d7692007-05-15 11:42:56 +02001322 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323}
1324
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001325static void __exit sscape_exit(void)
1326{
1327#ifdef CONFIG_PNP
1328 if (pnp_registered)
1329 pnp_unregister_card_driver(&sscape_pnpc_driver);
Rene Herman609d7692007-05-15 11:42:56 +02001330 if (isa_registered)
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001331#endif
Rene Herman609d7692007-05-15 11:42:56 +02001332 isa_unregister_driver(&snd_sscape_driver);
Takashi Iwai5e24c1c2007-02-22 12:50:54 +01001333}
1334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335module_init(sscape_init);
1336module_exit(sscape_exit);