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
      Generalised for soundcards based on DT-0196 and ALS-007 chips
409a3e981   Jonathan Woithe   Email/web address...
9
      by Jonathan Woithe <jwoithe@just42.net>: June 2002.
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
10

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
18
19
20
21
22
23
24
      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
25
26
27
28
  #include <linux/init.h>
  #include <linux/wait.h>
  #include <linux/time.h>
  #include <linux/pnp.h>
65a772172   Paul Gortmaker   sound: fix driver...
29
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
  #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...
37
38
39
40
  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
41
42
43
44
45
46
47
  	        "{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...
48
49
  MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
  MODULE_LICENSE("GPL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
  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...
52
  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
57
58
59
60
61
  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...
62
  MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  module_param_array(id, charp, NULL, 0444);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
64
  MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  module_param_array(enable, bool, NULL, 0444);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
66
67
68
  MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard.");
  
  MODULE_ALIAS("snd-dt019x");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
  
  struct snd_card_als100 {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
  	struct pnp_dev *dev;
  	struct pnp_dev *devmpu;
  	struct pnp_dev *devopl;
480615f33   Takashi Iwai   [ALSA] als100 - A...
74
  	struct snd_sb *chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  };
815cfec76   Arvind Yadav   ALSA: als100: con...
76
  static const 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);
1bff292e9   Bill Pemberton   ALSA: isa: remove...
113
114
115
  static int snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
  			       struct pnp_card_link *card,
  			       const struct pnp_card_device_id *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
  {
  	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;
  }
1bff292e9   Bill Pemberton   ALSA: isa: remove...
178
179
180
  static int snd_card_als100_probe(int dev,
  				 struct pnp_card_link *pcard,
  				 const struct pnp_card_device_id *pid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
  {
  	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

4323cc4d5   Takashi Iwai   ALSA: isa: Conver...
188
189
190
  	error = snd_card_new(&pcard->card->dev,
  			     index[dev], id[dev], THIS_MODULE,
  			     sizeof(struct snd_card_als100), &card);
c95eadd2f   Takashi Iwai   ALSA: Convert to ...
191
192
  	if (error < 0)
  		return error;
480615f33   Takashi Iwai   [ALSA] als100 - A...
193
  	acard = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
  
  	if ((error = snd_card_als100_pnp(dev, acard, pcard, pid))) {
  		snd_card_free(card);
  		return error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199

14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
200
201
202
203
204
205
206
207
208
  	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
209
210
211
  		snd_card_free(card);
  		return error;
  	}
480615f33   Takashi Iwai   [ALSA] als100 - A...
212
  	acard->chip = chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213

14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
214
215
216
  	if (pid->driver_data == SB_HW_DT019X) {
  		strcpy(card->driver, "DT-019X");
  		strcpy(card->shortname, "Diamond Tech. DT-019X");
8a463639d   Arnd Bergmann   ALSA: als100: fix...
217
218
219
  		snprintf(card->longname, sizeof(card->longname),
  			 "Diamond Tech. DT-019X, %s at 0x%lx, irq %d, dma %d",
  			 chip->name, chip->port, irq[dev], dma8[dev]);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
220
221
222
  	} else {
  		strcpy(card->driver, "ALS100");
  		strcpy(card->shortname, "Avance Logic ALS100");
8a463639d   Arnd Bergmann   ALSA: als100: fix...
223
224
225
226
  		snprintf(card->longname, sizeof(card->longname),
  			 "Avance Logic ALS100, %s at 0x%lx, irq %d, dma %d&%d",
  			 chip->name, chip->port, irq[dev], dma8[dev],
  			 dma16[dev]);
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
227
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228

92533f188   Lars-Peter Clausen   ASoC: sb16: Simpl...
229
  	if ((error = snd_sb16dsp_pcm(chip, 0)) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
235
236
237
238
239
  		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...
240
241
242
243
244
245
246
247
248
249
  		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
250
  					mpu_port[dev], 0, 
14ff3e783   Krzysztof Helt   ALSA: dt019x: mer...
251
  					mpu_irq[dev],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  					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;
  }
1bff292e9   Bill Pemberton   ALSA: isa: remove...
283
  static unsigned int als100_devices;
51427ec0f   Bjorn Helgaas   [PATCH] PNP: adju...
284

1bff292e9   Bill Pemberton   ALSA: isa: remove...
285
286
  static int snd_als100_pnp_detect(struct pnp_card_link *card,
  				 const struct pnp_card_device_id *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
292
293
294
295
296
297
  {
  	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...
298
  		als100_devices++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
  		return 0;
  	}
  	return -ENODEV;
  }
1bff292e9   Bill Pemberton   ALSA: isa: remove...
303
  static void snd_als100_pnp_remove(struct pnp_card_link *pcard)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  {
480615f33   Takashi Iwai   [ALSA] als100 - A...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  	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
327

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

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