Blame view

sound/isa/als100.c 10.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  
  /*
      card-als100.c - driver for Avance Logic ALS100 based soundcards.
      Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
5
      Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
  
      Thanks to Pierfrancesco 'qM2' Passerini.
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
8
9
      Generalised for soundcards based on DT-0196 and ALS-007 chips
      by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
23
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.
  
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
  
      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
  #include <linux/init.h>
  #include <linux/wait.h>
  #include <linux/time.h>
  #include <linux/pnp.h>
65a772172   Paul Gortmaker   sound: fix driver...
28
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
  #include <sound/core.h>
  #include <sound/initval.h>
  #include <sound/mpu401.h>
  #include <sound/opl3.h>
  #include <sound/sb.h>
  
  #define PFX "als100: "
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
36
37
38
39
  MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");
  MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
  		"{Avance Logic ALS-007}}"
  		"{{Avance Logic,ALS100 - PRO16PNP},"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
  	        "{Avance Logic,ALS110},"
  	        "{Avance Logic,ALS120},"
  	        "{Avance Logic,ALS200},"
  	        "{3D Melody,MF1000},"
  	        "{Digimate,3D Sound},"
  	        "{Avance Logic,ALS120},"
  	        "{RTL,RTL3000}}");
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
47
48
  MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
  MODULE_LICENSE("GPL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
a67ff6a54   Rusty Russell   ALSA: module_para...
51
  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
60
  static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
  static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
  static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
  static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
  static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
  static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
  static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
  
  module_param_array(index, int, NULL, 0444);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
61
  MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  module_param_array(id, charp, NULL, 0444);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
63
  MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  module_param_array(enable, bool, NULL, 0444);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
65
66
67
  MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard.");
  
  MODULE_ALIAS("snd-dt019x");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  
  struct snd_card_als100 {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
  	struct pnp_dev *dev;
  	struct pnp_dev *devmpu;
  	struct pnp_dev *devopl;
480615f33   Takashi Iwai   [ALSA] als100 - A...
73
  	struct snd_sb *chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
  };
  
  static struct pnp_card_device_id snd_als100_pnpids[] = {
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
77
78
79
80
81
82
83
84
  	/* DT197A30 */
  	{ .id = "RWB1688",
  	  .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
  	  .driver_data = SB_HW_DT019X },
  	/* DT0196 / ALS-007 */
  	{ .id = "ALS0007",
  	  .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
  	  .driver_data = SB_HW_DT019X },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  	/* ALS100 - PRO16PNP */
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
86
87
88
  	{ .id = "ALS0001",
  	  .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
  	  .driver_data = SB_HW_ALS100 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  	/* ALS110 - MF1000 - Digimate 3D Sound */
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
90
91
92
  	{ .id = "ALS0110",
  	  .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } },
  	  .driver_data = SB_HW_ALS100 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  	/* ALS120 */
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
94
95
96
  	{ .id = "ALS0120",
  	  .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
  	  .driver_data = SB_HW_ALS100 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  	/* ALS200 */
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
98
99
100
  	{ .id = "ALS0200",
  	  .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } },
  	  .driver_data = SB_HW_ALS100 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  	/* ALS200 OEM */
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
102
103
104
  	{ .id = "ALS0200",
  	  .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } },
  	  .driver_data = SB_HW_ALS100 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	/* RTL3000 */
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
106
107
108
109
  	{ .id = "RTL3000",
  	  .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
  	  .driver_data = SB_HW_ALS100 },
  	{ .id = "" } /* end */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
  };
  
  MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
  static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
  					 struct pnp_card_link *card,
  					 const struct pnp_card_device_id *id)
  {
  	struct pnp_dev *pdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
109c53f84   Rene Herman   [ALSA] sound/isa:...
120
  	if (acard->dev == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  		return -ENODEV;
109c53f84   Rene Herman   [ALSA] sound/isa:...
122

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
  	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev);
  	acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev);
  
  	pdev = acard->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
  	err = pnp_activate_dev(pdev);
  	if (err < 0) {
  		snd_printk(KERN_ERR PFX "AUDIO pnp configure failure
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
  		return err;
  	}
  	port[dev] = pnp_port_start(pdev, 0);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
134
135
136
137
138
139
  	if (id->driver_data == SB_HW_DT019X)
  		dma8[dev] = pnp_dma(pdev, 0);
  	else {
  		dma8[dev] = pnp_dma(pdev, 1);
  		dma16[dev] = pnp_dma(pdev, 0);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
  	irq[dev] = pnp_irq(pdev, 0);
  
  	pdev = acard->devmpu;
  	if (pdev != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  		err = pnp_activate_dev(pdev);
  		if (err < 0)
  			goto __mpu_error;
  		mpu_port[dev] = pnp_port_start(pdev, 0);
  		mpu_irq[dev] = pnp_irq(pdev, 0);
  	} else {
  	     __mpu_error:
  	     	if (pdev) {
  		     	pnp_release_card_device(pdev);
  	     		snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping
  ");
  	     	}
  	     	acard->devmpu = NULL;
  	     	mpu_port[dev] = -1;
  	}
  
  	pdev = acard->devopl;
  	if (pdev != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  		err = pnp_activate_dev(pdev);
  		if (err < 0)
  			goto __fm_error;
  		fm_port[dev] = pnp_port_start(pdev, 0);
  	} else {
  	      __fm_error:
  	     	if (pdev) {
  		     	pnp_release_card_device(pdev);
  	     		snd_printk(KERN_ERR PFX "OPL3 pnp configure failure, skipping
  ");
  	     	}
  	     	acard->devopl = NULL;
  	     	fm_port[dev] = -1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  	return 0;
  }
51427ec0f   Bjorn Helgaas   [PATCH] PNP: adju...
178
  static int __devinit snd_card_als100_probe(int dev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
  					struct pnp_card_link *pcard,
  					const struct pnp_card_device_id *pid)
  {
  	int error;
11ff5c62b   Takashi Iwai   [ALSA] Remove xxx...
183
184
  	struct snd_sb *chip;
  	struct snd_card *card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  	struct snd_card_als100 *acard;
11ff5c62b   Takashi Iwai   [ALSA] Remove xxx...
186
  	struct snd_opl3 *opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187

c95eadd2f   Takashi Iwai   ALSA: Convert to ...
188
189
190
191
  	error = snd_card_create(index[dev], id[dev], THIS_MODULE,
  				sizeof(struct snd_card_als100), &card);
  	if (error < 0)
  		return error;
480615f33   Takashi Iwai   [ALSA] als100 - A...
192
  	acard = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
198
  
  	if ((error = snd_card_als100_pnp(dev, acard, pcard, pid))) {
  		snd_card_free(card);
  		return error;
  	}
  	snd_card_set_dev(card, &pcard->card->dev);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
199
200
201
202
203
204
205
206
207
  	if (pid->driver_data == SB_HW_DT019X)
  		dma16[dev] = -1;
  
  	error = snd_sbdsp_create(card, port[dev], irq[dev],
  				  snd_sb16dsp_interrupt,
  				  dma8[dev], dma16[dev],
  				  pid->driver_data,
  				  &chip);
  	if (error < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
  		snd_card_free(card);
  		return error;
  	}
480615f33   Takashi Iwai   [ALSA] als100 - A...
211
  	acard->chip = chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212

14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
213
214
215
216
217
218
219
220
221
222
223
224
225
  	if (pid->driver_data == SB_HW_DT019X) {
  		strcpy(card->driver, "DT-019X");
  		strcpy(card->shortname, "Diamond Tech. DT-019X");
  		sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
  			card->shortname, chip->name, chip->port,
  			irq[dev], dma8[dev]);
  	} else {
  		strcpy(card->driver, "ALS100");
  		strcpy(card->shortname, "Avance Logic ALS100");
  		sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
  			card->shortname, chip->name, chip->port,
  			irq[dev], dma8[dev], dma16[dev]);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
233
234
235
236
237
  
  	if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
  		snd_card_free(card);
  		return error;
  	}
  
  	if ((error = snd_sbmixer_new(chip)) < 0) {
  		snd_card_free(card);
  		return error;
  	}
  
  	if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
238
239
240
241
242
243
244
245
246
247
  		int mpu_type = MPU401_HW_ALS100;
  
  		if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
  			mpu_irq[dev] = -1;
  
  		if (pid->driver_data == SB_HW_DT019X)
  			mpu_type = MPU401_HW_MPU401;
  
  		if (snd_mpu401_uart_new(card, 0,
  					mpu_type,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  					mpu_port[dev], 0, 
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
249
  					mpu_irq[dev],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  					NULL) < 0)
  			snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx
  ", mpu_port[dev]);
  	}
  
  	if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
  		if (snd_opl3_create(card,
  				    fm_port[dev], fm_port[dev] + 2,
  				    OPL3_HW_AUTO, 0, &opl3) < 0) {
  			snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx
  ",
  				   fm_port[dev], fm_port[dev] + 2);
  		} else {
  			if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
  				snd_card_free(card);
  				return error;
  			}
  			if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
  				snd_card_free(card);
  				return error;
  			}
  		}
  	}
  
  	if ((error = snd_card_register(card)) < 0) {
  		snd_card_free(card);
  		return error;
  	}
  	pnp_set_card_drvdata(pcard, card);
  	return 0;
  }
51427ec0f   Bjorn Helgaas   [PATCH] PNP: adju...
281
  static unsigned int __devinitdata als100_devices;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
286
287
288
289
290
291
292
293
294
  static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card,
  					   const struct pnp_card_device_id *id)
  {
  	static int dev;
  	int res;
  
  	for ( ; dev < SNDRV_CARDS; dev++) {
  		if (!enable[dev])
  			continue;
  		res = snd_card_als100_probe(dev, card, id);
  		if (res < 0)
  			return res;
  		dev++;
51427ec0f   Bjorn Helgaas   [PATCH] PNP: adju...
295
  		als100_devices++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
302
  		return 0;
  	}
  	return -ENODEV;
  }
  
  static void __devexit snd_als100_pnp_remove(struct pnp_card_link * pcard)
  {
480615f33   Takashi Iwai   [ALSA] als100 - A...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  	snd_card_free(pnp_get_card_drvdata(pcard));
  	pnp_set_card_drvdata(pcard, NULL);
  }
  
  #ifdef CONFIG_PM
  static int snd_als100_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
  {
  	struct snd_card *card = pnp_get_card_drvdata(pcard);
  	struct snd_card_als100 *acard = card->private_data;
  	struct snd_sb *chip = acard->chip;
  
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
  	snd_pcm_suspend_all(chip->pcm);
  	snd_sbmixer_suspend(chip);
  	return 0;
  }
  
  static int snd_als100_pnp_resume(struct pnp_card_link *pcard)
  {
  	struct snd_card *card = pnp_get_card_drvdata(pcard);
  	struct snd_card_als100 *acard = card->private_data;
  	struct snd_sb *chip = acard->chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325

480615f33   Takashi Iwai   [ALSA] als100 - A...
326
327
328
329
  	snd_sbdsp_reset(chip);
  	snd_sbmixer_resume(chip);
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  }
480615f33   Takashi Iwai   [ALSA] als100 - A...
331
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
  
  static struct pnp_card_driver als100_pnpc_driver = {
  	.flags          = PNP_DRIVER_RES_DISABLE,
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
335
  	.name		= "als100",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
          .id_table       = snd_als100_pnpids,
          .probe          = snd_als100_pnp_detect,
          .remove         = __devexit_p(snd_als100_pnp_remove),
480615f33   Takashi Iwai   [ALSA] als100 - A...
339
340
341
342
  #ifdef CONFIG_PM
  	.suspend	= snd_als100_pnp_suspend,
  	.resume		= snd_als100_pnp_resume,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
  };
  
  static int __init alsa_card_als100_init(void)
  {
51427ec0f   Bjorn Helgaas   [PATCH] PNP: adju...
347
348
349
350
351
  	int err;
  
  	err = pnp_register_card_driver(&als100_pnpc_driver);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352

51427ec0f   Bjorn Helgaas   [PATCH] PNP: adju...
353
  	if (!als100_devices) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  		pnp_unregister_card_driver(&als100_pnpc_driver);
480615f33   Takashi Iwai   [ALSA] als100 - A...
355
  #ifdef MODULE
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
356
357
  		snd_printk(KERN_ERR "no Avance Logic based soundcards found
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  #endif
480615f33   Takashi Iwai   [ALSA] als100 - A...
359
360
361
  		return -ENODEV;
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
369
370
  }
  
  static void __exit alsa_card_als100_exit(void)
  {
  	pnp_unregister_card_driver(&als100_pnpc_driver);
  }
  
  module_init(alsa_card_als100_init)
  module_exit(alsa_card_als100_exit)