Blame view

sound/usb/usx2y/us122l.c 18.8 KB
030a07e44   Karsten Wiese   ALSA: Add USB US1...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
   *
   * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
19
20
  #include <linux/usb.h>
  #include <linux/usb/audio.h>
da155d5b4   Paul Gortmaker   sound: Add module...
21
  #include <linux/module.h>
030a07e44   Karsten Wiese   ALSA: Add USB US1...
22
23
24
25
26
27
28
  #include <sound/core.h>
  #include <sound/hwdep.h>
  #include <sound/pcm.h>
  #include <sound/initval.h>
  #define MODNAME "US122L"
  #include "usb_stream.c"
  #include "../usbaudio.h"
e5779998b   Daniel Mack   ALSA: usb-audio: ...
29
  #include "../midi.h"
030a07e44   Karsten Wiese   ALSA: Add USB US1...
30
31
32
33
34
35
36
37
38
  #include "us122l.h"
  
  MODULE_AUTHOR("Karsten Wiese <fzu@wemgehoertderstaat.de>");
  MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.5");
  MODULE_LICENSE("GPL");
  
  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-max */
  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* Id for this card */
  							/* Enable this card */
a67ff6a54   Rusty Russell   ALSA: module_para...
39
  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  
  module_param_array(index, int, NULL, 0444);
  MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
  module_param_array(id, charp, NULL, 0444);
  MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS".");
  module_param_array(enable, bool, NULL, 0444);
  MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS".");
  
  static int snd_us122l_card_used[SNDRV_CARDS];
  
  
  static int us122l_create_usbmidi(struct snd_card *card)
  {
  	static struct snd_usb_midi_endpoint_info quirk_data = {
  		.out_ep = 4,
  		.in_ep = 3,
  		.out_cables =	0x001,
  		.in_cables =	0x001
  	};
  	static struct snd_usb_audio_quirk quirk = {
  		.vendor_name =	"US122L",
  		.product_name =	NAME_ALLCAPS,
  		.ifnum = 	1,
  		.type = QUIRK_MIDI_US122L,
  		.data = &quirk_data
  	};
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
66
  	struct usb_device *dev = US122L(card)->dev;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
67
  	struct usb_interface *iface = usb_ifnum_to_if(dev, 1);
d82af9f9a   Clemens Ladisch   sound: usb: make ...
68
69
  	return snd_usbmidi_create(card, iface,
  				  &US122L(card)->midi_list, &quirk);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
70
  }
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  static int us144_create_usbmidi(struct snd_card *card)
  {
  	static struct snd_usb_midi_endpoint_info quirk_data = {
  		.out_ep = 4,
  		.in_ep = 3,
  		.out_cables =	0x001,
  		.in_cables =	0x001
  	};
  	static struct snd_usb_audio_quirk quirk = {
  		.vendor_name =	"US144",
  		.product_name =	NAME_ALLCAPS,
  		.ifnum = 	0,
  		.type = QUIRK_MIDI_US122L,
  		.data = &quirk_data
  	};
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
86
  	struct usb_device *dev = US122L(card)->dev;
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
87
  	struct usb_interface *iface = usb_ifnum_to_if(dev, 0);
d82af9f9a   Clemens Ladisch   sound: usb: make ...
88
89
  	return snd_usbmidi_create(card, iface,
  				  &US122L(card)->midi_list, &quirk);
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
90
  }
030a07e44   Karsten Wiese   ALSA: Add USB US1...
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
141
142
143
144
  /*
   * Wrapper for usb_control_msg().
   * Allocates a temp buffer to prevent dmaing from/to the stack.
   */
  static int us122l_ctl_msg(struct usb_device *dev, unsigned int pipe,
  			  __u8 request, __u8 requesttype,
  			  __u16 value, __u16 index, void *data,
  			  __u16 size, int timeout)
  {
  	int err;
  	void *buf = NULL;
  
  	if (size > 0) {
  		buf = kmemdup(data, size, GFP_KERNEL);
  		if (!buf)
  			return -ENOMEM;
  	}
  	err = usb_control_msg(dev, pipe, request, requesttype,
  			      value, index, buf, size, timeout);
  	if (size > 0) {
  		memcpy(data, buf, size);
  		kfree(buf);
  	}
  	return err;
  }
  
  static void pt_info_set(struct usb_device *dev, u8 v)
  {
  	int ret;
  
  	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
  			      'I',
  			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
  			      v, 0, NULL, 0, 1000);
  	snd_printdd(KERN_DEBUG "%i
  ", ret);
  }
  
  static void usb_stream_hwdep_vm_open(struct vm_area_struct *area)
  {
  	struct us122l *us122l = area->vm_private_data;
  	atomic_inc(&us122l->mmap_count);
  	snd_printdd(KERN_DEBUG "%i
  ", atomic_read(&us122l->mmap_count));
  }
  
  static int usb_stream_hwdep_vm_fault(struct vm_area_struct *area,
  				     struct vm_fault *vmf)
  {
  	unsigned long offset;
  	struct page *page;
  	void *vaddr;
  	struct us122l *us122l = area->vm_private_data;
  	struct usb_stream *s;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
145
146
147
148
  
  	mutex_lock(&us122l->mutex);
  	s = us122l->sk.s;
  	if (!s)
428ffb715   Li Zefan   ALSA: us122l: fix...
149
  		goto unlock;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
150
151
152
153
154
155
156
  
  	offset = vmf->pgoff << PAGE_SHIFT;
  	if (offset < PAGE_ALIGN(s->read_size))
  		vaddr = (char *)s + offset;
  	else {
  		offset -= PAGE_ALIGN(s->read_size);
  		if (offset >= PAGE_ALIGN(s->write_size))
428ffb715   Li Zefan   ALSA: us122l: fix...
157
  			goto unlock;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
158
159
160
161
162
163
164
165
166
  
  		vaddr = us122l->sk.write_page + offset;
  	}
  	page = virt_to_page(vaddr);
  
  	get_page(page);
  	mutex_unlock(&us122l->mutex);
  
  	vmf->page = page;
428ffb715   Li Zefan   ALSA: us122l: fix...
167
168
169
170
171
  
  	return 0;
  unlock:
  	mutex_unlock(&us122l->mutex);
  	return VM_FAULT_SIGBUS;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
172
173
174
175
176
177
178
179
180
  }
  
  static void usb_stream_hwdep_vm_close(struct vm_area_struct *area)
  {
  	struct us122l *us122l = area->vm_private_data;
  	atomic_dec(&us122l->mmap_count);
  	snd_printdd(KERN_DEBUG "%i
  ", atomic_read(&us122l->mmap_count));
  }
f0f37e2f7   Alexey Dobriyan   const: mark struc...
181
  static const struct vm_operations_struct usb_stream_hwdep_vm_ops = {
030a07e44   Karsten Wiese   ALSA: Add USB US1...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  	.open = usb_stream_hwdep_vm_open,
  	.fault = usb_stream_hwdep_vm_fault,
  	.close = usb_stream_hwdep_vm_close,
  };
  
  
  static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
  {
  	struct us122l	*us122l = hw->private_data;
  	struct usb_interface *iface;
  	snd_printdd(KERN_DEBUG "%p %p
  ", hw, file);
  	if (hw->used >= 2)
  		return -EBUSY;
  
  	if (!us122l->first)
  		us122l->first = file;
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
199

2b6f6c0d1   Tobias Hansen   ALSA: snd-usb-us1...
200
201
  	if (us122l->dev->descriptor.idProduct == USB_ID_US144 ||
  	    us122l->dev->descriptor.idProduct == USB_ID_US144MKII) {
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
202
  		iface = usb_ifnum_to_if(us122l->dev, 0);
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
203
204
  		usb_autopm_get_interface(iface);
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
205
  	iface = usb_ifnum_to_if(us122l->dev, 1);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
206
207
208
209
210
211
212
  	usb_autopm_get_interface(iface);
  	return 0;
  }
  
  static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file)
  {
  	struct us122l	*us122l = hw->private_data;
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
213
  	struct usb_interface *iface;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
214
215
  	snd_printdd(KERN_DEBUG "%p %p
  ", hw, file);
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
216

2b6f6c0d1   Tobias Hansen   ALSA: snd-usb-us1...
217
218
  	if (us122l->dev->descriptor.idProduct == USB_ID_US144 ||
  	    us122l->dev->descriptor.idProduct == USB_ID_US144MKII) {
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
219
  		iface = usb_ifnum_to_if(us122l->dev, 0);
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
220
221
  		usb_autopm_put_interface(iface);
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
222
  	iface = usb_ifnum_to_if(us122l->dev, 1);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  	usb_autopm_put_interface(iface);
  	if (us122l->first == file)
  		us122l->first = NULL;
  	mutex_lock(&us122l->mutex);
  	if (us122l->master == file)
  		us122l->master = us122l->slave;
  
  	us122l->slave = NULL;
  	mutex_unlock(&us122l->mutex);
  	return 0;
  }
  
  static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
  				 struct file *filp, struct vm_area_struct *area)
  {
  	unsigned long	size = area->vm_end - area->vm_start;
  	struct us122l	*us122l = hw->private_data;
  	unsigned long offset;
  	struct usb_stream *s;
  	int err = 0;
  	bool read;
  
  	offset = area->vm_pgoff << PAGE_SHIFT;
  	mutex_lock(&us122l->mutex);
  	s = us122l->sk.s;
  	read = offset < s->read_size;
  	if (read && area->vm_flags & VM_WRITE) {
  		err = -EPERM;
  		goto out;
  	}
  	snd_printdd(KERN_DEBUG "%lu %u
  ", size,
  		    read ? s->read_size : s->write_size);
  	/* if userspace tries to mmap beyond end of our buffer, fail */
  	if (size > PAGE_ALIGN(read ? s->read_size : s->write_size)) {
  		snd_printk(KERN_WARNING "%lu > %u
  ", size,
  			   read ? s->read_size : s->write_size);
  		err = -EINVAL;
  		goto out;
  	}
  
  	area->vm_ops = &usb_stream_hwdep_vm_ops;
  	area->vm_flags |= VM_RESERVED;
  	area->vm_private_data = us122l;
  	atomic_inc(&us122l->mmap_count);
  out:
  	mutex_unlock(&us122l->mutex);
  	return err;
  }
  
  static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw,
  					  struct file *file, poll_table *wait)
  {
  	struct us122l	*us122l = hw->private_data;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
278
279
280
281
  	unsigned	*polled;
  	unsigned int	mask;
  
  	poll_wait(file, &us122l->sk.sleep, wait);
cdce2db74   Karsten Wiese   ALSA: snd-usb-us1...
282
283
284
285
286
287
288
289
290
291
292
293
294
  	mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR;
  	if (mutex_trylock(&us122l->mutex)) {
  		struct usb_stream *s = us122l->sk.s;
  		if (s && s->state == usb_stream_ready) {
  			if (us122l->first == file)
  				polled = &s->periods_polled;
  			else
  				polled = &us122l->second_periods_polled;
  			if (*polled != s->periods_done) {
  				*polled = s->periods_done;
  				mask = POLLIN | POLLOUT | POLLWRNORM;
  			} else
  				mask = 0;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
295
  		}
cdce2db74   Karsten Wiese   ALSA: snd-usb-us1...
296
  		mutex_unlock(&us122l->mutex);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
297
298
299
300
301
302
303
  	}
  	return mask;
  }
  
  static void us122l_stop(struct us122l *us122l)
  {
  	struct list_head *p;
d82af9f9a   Clemens Ladisch   sound: usb: make ...
304
  	list_for_each(p, &us122l->midi_list)
030a07e44   Karsten Wiese   ALSA: Add USB US1...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  		snd_usbmidi_input_stop(p);
  
  	usb_stream_stop(&us122l->sk);
  	usb_stream_free(&us122l->sk);
  }
  
  static int us122l_set_sample_rate(struct usb_device *dev, int rate)
  {
  	unsigned int ep = 0x81;
  	unsigned char data[3];
  	int err;
  
  	data[0] = rate;
  	data[1] = rate >> 8;
  	data[2] = rate >> 16;
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
320
  	err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
030a07e44   Karsten Wiese   ALSA: Add USB US1...
321
  			     USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
322
  			     UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  	if (err < 0)
  		snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x
  ",
  			   dev->devnum, rate, ep);
  	return err;
  }
  
  static bool us122l_start(struct us122l *us122l,
  			 unsigned rate, unsigned period_frames)
  {
  	struct list_head *p;
  	int err;
  	unsigned use_packsize = 0;
  	bool success = false;
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
337
  	if (us122l->dev->speed == USB_SPEED_HIGH) {
030a07e44   Karsten Wiese   ALSA: Add USB US1...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  		/* The us-122l's descriptor defaults to iso max_packsize 78,
  		   which isn't needed for samplerates <= 48000.
  		   Lets save some memory:
  		*/
  		switch (rate) {
  		case 44100:
  			use_packsize = 36;
  			break;
  		case 48000:
  			use_packsize = 42;
  			break;
  		case 88200:
  			use_packsize = 72;
  			break;
  		}
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
354
  	if (!usb_stream_new(&us122l->sk, us122l->dev, 1, 2,
030a07e44   Karsten Wiese   ALSA: Add USB US1...
355
356
  			    rate, use_packsize, period_frames, 6))
  		goto out;
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
357
  	err = us122l_set_sample_rate(us122l->dev, rate);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
358
359
360
361
362
363
364
365
366
367
368
369
370
  	if (err < 0) {
  		us122l_stop(us122l);
  		snd_printk(KERN_ERR "us122l_set_sample_rate error 
  ");
  		goto out;
  	}
  	err = usb_stream_start(&us122l->sk);
  	if (err < 0) {
  		us122l_stop(us122l);
  		snd_printk(KERN_ERR "us122l_start error %i 
  ", err);
  		goto out;
  	}
d82af9f9a   Clemens Ladisch   sound: usb: make ...
371
  	list_for_each(p, &us122l->midi_list)
030a07e44   Karsten Wiese   ALSA: Add USB US1...
372
373
374
375
376
377
378
379
380
381
382
  		snd_usbmidi_input_start(p);
  	success = true;
  out:
  	return success;
  }
  
  static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
  				  unsigned cmd, unsigned long arg)
  {
  	struct usb_stream_config *cfg;
  	struct us122l *us122l = hw->private_data;
cdce2db74   Karsten Wiese   ALSA: snd-usb-us1...
383
  	struct usb_stream *s;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
384
385
386
387
388
389
  	unsigned min_period_frames;
  	int err = 0;
  	bool high_speed;
  
  	if (cmd != SNDRV_USB_STREAM_IOCTL_SET_PARAMS)
  		return -ENOTTY;
85385c155   Li Zefan   ALSA: sound/usb: ...
390
391
392
  	cfg = memdup_user((void *)arg, sizeof(*cfg));
  	if (IS_ERR(cfg))
  		return PTR_ERR(cfg);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
393

030a07e44   Karsten Wiese   ALSA: Add USB US1...
394
395
396
397
  	if (cfg->version != USB_STREAM_INTERFACE_VERSION) {
  		err = -ENXIO;
  		goto free;
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
398
  	high_speed = us122l->dev->speed == USB_SPEED_HIGH;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  	if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000  &&
  	     (!high_speed ||
  	      (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) ||
  	    cfg->frame_size != 6 ||
  	    cfg->period_frames > 0x3000) {
  		err = -EINVAL;
  		goto free;
  	}
  	switch (cfg->sample_rate) {
  	case 44100:
  		min_period_frames = 48;
  		break;
  	case 48000:
  		min_period_frames = 52;
  		break;
  	default:
  		min_period_frames = 104;
  		break;
  	}
  	if (!high_speed)
  		min_period_frames <<= 1;
  	if (cfg->period_frames < min_period_frames) {
  		err = -EINVAL;
  		goto free;
  	}
  
  	snd_power_wait(hw->card, SNDRV_CTL_POWER_D0);
  
  	mutex_lock(&us122l->mutex);
cdce2db74   Karsten Wiese   ALSA: snd-usb-us1...
428
  	s = us122l->sk.s;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
429
430
431
  	if (!us122l->master)
  		us122l->master = file;
  	else if (us122l->master != file) {
cdce2db74   Karsten Wiese   ALSA: snd-usb-us1...
432
  		if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg))) {
030a07e44   Karsten Wiese   ALSA: Add USB US1...
433
434
435
436
437
  			err = -EIO;
  			goto unlock;
  		}
  		us122l->slave = file;
  	}
cdce2db74   Karsten Wiese   ALSA: snd-usb-us1...
438
439
  	if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg)) ||
  	    s->state == usb_stream_xrun) {
030a07e44   Karsten Wiese   ALSA: Add USB US1...
440
441
442
443
444
445
446
447
448
449
  		us122l_stop(us122l);
  		if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames))
  			err = -EIO;
  		else
  			err = 1;
  	}
  unlock:
  	mutex_unlock(&us122l->mutex);
  free:
  	kfree(cfg);
cdce2db74   Karsten Wiese   ALSA: snd-usb-us1...
450
  	wake_up_all(&us122l->sk.sleep);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
451
452
453
454
455
456
457
458
  	return err;
  }
  
  #define SND_USB_STREAM_ID "USB STREAM"
  static int usb_stream_hwdep_new(struct snd_card *card)
  {
  	int err;
  	struct snd_hwdep *hw;
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
459
  	struct usb_device *dev = US122L(card)->dev;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  
  	err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw);
  	if (err < 0)
  		return err;
  
  	hw->iface = SNDRV_HWDEP_IFACE_USB_STREAM;
  	hw->private_data = US122L(card);
  	hw->ops.open = usb_stream_hwdep_open;
  	hw->ops.release = usb_stream_hwdep_release;
  	hw->ops.ioctl = usb_stream_hwdep_ioctl;
  	hw->ops.ioctl_compat = usb_stream_hwdep_ioctl;
  	hw->ops.mmap = usb_stream_hwdep_mmap;
  	hw->ops.poll = usb_stream_hwdep_poll;
  
  	sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm",
  		dev->bus->busnum, dev->devnum);
  	return 0;
  }
  
  
  static bool us122l_create_card(struct snd_card *card)
  {
  	int err;
  	struct us122l *us122l = US122L(card);
2b6f6c0d1   Tobias Hansen   ALSA: snd-usb-us1...
484
485
  	if (us122l->dev->descriptor.idProduct == USB_ID_US144 ||
  	    us122l->dev->descriptor.idProduct == USB_ID_US144MKII) {
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
486
  		err = usb_set_interface(us122l->dev, 0, 1);
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
487
488
489
490
491
492
  		if (err) {
  			snd_printk(KERN_ERR "usb_set_interface error 
  ");
  			return false;
  		}
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
493
  	err = usb_set_interface(us122l->dev, 1, 1);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
494
495
496
497
498
  	if (err) {
  		snd_printk(KERN_ERR "usb_set_interface error 
  ");
  		return false;
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
499
500
  	pt_info_set(us122l->dev, 0x11);
  	pt_info_set(us122l->dev, 0x10);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
501
502
503
  
  	if (!us122l_start(us122l, 44100, 256))
  		return false;
2b6f6c0d1   Tobias Hansen   ALSA: snd-usb-us1...
504
505
  	if (us122l->dev->descriptor.idProduct == USB_ID_US144 ||
  	    us122l->dev->descriptor.idProduct == USB_ID_US144MKII)
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
506
507
508
  		err = us144_create_usbmidi(card);
  	else
  		err = us122l_create_usbmidi(card);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
509
510
511
512
513
514
515
516
517
518
  	if (err < 0) {
  		snd_printk(KERN_ERR "us122l_create_usbmidi error %i 
  ", err);
  		us122l_stop(us122l);
  		return false;
  	}
  	err = usb_stream_hwdep_new(card);
  	if (err < 0) {
  /* release the midi resources */
  		struct list_head *p;
d82af9f9a   Clemens Ladisch   sound: usb: make ...
519
  		list_for_each(p, &us122l->midi_list)
030a07e44   Karsten Wiese   ALSA: Add USB US1...
520
521
522
523
524
525
526
  			snd_usbmidi_disconnect(p);
  
  		us122l_stop(us122l);
  		return false;
  	}
  	return true;
  }
5d4af1be0   Karsten Wiese   ALSA: us122l: add...
527
528
529
  static void snd_us122l_free(struct snd_card *card)
  {
  	struct us122l	*us122l = US122L(card);
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
530
  	int		index = us122l->card_index;
5d4af1be0   Karsten Wiese   ALSA: us122l: add...
531
532
533
  	if (index >= 0  &&  index < SNDRV_CARDS)
  		snd_us122l_card_used[index] = 0;
  }
51721f70a   Takashi Iwai   ALSA: Return prop...
534
  static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
030a07e44   Karsten Wiese   ALSA: Add USB US1...
535
536
537
  {
  	int		dev;
  	struct snd_card *card;
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
538
  	int err;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
539
540
541
542
  	for (dev = 0; dev < SNDRV_CARDS; ++dev)
  		if (enable[dev] && !snd_us122l_card_used[dev])
  			break;
  	if (dev >= SNDRV_CARDS)
51721f70a   Takashi Iwai   ALSA: Return prop...
543
  		return -ENODEV;
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
544
545
546
  	err = snd_card_create(index[dev], id[dev], THIS_MODULE,
  			      sizeof(struct us122l), &card);
  	if (err < 0)
51721f70a   Takashi Iwai   ALSA: Return prop...
547
  		return err;
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
548
  	snd_us122l_card_used[US122L(card)->card_index = dev] = 1;
5d4af1be0   Karsten Wiese   ALSA: us122l: add...
549
  	card->private_free = snd_us122l_free;
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
550
  	US122L(card)->dev = device;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
551
552
  	mutex_init(&US122L(card)->mutex);
  	init_waitqueue_head(&US122L(card)->sk.sleep);
d82af9f9a   Clemens Ladisch   sound: usb: make ...
553
  	INIT_LIST_HEAD(&US122L(card)->midi_list);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
554
555
556
557
558
559
560
  	strcpy(card->driver, "USB "NAME_ALLCAPS"");
  	sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
  	sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
  		card->shortname,
  		le16_to_cpu(device->descriptor.idVendor),
  		le16_to_cpu(device->descriptor.idProduct),
  		0,
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
561
562
  		US122L(card)->dev->bus->busnum,
  		US122L(card)->dev->devnum
030a07e44   Karsten Wiese   ALSA: Add USB US1...
563
  		);
51721f70a   Takashi Iwai   ALSA: Return prop...
564
565
  	*cardp = card;
  	return 0;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
566
  }
51721f70a   Takashi Iwai   ALSA: Return prop...
567
568
569
  static int us122l_usb_probe(struct usb_interface *intf,
  			    const struct usb_device_id *device_id,
  			    struct snd_card **cardp)
030a07e44   Karsten Wiese   ALSA: Add USB US1...
570
571
  {
  	struct usb_device *device = interface_to_usbdev(intf);
51721f70a   Takashi Iwai   ALSA: Return prop...
572
573
  	struct snd_card *card;
  	int err;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
574

51721f70a   Takashi Iwai   ALSA: Return prop...
575
576
577
  	err = usx2y_create_card(device, &card);
  	if (err < 0)
  		return err;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
578

3f5d3465b   Takashi Iwai   ALSA: usx2y - rep...
579
  	snd_card_set_dev(card, &intf->dev);
51721f70a   Takashi Iwai   ALSA: Return prop...
580
  	if (!us122l_create_card(card)) {
030a07e44   Karsten Wiese   ALSA: Add USB US1...
581
  		snd_card_free(card);
51721f70a   Takashi Iwai   ALSA: Return prop...
582
583
584
585
586
587
588
  		return -EINVAL;
  	}
  
  	err = snd_card_register(card);
  	if (err < 0) {
  		snd_card_free(card);
  		return err;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
589
  	}
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
590
  	usb_get_intf(usb_ifnum_to_if(device, 0));
030a07e44   Karsten Wiese   ALSA: Add USB US1...
591
  	usb_get_dev(device);
51721f70a   Takashi Iwai   ALSA: Return prop...
592
593
  	*cardp = card;
  	return 0;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
594
595
596
597
598
  }
  
  static int snd_us122l_probe(struct usb_interface *intf,
  			    const struct usb_device_id *id)
  {
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
599
  	struct usb_device *device = interface_to_usbdev(intf);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
600
  	struct snd_card *card;
51721f70a   Takashi Iwai   ALSA: Return prop...
601
  	int err;
2b6f6c0d1   Tobias Hansen   ALSA: snd-usb-us1...
602
603
  	if ((device->descriptor.idProduct == USB_ID_US144 ||
  	     device->descriptor.idProduct == USB_ID_US144MKII)
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
604
605
606
  		&& device->speed == USB_SPEED_HIGH) {
  		snd_printk(KERN_ERR "disable ehci-hcd to run US-144 
  ");
a688e4885   Tobias Hansen   ALSA: snd-usb-us1...
607
  		return -ENODEV;
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
608
  	}
030a07e44   Karsten Wiese   ALSA: Add USB US1...
609
610
611
612
613
  	snd_printdd(KERN_DEBUG"%p:%i
  ",
  		    intf, intf->cur_altsetting->desc.bInterfaceNumber);
  	if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
  		return 0;
51721f70a   Takashi Iwai   ALSA: Return prop...
614
615
616
617
  	err = us122l_usb_probe(usb_get_intf(intf), id, &card);
  	if (err < 0) {
  		usb_put_intf(intf);
  		return err;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
618
  	}
51721f70a   Takashi Iwai   ALSA: Return prop...
619
620
  	usb_set_intfdata(intf, card);
  	return 0;
030a07e44   Karsten Wiese   ALSA: Add USB US1...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  }
  
  static void snd_us122l_disconnect(struct usb_interface *intf)
  {
  	struct snd_card *card;
  	struct us122l *us122l;
  	struct list_head *p;
  
  	card = usb_get_intfdata(intf);
  	if (!card)
  		return;
  
  	snd_card_disconnect(card);
  
  	us122l = US122L(card);
  	mutex_lock(&us122l->mutex);
  	us122l_stop(us122l);
  	mutex_unlock(&us122l->mutex);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
639
640
  
  /* release the midi resources */
d82af9f9a   Clemens Ladisch   sound: usb: make ...
641
  	list_for_each(p, &us122l->midi_list) {
030a07e44   Karsten Wiese   ALSA: Add USB US1...
642
643
  		snd_usbmidi_disconnect(p);
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
644
645
646
  	usb_put_intf(usb_ifnum_to_if(us122l->dev, 0));
  	usb_put_intf(usb_ifnum_to_if(us122l->dev, 1));
  	usb_put_dev(us122l->dev);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
647
648
649
650
651
652
653
654
655
656
657
658
  
  	while (atomic_read(&us122l->mmap_count))
  		msleep(500);
  
  	snd_card_free(card);
  }
  
  static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message)
  {
  	struct snd_card *card;
  	struct us122l *us122l;
  	struct list_head *p;
f4e9749f4   Julia Lawall   ALSA: Use usb_set...
659
  	card = usb_get_intfdata(intf);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
660
661
662
663
664
665
666
  	if (!card)
  		return 0;
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
  
  	us122l = US122L(card);
  	if (!us122l)
  		return 0;
d82af9f9a   Clemens Ladisch   sound: usb: make ...
667
  	list_for_each(p, &us122l->midi_list)
030a07e44   Karsten Wiese   ALSA: Add USB US1...
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
  		snd_usbmidi_input_stop(p);
  
  	mutex_lock(&us122l->mutex);
  	usb_stream_stop(&us122l->sk);
  	mutex_unlock(&us122l->mutex);
  
  	return 0;
  }
  
  static int snd_us122l_resume(struct usb_interface *intf)
  {
  	struct snd_card *card;
  	struct us122l *us122l;
  	struct list_head *p;
  	int err;
f4e9749f4   Julia Lawall   ALSA: Use usb_set...
683
  	card = usb_get_intfdata(intf);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
684
685
686
687
688
689
690
691
692
  	if (!card)
  		return 0;
  
  	us122l = US122L(card);
  	if (!us122l)
  		return 0;
  
  	mutex_lock(&us122l->mutex);
  	/* needed, doesn't restart without: */
2b6f6c0d1   Tobias Hansen   ALSA: snd-usb-us1...
693
694
  	if (us122l->dev->descriptor.idProduct == USB_ID_US144 ||
  	    us122l->dev->descriptor.idProduct == USB_ID_US144MKII) {
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
695
  		err = usb_set_interface(us122l->dev, 0, 1);
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
696
697
698
699
700
701
  		if (err) {
  			snd_printk(KERN_ERR "usb_set_interface error 
  ");
  			goto unlock;
  		}
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
702
  	err = usb_set_interface(us122l->dev, 1, 1);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
703
704
705
706
707
  	if (err) {
  		snd_printk(KERN_ERR "usb_set_interface error 
  ");
  		goto unlock;
  	}
a014bbadb   Clemens Ladisch   sound: usxxx: cle...
708
709
  	pt_info_set(us122l->dev, 0x11);
  	pt_info_set(us122l->dev, 0x10);
030a07e44   Karsten Wiese   ALSA: Add USB US1...
710

a014bbadb   Clemens Ladisch   sound: usxxx: cle...
711
  	err = us122l_set_sample_rate(us122l->dev,
030a07e44   Karsten Wiese   ALSA: Add USB US1...
712
713
714
715
716
717
718
719
720
  				     us122l->sk.s->cfg.sample_rate);
  	if (err < 0) {
  		snd_printk(KERN_ERR "us122l_set_sample_rate error 
  ");
  		goto unlock;
  	}
  	err = usb_stream_start(&us122l->sk);
  	if (err)
  		goto unlock;
d82af9f9a   Clemens Ladisch   sound: usb: make ...
721
  	list_for_each(p, &us122l->midi_list)
030a07e44   Karsten Wiese   ALSA: Add USB US1...
722
723
724
725
726
727
728
729
730
731
732
733
734
  		snd_usbmidi_input_start(p);
  unlock:
  	mutex_unlock(&us122l->mutex);
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
  	return err;
  }
  
  static struct usb_device_id snd_us122l_usb_id_table[] = {
  	{
  		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
  		.idVendor =	0x0644,
  		.idProduct =	USB_ID_US122L
  	},
4f272341c   Tobias Hansen   ALSA: snd-usb-us1...
735
736
737
738
739
  	{	/* US-144 only works at USB1.1! Disable module ehci-hcd. */
  		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
  		.idVendor =	0x0644,
  		.idProduct =	USB_ID_US144
  	},
2b6f6c0d1   Tobias Hansen   ALSA: snd-usb-us1...
740
741
742
743
744
745
746
747
748
749
  	{
  		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
  		.idVendor =	0x0644,
  		.idProduct =	USB_ID_US122MKII
  	},
  	{
  		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
  		.idVendor =	0x0644,
  		.idProduct =	USB_ID_US144MKII
  	},
030a07e44   Karsten Wiese   ALSA: Add USB US1...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  	{ /* terminator */ }
  };
  
  MODULE_DEVICE_TABLE(usb, snd_us122l_usb_id_table);
  static struct usb_driver snd_us122l_usb_driver = {
  	.name =		"snd-usb-us122l",
  	.probe =	snd_us122l_probe,
  	.disconnect =	snd_us122l_disconnect,
  	.suspend =	snd_us122l_suspend,
  	.resume =	snd_us122l_resume,
  	.reset_resume =	snd_us122l_resume,
  	.id_table =	snd_us122l_usb_id_table,
  	.supports_autosuspend = 1
  };
424f0750e   Greg Kroah-Hartman   USB: convert soun...
764
  module_usb_driver(snd_us122l_usb_driver);