Blame view

sound/drivers/opl3/opl3_lib.c 13.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
2
   *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   *                   Hannu Savolainen 1993-1996,
   *                   Rob Hooft
   *                   
   *  Routines for control of AdLib FM cards (OPL2/OPL3/OPL4 chips)
   *
   *  Most if code is ported from OSS/Lite.
   *
   *   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
   *
   */
  
  #include <sound/opl3.h>
  #include <asm/io.h>
  #include <linux/delay.h>
da155d5b4   Paul Gortmaker   sound: Add module...
29
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/ioport.h>
  #include <sound/minors.h>
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
34
  MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Hannu Savolainen 1993-1996, Rob Hooft");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
  MODULE_DESCRIPTION("Routines for control of AdLib FM cards (OPL2/OPL3/OPL4 chips)");
  MODULE_LICENSE("GPL");
  
  extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
39
  static void snd_opl2_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  {
  	unsigned long flags;
  	unsigned long port;
  
  	/*
  	 * The original 2-OP synth requires a quite long delay
  	 * after writing to a register.
  	 */
  
  	port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port;
  
  	spin_lock_irqsave(&opl3->reg_lock, flags);
  
  	outb((unsigned char) cmd, port);
  	udelay(10);
  
  	outb((unsigned char) val, port + 1);
  	udelay(30);
  
  	spin_unlock_irqrestore(&opl3->reg_lock, flags);
  }
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
61
  static void snd_opl3_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  {
  	unsigned long flags;
  	unsigned long port;
  
  	/*
  	 * The OPL-3 survives with just two INBs
  	 * after writing to a register.
  	 */
  
  	port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port;
  
  	spin_lock_irqsave(&opl3->reg_lock, flags);
  
  	outb((unsigned char) cmd, port);
  	inb(opl3->l_port);
  	inb(opl3->l_port);
  
  	outb((unsigned char) val, port + 1);
  	inb(opl3->l_port);
  	inb(opl3->l_port);
  
  	spin_unlock_irqrestore(&opl3->reg_lock, flags);
  }
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
85
  static int snd_opl3_detect(struct snd_opl3 * opl3)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  {
  	/*
  	 * This function returns 1 if the FM chip is present at the given I/O port
  	 * The detection algorithm plays with the timer built in the FM chip and
  	 * looks for a change in the status register.
  	 *
  	 * Note! The timers of the FM chip are not connected to AdLib (and compatible)
  	 * boards.
  	 *
  	 * Note2! The chip is initialized if detected.
  	 */
  
  	unsigned char stat1, stat2, signature;
  
  	/* Reset timers 1 and 2 */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER1_MASK | OPL3_TIMER2_MASK);
  	/* Reset the IRQ of the FM chip */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);
  	signature = stat1 = inb(opl3->l_port);	/* Status register */
  	if ((stat1 & 0xe0) != 0x00) {	/* Should be 0x00 */
  		snd_printd("OPL3: stat1 = 0x%x
  ", stat1);
  		return -ENODEV;
  	}
  	/* Set timer1 to 0xff */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER1, 0xff);
  	/* Unmask and start timer 1 */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER2_MASK | OPL3_TIMER1_START);
  	/* Now we have to delay at least 80us */
  	udelay(200);
  	/* Read status after timers have expired */
  	stat2 = inb(opl3->l_port);
  	/* Stop the timers */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER1_MASK | OPL3_TIMER2_MASK);
  	/* Reset the IRQ of the FM chip */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);
  	if ((stat2 & 0xe0) != 0xc0) {	/* There is no YM3812 */
  		snd_printd("OPL3: stat2 = 0x%x
  ", stat2);
  		return -ENODEV;
  	}
  
  	/* If the toplevel code knows exactly the type of chip, don't try
  	   to detect it. */
  	if (opl3->hardware != OPL3_HW_AUTO)
  		return 0;
  
  	/* There is a FM chip on this address. Detect the type (OPL2 to OPL4) */
  	if (signature == 0x06) {	/* OPL2 */
  		opl3->hardware = OPL3_HW_OPL2;
  	} else {
  		/*
  		 * If we had an OPL4 chip, opl3->hardware would have been set
  		 * by the OPL4 driver; so we can assume OPL3 here.
  		 */
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
141
142
  		if (snd_BUG_ON(!opl3->r_port))
  			return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
149
150
151
152
153
154
  		opl3->hardware = OPL3_HW_OPL3;
  	}
  	return 0;
  }
  
  /*
   *  AdLib timers
   */
  
  /*
   *  Timer 1 - 80us
   */
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
155
  static int snd_opl3_timer1_start(struct snd_timer * timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
  {
  	unsigned long flags;
  	unsigned char tmp;
  	unsigned int ticks;
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
160
  	struct snd_opl3 *opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
168
169
170
171
  
  	opl3 = snd_timer_chip(timer);
  	spin_lock_irqsave(&opl3->timer_lock, flags);
  	ticks = timer->sticks;
  	tmp = (opl3->timer_enable | OPL3_TIMER1_START) & ~OPL3_TIMER1_MASK;
  	opl3->timer_enable = tmp;
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER1, 256 - ticks);	/* timer 1 count */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp);	/* enable timer 1 IRQ */
  	spin_unlock_irqrestore(&opl3->timer_lock, flags);
  	return 0;
  }
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
172
  static int snd_opl3_timer1_stop(struct snd_timer * timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
  {
  	unsigned long flags;
  	unsigned char tmp;
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
176
  	struct snd_opl3 *opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
180
181
182
183
184
185
186
187
188
189
  
  	opl3 = snd_timer_chip(timer);
  	spin_lock_irqsave(&opl3->timer_lock, flags);
  	tmp = (opl3->timer_enable | OPL3_TIMER1_MASK) & ~OPL3_TIMER1_START;
  	opl3->timer_enable = tmp;
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp);	/* disable timer #1 */
  	spin_unlock_irqrestore(&opl3->timer_lock, flags);
  	return 0;
  }
  
  /*
   *  Timer 2 - 320us
   */
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
190
  static int snd_opl3_timer2_start(struct snd_timer * timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
  {
  	unsigned long flags;
  	unsigned char tmp;
  	unsigned int ticks;
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
195
  	struct snd_opl3 *opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
201
202
203
204
205
206
  
  	opl3 = snd_timer_chip(timer);
  	spin_lock_irqsave(&opl3->timer_lock, flags);
  	ticks = timer->sticks;
  	tmp = (opl3->timer_enable | OPL3_TIMER2_START) & ~OPL3_TIMER2_MASK;
  	opl3->timer_enable = tmp;
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER2, 256 - ticks);	/* timer 1 count */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp);	/* enable timer 1 IRQ */
  	spin_unlock_irqrestore(&opl3->timer_lock, flags);
  	return 0;
  }
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
207
  static int snd_opl3_timer2_stop(struct snd_timer * timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
  {
  	unsigned long flags;
  	unsigned char tmp;
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
211
  	struct snd_opl3 *opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
221
222
223
224
  
  	opl3 = snd_timer_chip(timer);
  	spin_lock_irqsave(&opl3->timer_lock, flags);
  	tmp = (opl3->timer_enable | OPL3_TIMER2_MASK) & ~OPL3_TIMER2_START;
  	opl3->timer_enable = tmp;
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp);	/* disable timer #1 */
  	spin_unlock_irqrestore(&opl3->timer_lock, flags);
  	return 0;
  }
  
  /*
  
   */
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
225
  static struct snd_timer_hardware snd_opl3_timer1 =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
  {
  	.flags =	SNDRV_TIMER_HW_STOP,
  	.resolution =	80000,
  	.ticks =	256,
  	.start =	snd_opl3_timer1_start,
  	.stop =		snd_opl3_timer1_stop,
  };
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
233
  static struct snd_timer_hardware snd_opl3_timer2 =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
237
238
239
240
  {
  	.flags =	SNDRV_TIMER_HW_STOP,
  	.resolution =	320000,
  	.ticks =	256,
  	.start =	snd_opl3_timer2_start,
  	.stop =		snd_opl3_timer2_stop,
  };
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
241
  static int snd_opl3_timer1_init(struct snd_opl3 * opl3, int timer_no)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  {
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
243
244
  	struct snd_timer *timer = NULL;
  	struct snd_timer_id tid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
  	int err;
  
  	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
  	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
  	tid.card = opl3->card->number;
  	tid.device = timer_no;
  	tid.subdevice = 0;
  	if ((err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer)) >= 0) {
  		strcpy(timer->name, "AdLib timer #1");
  		timer->private_data = opl3;
  		timer->hw = snd_opl3_timer1;
  	}
  	opl3->timer1 = timer;
  	return err;
  }
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
260
  static int snd_opl3_timer2_init(struct snd_opl3 * opl3, int timer_no)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  {
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
262
263
  	struct snd_timer *timer = NULL;
  	struct snd_timer_id tid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  	int err;
  
  	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
  	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
  	tid.card = opl3->card->number;
  	tid.device = timer_no;
  	tid.subdevice = 0;
  	if ((err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer)) >= 0) {
  		strcpy(timer->name, "AdLib timer #2");
  		timer->private_data = opl3;
  		timer->hw = snd_opl3_timer2;
  	}
  	opl3->timer2 = timer;
  	return err;
  }
  
  /*
  
   */
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
283
  void snd_opl3_interrupt(struct snd_hwdep * hw)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  {
  	unsigned char status;
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
286
287
  	struct snd_opl3 *opl3;
  	struct snd_timer *timer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
293
294
  
  	if (hw == NULL)
  		return;
  
  	opl3 = hw->private_data;
  	status = inb(opl3->l_port);
  #if 0
45203832d   Takashi Iwai   ALSA: Add missing...
295
296
  	snd_printk(KERN_DEBUG "AdLib IRQ status = 0x%x
  ", status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
302
303
304
305
306
307
308
309
  #endif
  	if (!(status & 0x80))
  		return;
  
  	if (status & 0x40) {
  		timer = opl3->timer1;
  		snd_timer_interrupt(timer, timer->sticks);
  	}
  	if (status & 0x20) {
  		timer = opl3->timer2;
  		snd_timer_interrupt(timer, timer->sticks);
  	}
  }
ac19e19b3   Takashi Iwai   [ALSA] opl3 - Mov...
310
  EXPORT_SYMBOL(snd_opl3_interrupt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
  /*
  
   */
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
314
  static int snd_opl3_free(struct snd_opl3 *opl3)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  {
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
316
317
  	if (snd_BUG_ON(!opl3))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
  	if (opl3->private_free)
  		opl3->private_free(opl3);
224a03325   Takashi Iwai   [ALSA] opl3 - Use...
320
  	snd_opl3_clear_patches(opl3);
b1d5776d8   Takashi Iwai   [ALSA] Remove vma...
321
322
  	release_and_free_resource(opl3->res_l_port);
  	release_and_free_resource(opl3->res_r_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
  	kfree(opl3);
  	return 0;
  }
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
326
  static int snd_opl3_dev_free(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  {
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
328
  	struct snd_opl3 *opl3 = device->device_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
  	return snd_opl3_free(opl3);
  }
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
331
  int snd_opl3_new(struct snd_card *card,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  		 unsigned short hardware,
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
333
  		 struct snd_opl3 **ropl3)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  {
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
335
  	static struct snd_device_ops ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  		.dev_free = snd_opl3_dev_free,
  	};
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
338
  	struct snd_opl3 *opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
  	int err;
  
  	*ropl3 = NULL;
561b220a4   Takashi Iwai   [ALSA] Replace wi...
342
  	opl3 = kzalloc(sizeof(*opl3), GFP_KERNEL);
73e77ba02   Takashi Iwai   [ALSA] Add error ...
343
344
345
  	if (opl3 == NULL) {
  		snd_printk(KERN_ERR "opl3: cannot allocate
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  		return -ENOMEM;
73e77ba02   Takashi Iwai   [ALSA] Add error ...
347
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
  
  	opl3->card = card;
  	opl3->hardware = hardware;
  	spin_lock_init(&opl3->reg_lock);
  	spin_lock_init(&opl3->timer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
358
359
360
361
  
  	if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) {
  		snd_opl3_free(opl3);
  		return err;
  	}
  
  	*ropl3 = opl3;
  	return 0;
  }
ac19e19b3   Takashi Iwai   [ALSA] opl3 - Mov...
362
  EXPORT_SYMBOL(snd_opl3_new);
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
363
  int snd_opl3_init(struct snd_opl3 *opl3)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  {
  	if (! opl3->command) {
  		printk(KERN_ERR "snd_opl3_init: command not defined!
  ");
  		return -EINVAL;
  	}
  
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TEST, OPL3_ENABLE_WAVE_SELECT);
  	/* Melodic mode */
  	opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 0x00);
  
  	switch (opl3->hardware & OPL3_HW_MASK) {
  	case OPL3_HW_OPL2:
  		opl3->max_voices = MAX_OPL2_VOICES;
  		break;
  	case OPL3_HW_OPL3:
  	case OPL3_HW_OPL4:
  		opl3->max_voices = MAX_OPL3_VOICES;
  		/* Enter OPL3 mode */
  		opl3->command(opl3, OPL3_RIGHT | OPL3_REG_MODE, OPL3_OPL3_ENABLE);
  	}
  	return 0;
  }
ac19e19b3   Takashi Iwai   [ALSA] opl3 - Mov...
387
  EXPORT_SYMBOL(snd_opl3_init);
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
388
  int snd_opl3_create(struct snd_card *card,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
  		    unsigned long l_port,
  		    unsigned long r_port,
  		    unsigned short hardware,
  		    int integrated,
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
393
  		    struct snd_opl3 ** ropl3)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  {
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
395
  	struct snd_opl3 *opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
400
401
402
403
404
  	int err;
  
  	*ropl3 = NULL;
  	if ((err = snd_opl3_new(card, hardware, &opl3)) < 0)
  		return err;
  	if (! integrated) {
  		if ((opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)")) == NULL) {
  			snd_printk(KERN_ERR "opl3: can't grab left port 0x%lx
  ", l_port);
676338a16   Takashi Iwai   [ALSA] opl3 - Fix...
405
  			snd_device_free(card, opl3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
411
  			return -EBUSY;
  		}
  		if (r_port != 0 &&
  		    (opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)")) == NULL) {
  			snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx
  ", r_port);
676338a16   Takashi Iwai   [ALSA] opl3 - Fix...
412
  			snd_device_free(card, opl3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  			return -EBUSY;
  		}
  	}
  	opl3->l_port = l_port;
  	opl3->r_port = r_port;
  
  	switch (opl3->hardware) {
  	/* some hardware doesn't support timers */
  	case OPL3_HW_OPL3_SV:
  	case OPL3_HW_OPL3_CS:
  	case OPL3_HW_OPL3_FM801:
  		opl3->command = &snd_opl3_command;
  		break;
  	default:
  		opl3->command = &snd_opl2_command;
  		if ((err = snd_opl3_detect(opl3)) < 0) {
  			snd_printd("OPL2/3 chip not detected at 0x%lx/0x%lx
  ",
  				   opl3->l_port, opl3->r_port);
676338a16   Takashi Iwai   [ALSA] opl3 - Fix...
432
  			snd_device_free(card, opl3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
  			return err;
  		}
  		/* detect routine returns correct hardware type */
  		switch (opl3->hardware & OPL3_HW_MASK) {
  		case OPL3_HW_OPL3:
  		case OPL3_HW_OPL4:
  			opl3->command = &snd_opl3_command;
  		}
  	}
  
  	snd_opl3_init(opl3);
  
  	*ropl3 = opl3;
  	return 0;
  }
ac19e19b3   Takashi Iwai   [ALSA] opl3 - Mov...
448
  EXPORT_SYMBOL(snd_opl3_create);
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
449
  int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  {
  	int err;
  
  	if (timer1_dev >= 0)
  		if ((err = snd_opl3_timer1_init(opl3, timer1_dev)) < 0)
  			return err;
  	if (timer2_dev >= 0) {
  		if ((err = snd_opl3_timer2_init(opl3, timer2_dev)) < 0) {
  			snd_device_free(opl3->card, opl3->timer1);
  			opl3->timer1 = NULL;
  			return err;
  		}
  	}
  	return 0;
  }
ac19e19b3   Takashi Iwai   [ALSA] opl3 - Mov...
465
  EXPORT_SYMBOL(snd_opl3_timer_new);
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
466
  int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  		       int device, int seq_device,
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
468
  		       struct snd_hwdep ** rhwdep)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  {
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
470
471
  	struct snd_hwdep *hw;
  	struct snd_card *card = opl3->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
477
478
479
480
481
482
483
  	int err;
  
  	if (rhwdep)
  		*rhwdep = NULL;
  
  	/* create hardware dependent device (direct FM) */
  
  	if ((err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw)) < 0) {
  		snd_device_free(card, opl3);
  		return err;
  	}
  	hw->private_data = opl3;
05c1afe75   Takashi Iwai   [ALSA] opl3 - sim...
484
  	hw->exclusive = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  #ifdef CONFIG_SND_OSSEMUL
  	if (device == 0) {
  		hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM;
  		sprintf(hw->oss_dev, "dmfm%i", card->number);
  	}
  #endif
  	strcpy(hw->name, hw->id);
  	switch (opl3->hardware & OPL3_HW_MASK) {
  	case OPL3_HW_OPL2:
  		strcpy(hw->name, "OPL2 FM");
  		hw->iface = SNDRV_HWDEP_IFACE_OPL2;
  		break;
  	case OPL3_HW_OPL3:
  		strcpy(hw->name, "OPL3 FM");
  		hw->iface = SNDRV_HWDEP_IFACE_OPL3;
  		break;
  	case OPL3_HW_OPL4:
  		strcpy(hw->name, "OPL4 FM");
  		hw->iface = SNDRV_HWDEP_IFACE_OPL4;
  		break;
  	}
  
  	/* operators - only ioctl */
  	hw->ops.open = snd_opl3_open;
  	hw->ops.ioctl = snd_opl3_ioctl;
224a03325   Takashi Iwai   [ALSA] opl3 - Use...
510
  	hw->ops.write = snd_opl3_write;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  	hw->ops.release = snd_opl3_release;
045765253   Takashi Iwai   [ALSA] opl3 - Fix...
512
  	opl3->hwdep = hw;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
  	opl3->seq_dev_num = seq_device;
  #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
  	if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3,
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
516
  			       sizeof(struct snd_opl3 *), &opl3->seq_dev) >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  		strcpy(opl3->seq_dev->name, hw->name);
5b1646a8e   Takashi Iwai   [ALSA] Remove xxx...
518
  		*(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(opl3->seq_dev) = opl3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
523
524
  	}
  #endif
  	if (rhwdep)
  		*rhwdep = hw;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  EXPORT_SYMBOL(snd_opl3_hwdep_new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  /*
   *  INIT part
   */
  
  static int __init alsa_opl3_init(void)
  {
  	return 0;
  }
  
  static void __exit alsa_opl3_exit(void)
  {
  }
  
  module_init(alsa_opl3_init)
  module_exit(alsa_opl3_exit)