xref: /OK3568_Linux_fs/kernel/sound/usb/usx2y/us122l.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/slab.h>
7*4882a593Smuzhiyun #include <linux/usb.h>
8*4882a593Smuzhiyun #include <linux/usb/audio.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <sound/core.h>
11*4882a593Smuzhiyun #include <sound/hwdep.h>
12*4882a593Smuzhiyun #include <sound/pcm.h>
13*4882a593Smuzhiyun #include <sound/initval.h>
14*4882a593Smuzhiyun #define MODNAME "US122L"
15*4882a593Smuzhiyun #include "usb_stream.c"
16*4882a593Smuzhiyun #include "../usbaudio.h"
17*4882a593Smuzhiyun #include "../midi.h"
18*4882a593Smuzhiyun #include "us122l.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun MODULE_AUTHOR("Karsten Wiese <fzu@wemgehoertderstaat.de>");
21*4882a593Smuzhiyun MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.5");
22*4882a593Smuzhiyun MODULE_LICENSE("GPL");
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-max */
25*4882a593Smuzhiyun static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* Id for this card */
26*4882a593Smuzhiyun 							/* Enable this card */
27*4882a593Smuzhiyun static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun module_param_array(index, int, NULL, 0444);
30*4882a593Smuzhiyun MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
31*4882a593Smuzhiyun module_param_array(id, charp, NULL, 0444);
32*4882a593Smuzhiyun MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS".");
33*4882a593Smuzhiyun module_param_array(enable, bool, NULL, 0444);
34*4882a593Smuzhiyun MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS".");
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* driver_info flags */
37*4882a593Smuzhiyun #define US122L_FLAG_US144	BIT(0)
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun static int snd_us122l_card_used[SNDRV_CARDS];
40*4882a593Smuzhiyun 
us122l_create_usbmidi(struct snd_card * card)41*4882a593Smuzhiyun static int us122l_create_usbmidi(struct snd_card *card)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	static const struct snd_usb_midi_endpoint_info quirk_data = {
44*4882a593Smuzhiyun 		.out_ep = 4,
45*4882a593Smuzhiyun 		.in_ep = 3,
46*4882a593Smuzhiyun 		.out_cables =	0x001,
47*4882a593Smuzhiyun 		.in_cables =	0x001
48*4882a593Smuzhiyun 	};
49*4882a593Smuzhiyun 	static const struct snd_usb_audio_quirk quirk = {
50*4882a593Smuzhiyun 		.vendor_name =	"US122L",
51*4882a593Smuzhiyun 		.product_name =	NAME_ALLCAPS,
52*4882a593Smuzhiyun 		.ifnum = 	1,
53*4882a593Smuzhiyun 		.type = QUIRK_MIDI_US122L,
54*4882a593Smuzhiyun 		.data = &quirk_data
55*4882a593Smuzhiyun 	};
56*4882a593Smuzhiyun 	struct usb_device *dev = US122L(card)->dev;
57*4882a593Smuzhiyun 	struct usb_interface *iface = usb_ifnum_to_if(dev, 1);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	return snd_usbmidi_create(card, iface,
60*4882a593Smuzhiyun 				  &US122L(card)->midi_list, &quirk);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
us144_create_usbmidi(struct snd_card * card)63*4882a593Smuzhiyun static int us144_create_usbmidi(struct snd_card *card)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	static const struct snd_usb_midi_endpoint_info quirk_data = {
66*4882a593Smuzhiyun 		.out_ep = 4,
67*4882a593Smuzhiyun 		.in_ep = 3,
68*4882a593Smuzhiyun 		.out_cables =	0x001,
69*4882a593Smuzhiyun 		.in_cables =	0x001
70*4882a593Smuzhiyun 	};
71*4882a593Smuzhiyun 	static const struct snd_usb_audio_quirk quirk = {
72*4882a593Smuzhiyun 		.vendor_name =	"US144",
73*4882a593Smuzhiyun 		.product_name =	NAME_ALLCAPS,
74*4882a593Smuzhiyun 		.ifnum = 	0,
75*4882a593Smuzhiyun 		.type = QUIRK_MIDI_US122L,
76*4882a593Smuzhiyun 		.data = &quirk_data
77*4882a593Smuzhiyun 	};
78*4882a593Smuzhiyun 	struct usb_device *dev = US122L(card)->dev;
79*4882a593Smuzhiyun 	struct usb_interface *iface = usb_ifnum_to_if(dev, 0);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return snd_usbmidi_create(card, iface,
82*4882a593Smuzhiyun 				  &US122L(card)->midi_list, &quirk);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
pt_info_set(struct usb_device * dev,u8 v)85*4882a593Smuzhiyun static void pt_info_set(struct usb_device *dev, u8 v)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	int ret;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	ret = usb_control_msg_send(dev, 0, 'I',
90*4882a593Smuzhiyun 				   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
91*4882a593Smuzhiyun 				   v, 0, NULL, 0, 1000, GFP_NOIO);
92*4882a593Smuzhiyun 	snd_printdd(KERN_DEBUG "%i\n", ret);
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
usb_stream_hwdep_vm_open(struct vm_area_struct * area)95*4882a593Smuzhiyun static void usb_stream_hwdep_vm_open(struct vm_area_struct *area)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	struct us122l *us122l = area->vm_private_data;
98*4882a593Smuzhiyun 	atomic_inc(&us122l->mmap_count);
99*4882a593Smuzhiyun 	snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
usb_stream_hwdep_vm_fault(struct vm_fault * vmf)102*4882a593Smuzhiyun static vm_fault_t usb_stream_hwdep_vm_fault(struct vm_fault *vmf)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	unsigned long offset;
105*4882a593Smuzhiyun 	struct page *page;
106*4882a593Smuzhiyun 	void *vaddr;
107*4882a593Smuzhiyun 	struct us122l *us122l = vmf->vma->vm_private_data;
108*4882a593Smuzhiyun 	struct usb_stream *s;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	mutex_lock(&us122l->mutex);
111*4882a593Smuzhiyun 	s = us122l->sk.s;
112*4882a593Smuzhiyun 	if (!s)
113*4882a593Smuzhiyun 		goto unlock;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	offset = vmf->pgoff << PAGE_SHIFT;
116*4882a593Smuzhiyun 	if (offset < PAGE_ALIGN(s->read_size))
117*4882a593Smuzhiyun 		vaddr = (char *)s + offset;
118*4882a593Smuzhiyun 	else {
119*4882a593Smuzhiyun 		offset -= PAGE_ALIGN(s->read_size);
120*4882a593Smuzhiyun 		if (offset >= PAGE_ALIGN(s->write_size))
121*4882a593Smuzhiyun 			goto unlock;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 		vaddr = us122l->sk.write_page + offset;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	page = virt_to_page(vaddr);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	get_page(page);
128*4882a593Smuzhiyun 	mutex_unlock(&us122l->mutex);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	vmf->page = page;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun unlock:
134*4882a593Smuzhiyun 	mutex_unlock(&us122l->mutex);
135*4882a593Smuzhiyun 	return VM_FAULT_SIGBUS;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
usb_stream_hwdep_vm_close(struct vm_area_struct * area)138*4882a593Smuzhiyun static void usb_stream_hwdep_vm_close(struct vm_area_struct *area)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	struct us122l *us122l = area->vm_private_data;
141*4882a593Smuzhiyun 	atomic_dec(&us122l->mmap_count);
142*4882a593Smuzhiyun 	snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun static const struct vm_operations_struct usb_stream_hwdep_vm_ops = {
146*4882a593Smuzhiyun 	.open = usb_stream_hwdep_vm_open,
147*4882a593Smuzhiyun 	.fault = usb_stream_hwdep_vm_fault,
148*4882a593Smuzhiyun 	.close = usb_stream_hwdep_vm_close,
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 
usb_stream_hwdep_open(struct snd_hwdep * hw,struct file * file)152*4882a593Smuzhiyun static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	struct us122l	*us122l = hw->private_data;
155*4882a593Smuzhiyun 	struct usb_interface *iface;
156*4882a593Smuzhiyun 	snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
157*4882a593Smuzhiyun 	if (hw->used >= 2)
158*4882a593Smuzhiyun 		return -EBUSY;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	if (!us122l->first)
161*4882a593Smuzhiyun 		us122l->first = file;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (us122l->is_us144) {
164*4882a593Smuzhiyun 		iface = usb_ifnum_to_if(us122l->dev, 0);
165*4882a593Smuzhiyun 		usb_autopm_get_interface(iface);
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 	iface = usb_ifnum_to_if(us122l->dev, 1);
168*4882a593Smuzhiyun 	usb_autopm_get_interface(iface);
169*4882a593Smuzhiyun 	return 0;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
usb_stream_hwdep_release(struct snd_hwdep * hw,struct file * file)172*4882a593Smuzhiyun static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	struct us122l	*us122l = hw->private_data;
175*4882a593Smuzhiyun 	struct usb_interface *iface;
176*4882a593Smuzhiyun 	snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (us122l->is_us144) {
179*4882a593Smuzhiyun 		iface = usb_ifnum_to_if(us122l->dev, 0);
180*4882a593Smuzhiyun 		usb_autopm_put_interface(iface);
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 	iface = usb_ifnum_to_if(us122l->dev, 1);
183*4882a593Smuzhiyun 	usb_autopm_put_interface(iface);
184*4882a593Smuzhiyun 	if (us122l->first == file)
185*4882a593Smuzhiyun 		us122l->first = NULL;
186*4882a593Smuzhiyun 	mutex_lock(&us122l->mutex);
187*4882a593Smuzhiyun 	if (us122l->master == file)
188*4882a593Smuzhiyun 		us122l->master = us122l->slave;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	us122l->slave = NULL;
191*4882a593Smuzhiyun 	mutex_unlock(&us122l->mutex);
192*4882a593Smuzhiyun 	return 0;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
usb_stream_hwdep_mmap(struct snd_hwdep * hw,struct file * filp,struct vm_area_struct * area)195*4882a593Smuzhiyun static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
196*4882a593Smuzhiyun 				 struct file *filp, struct vm_area_struct *area)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	unsigned long	size = area->vm_end - area->vm_start;
199*4882a593Smuzhiyun 	struct us122l	*us122l = hw->private_data;
200*4882a593Smuzhiyun 	unsigned long offset;
201*4882a593Smuzhiyun 	struct usb_stream *s;
202*4882a593Smuzhiyun 	int err = 0;
203*4882a593Smuzhiyun 	bool read;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	offset = area->vm_pgoff << PAGE_SHIFT;
206*4882a593Smuzhiyun 	mutex_lock(&us122l->mutex);
207*4882a593Smuzhiyun 	s = us122l->sk.s;
208*4882a593Smuzhiyun 	read = offset < s->read_size;
209*4882a593Smuzhiyun 	if (read && area->vm_flags & VM_WRITE) {
210*4882a593Smuzhiyun 		err = -EPERM;
211*4882a593Smuzhiyun 		goto out;
212*4882a593Smuzhiyun 	}
213*4882a593Smuzhiyun 	snd_printdd(KERN_DEBUG "%lu %u\n", size,
214*4882a593Smuzhiyun 		    read ? s->read_size : s->write_size);
215*4882a593Smuzhiyun 	/* if userspace tries to mmap beyond end of our buffer, fail */
216*4882a593Smuzhiyun 	if (size > PAGE_ALIGN(read ? s->read_size : s->write_size)) {
217*4882a593Smuzhiyun 		snd_printk(KERN_WARNING "%lu > %u\n", size,
218*4882a593Smuzhiyun 			   read ? s->read_size : s->write_size);
219*4882a593Smuzhiyun 		err = -EINVAL;
220*4882a593Smuzhiyun 		goto out;
221*4882a593Smuzhiyun 	}
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	area->vm_ops = &usb_stream_hwdep_vm_ops;
224*4882a593Smuzhiyun 	area->vm_flags |= VM_DONTDUMP;
225*4882a593Smuzhiyun 	if (!read)
226*4882a593Smuzhiyun 		area->vm_flags |= VM_DONTEXPAND;
227*4882a593Smuzhiyun 	area->vm_private_data = us122l;
228*4882a593Smuzhiyun 	atomic_inc(&us122l->mmap_count);
229*4882a593Smuzhiyun out:
230*4882a593Smuzhiyun 	mutex_unlock(&us122l->mutex);
231*4882a593Smuzhiyun 	return err;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
usb_stream_hwdep_poll(struct snd_hwdep * hw,struct file * file,poll_table * wait)234*4882a593Smuzhiyun static __poll_t usb_stream_hwdep_poll(struct snd_hwdep *hw,
235*4882a593Smuzhiyun 					  struct file *file, poll_table *wait)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	struct us122l	*us122l = hw->private_data;
238*4882a593Smuzhiyun 	unsigned	*polled;
239*4882a593Smuzhiyun 	__poll_t	mask;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	poll_wait(file, &us122l->sk.sleep, wait);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	mask = EPOLLIN | EPOLLOUT | EPOLLWRNORM | EPOLLERR;
244*4882a593Smuzhiyun 	if (mutex_trylock(&us122l->mutex)) {
245*4882a593Smuzhiyun 		struct usb_stream *s = us122l->sk.s;
246*4882a593Smuzhiyun 		if (s && s->state == usb_stream_ready) {
247*4882a593Smuzhiyun 			if (us122l->first == file)
248*4882a593Smuzhiyun 				polled = &s->periods_polled;
249*4882a593Smuzhiyun 			else
250*4882a593Smuzhiyun 				polled = &us122l->second_periods_polled;
251*4882a593Smuzhiyun 			if (*polled != s->periods_done) {
252*4882a593Smuzhiyun 				*polled = s->periods_done;
253*4882a593Smuzhiyun 				mask = EPOLLIN | EPOLLOUT | EPOLLWRNORM;
254*4882a593Smuzhiyun 			} else
255*4882a593Smuzhiyun 				mask = 0;
256*4882a593Smuzhiyun 		}
257*4882a593Smuzhiyun 		mutex_unlock(&us122l->mutex);
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 	return mask;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
us122l_stop(struct us122l * us122l)262*4882a593Smuzhiyun static void us122l_stop(struct us122l *us122l)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	struct list_head *p;
265*4882a593Smuzhiyun 	list_for_each(p, &us122l->midi_list)
266*4882a593Smuzhiyun 		snd_usbmidi_input_stop(p);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	usb_stream_stop(&us122l->sk);
269*4882a593Smuzhiyun 	usb_stream_free(&us122l->sk);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
us122l_set_sample_rate(struct usb_device * dev,int rate)272*4882a593Smuzhiyun static int us122l_set_sample_rate(struct usb_device *dev, int rate)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	unsigned int ep = 0x81;
275*4882a593Smuzhiyun 	unsigned char data[3];
276*4882a593Smuzhiyun 	int err;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	data[0] = rate;
279*4882a593Smuzhiyun 	data[1] = rate >> 8;
280*4882a593Smuzhiyun 	data[2] = rate >> 16;
281*4882a593Smuzhiyun 	err = usb_control_msg_send(dev, 0, UAC_SET_CUR,
282*4882a593Smuzhiyun 				   USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
283*4882a593Smuzhiyun 				   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3,
284*4882a593Smuzhiyun 				   1000, GFP_NOIO);
285*4882a593Smuzhiyun 	if (err)
286*4882a593Smuzhiyun 		snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n",
287*4882a593Smuzhiyun 			   dev->devnum, rate, ep);
288*4882a593Smuzhiyun 	return err;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
us122l_start(struct us122l * us122l,unsigned rate,unsigned period_frames)291*4882a593Smuzhiyun static bool us122l_start(struct us122l *us122l,
292*4882a593Smuzhiyun 			 unsigned rate, unsigned period_frames)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	struct list_head *p;
295*4882a593Smuzhiyun 	int err;
296*4882a593Smuzhiyun 	unsigned use_packsize = 0;
297*4882a593Smuzhiyun 	bool success = false;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (us122l->dev->speed == USB_SPEED_HIGH) {
300*4882a593Smuzhiyun 		/* The us-122l's descriptor defaults to iso max_packsize 78,
301*4882a593Smuzhiyun 		   which isn't needed for samplerates <= 48000.
302*4882a593Smuzhiyun 		   Lets save some memory:
303*4882a593Smuzhiyun 		*/
304*4882a593Smuzhiyun 		switch (rate) {
305*4882a593Smuzhiyun 		case 44100:
306*4882a593Smuzhiyun 			use_packsize = 36;
307*4882a593Smuzhiyun 			break;
308*4882a593Smuzhiyun 		case 48000:
309*4882a593Smuzhiyun 			use_packsize = 42;
310*4882a593Smuzhiyun 			break;
311*4882a593Smuzhiyun 		case 88200:
312*4882a593Smuzhiyun 			use_packsize = 72;
313*4882a593Smuzhiyun 			break;
314*4882a593Smuzhiyun 		}
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 	if (!usb_stream_new(&us122l->sk, us122l->dev, 1, 2,
317*4882a593Smuzhiyun 			    rate, use_packsize, period_frames, 6))
318*4882a593Smuzhiyun 		goto out;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	err = us122l_set_sample_rate(us122l->dev, rate);
321*4882a593Smuzhiyun 	if (err < 0) {
322*4882a593Smuzhiyun 		us122l_stop(us122l);
323*4882a593Smuzhiyun 		snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
324*4882a593Smuzhiyun 		goto out;
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 	err = usb_stream_start(&us122l->sk);
327*4882a593Smuzhiyun 	if (err < 0) {
328*4882a593Smuzhiyun 		us122l_stop(us122l);
329*4882a593Smuzhiyun 		snd_printk(KERN_ERR "us122l_start error %i \n", err);
330*4882a593Smuzhiyun 		goto out;
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun 	list_for_each(p, &us122l->midi_list)
333*4882a593Smuzhiyun 		snd_usbmidi_input_start(p);
334*4882a593Smuzhiyun 	success = true;
335*4882a593Smuzhiyun out:
336*4882a593Smuzhiyun 	return success;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
usb_stream_hwdep_ioctl(struct snd_hwdep * hw,struct file * file,unsigned cmd,unsigned long arg)339*4882a593Smuzhiyun static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
340*4882a593Smuzhiyun 				  unsigned cmd, unsigned long arg)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	struct usb_stream_config cfg;
343*4882a593Smuzhiyun 	struct us122l *us122l = hw->private_data;
344*4882a593Smuzhiyun 	struct usb_stream *s;
345*4882a593Smuzhiyun 	unsigned min_period_frames;
346*4882a593Smuzhiyun 	int err = 0;
347*4882a593Smuzhiyun 	bool high_speed;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	if (cmd != SNDRV_USB_STREAM_IOCTL_SET_PARAMS)
350*4882a593Smuzhiyun 		return -ENOTTY;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	if (copy_from_user(&cfg, (void __user *)arg, sizeof(cfg)))
353*4882a593Smuzhiyun 		return -EFAULT;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	if (cfg.version != USB_STREAM_INTERFACE_VERSION)
356*4882a593Smuzhiyun 		return -ENXIO;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	high_speed = us122l->dev->speed == USB_SPEED_HIGH;
359*4882a593Smuzhiyun 	if ((cfg.sample_rate != 44100 && cfg.sample_rate != 48000  &&
360*4882a593Smuzhiyun 	     (!high_speed ||
361*4882a593Smuzhiyun 	      (cfg.sample_rate != 88200 && cfg.sample_rate != 96000))) ||
362*4882a593Smuzhiyun 	    cfg.frame_size != 6 ||
363*4882a593Smuzhiyun 	    cfg.period_frames > 0x3000)
364*4882a593Smuzhiyun 		return -EINVAL;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	switch (cfg.sample_rate) {
367*4882a593Smuzhiyun 	case 44100:
368*4882a593Smuzhiyun 		min_period_frames = 48;
369*4882a593Smuzhiyun 		break;
370*4882a593Smuzhiyun 	case 48000:
371*4882a593Smuzhiyun 		min_period_frames = 52;
372*4882a593Smuzhiyun 		break;
373*4882a593Smuzhiyun 	default:
374*4882a593Smuzhiyun 		min_period_frames = 104;
375*4882a593Smuzhiyun 		break;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 	if (!high_speed)
378*4882a593Smuzhiyun 		min_period_frames <<= 1;
379*4882a593Smuzhiyun 	if (cfg.period_frames < min_period_frames)
380*4882a593Smuzhiyun 		return -EINVAL;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	snd_power_wait(hw->card, SNDRV_CTL_POWER_D0);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	mutex_lock(&us122l->mutex);
385*4882a593Smuzhiyun 	s = us122l->sk.s;
386*4882a593Smuzhiyun 	if (!us122l->master)
387*4882a593Smuzhiyun 		us122l->master = file;
388*4882a593Smuzhiyun 	else if (us122l->master != file) {
389*4882a593Smuzhiyun 		if (!s || memcmp(&cfg, &s->cfg, sizeof(cfg))) {
390*4882a593Smuzhiyun 			err = -EIO;
391*4882a593Smuzhiyun 			goto unlock;
392*4882a593Smuzhiyun 		}
393*4882a593Smuzhiyun 		us122l->slave = file;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 	if (!s || memcmp(&cfg, &s->cfg, sizeof(cfg)) ||
396*4882a593Smuzhiyun 	    s->state == usb_stream_xrun) {
397*4882a593Smuzhiyun 		us122l_stop(us122l);
398*4882a593Smuzhiyun 		if (!us122l_start(us122l, cfg.sample_rate, cfg.period_frames))
399*4882a593Smuzhiyun 			err = -EIO;
400*4882a593Smuzhiyun 		else
401*4882a593Smuzhiyun 			err = 1;
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun unlock:
404*4882a593Smuzhiyun 	mutex_unlock(&us122l->mutex);
405*4882a593Smuzhiyun 	wake_up_all(&us122l->sk.sleep);
406*4882a593Smuzhiyun 	return err;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun #define SND_USB_STREAM_ID "USB STREAM"
usb_stream_hwdep_new(struct snd_card * card)410*4882a593Smuzhiyun static int usb_stream_hwdep_new(struct snd_card *card)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	int err;
413*4882a593Smuzhiyun 	struct snd_hwdep *hw;
414*4882a593Smuzhiyun 	struct usb_device *dev = US122L(card)->dev;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw);
417*4882a593Smuzhiyun 	if (err < 0)
418*4882a593Smuzhiyun 		return err;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	hw->iface = SNDRV_HWDEP_IFACE_USB_STREAM;
421*4882a593Smuzhiyun 	hw->private_data = US122L(card);
422*4882a593Smuzhiyun 	hw->ops.open = usb_stream_hwdep_open;
423*4882a593Smuzhiyun 	hw->ops.release = usb_stream_hwdep_release;
424*4882a593Smuzhiyun 	hw->ops.ioctl = usb_stream_hwdep_ioctl;
425*4882a593Smuzhiyun 	hw->ops.ioctl_compat = usb_stream_hwdep_ioctl;
426*4882a593Smuzhiyun 	hw->ops.mmap = usb_stream_hwdep_mmap;
427*4882a593Smuzhiyun 	hw->ops.poll = usb_stream_hwdep_poll;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm",
430*4882a593Smuzhiyun 		dev->bus->busnum, dev->devnum);
431*4882a593Smuzhiyun 	return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 
us122l_create_card(struct snd_card * card)435*4882a593Smuzhiyun static bool us122l_create_card(struct snd_card *card)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	int err;
438*4882a593Smuzhiyun 	struct us122l *us122l = US122L(card);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	if (us122l->is_us144) {
441*4882a593Smuzhiyun 		err = usb_set_interface(us122l->dev, 0, 1);
442*4882a593Smuzhiyun 		if (err) {
443*4882a593Smuzhiyun 			snd_printk(KERN_ERR "usb_set_interface error \n");
444*4882a593Smuzhiyun 			return false;
445*4882a593Smuzhiyun 		}
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 	err = usb_set_interface(us122l->dev, 1, 1);
448*4882a593Smuzhiyun 	if (err) {
449*4882a593Smuzhiyun 		snd_printk(KERN_ERR "usb_set_interface error \n");
450*4882a593Smuzhiyun 		return false;
451*4882a593Smuzhiyun 	}
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	pt_info_set(us122l->dev, 0x11);
454*4882a593Smuzhiyun 	pt_info_set(us122l->dev, 0x10);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	if (!us122l_start(us122l, 44100, 256))
457*4882a593Smuzhiyun 		return false;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	if (us122l->is_us144)
460*4882a593Smuzhiyun 		err = us144_create_usbmidi(card);
461*4882a593Smuzhiyun 	else
462*4882a593Smuzhiyun 		err = us122l_create_usbmidi(card);
463*4882a593Smuzhiyun 	if (err < 0) {
464*4882a593Smuzhiyun 		snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err);
465*4882a593Smuzhiyun 		goto stop;
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 	err = usb_stream_hwdep_new(card);
468*4882a593Smuzhiyun 	if (err < 0) {
469*4882a593Smuzhiyun /* release the midi resources */
470*4882a593Smuzhiyun 		struct list_head *p;
471*4882a593Smuzhiyun 		list_for_each(p, &us122l->midi_list)
472*4882a593Smuzhiyun 			snd_usbmidi_disconnect(p);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 		goto stop;
475*4882a593Smuzhiyun 	}
476*4882a593Smuzhiyun 	return true;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun stop:
479*4882a593Smuzhiyun 	us122l_stop(us122l);
480*4882a593Smuzhiyun 	return false;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
snd_us122l_free(struct snd_card * card)483*4882a593Smuzhiyun static void snd_us122l_free(struct snd_card *card)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	struct us122l	*us122l = US122L(card);
486*4882a593Smuzhiyun 	int		index = us122l->card_index;
487*4882a593Smuzhiyun 	if (index >= 0  &&  index < SNDRV_CARDS)
488*4882a593Smuzhiyun 		snd_us122l_card_used[index] = 0;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
usx2y_create_card(struct usb_device * device,struct usb_interface * intf,struct snd_card ** cardp,unsigned long flags)491*4882a593Smuzhiyun static int usx2y_create_card(struct usb_device *device,
492*4882a593Smuzhiyun 			     struct usb_interface *intf,
493*4882a593Smuzhiyun 			     struct snd_card **cardp,
494*4882a593Smuzhiyun 			     unsigned long flags)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun 	int		dev;
497*4882a593Smuzhiyun 	struct snd_card *card;
498*4882a593Smuzhiyun 	int err;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	for (dev = 0; dev < SNDRV_CARDS; ++dev)
501*4882a593Smuzhiyun 		if (enable[dev] && !snd_us122l_card_used[dev])
502*4882a593Smuzhiyun 			break;
503*4882a593Smuzhiyun 	if (dev >= SNDRV_CARDS)
504*4882a593Smuzhiyun 		return -ENODEV;
505*4882a593Smuzhiyun 	err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE,
506*4882a593Smuzhiyun 			   sizeof(struct us122l), &card);
507*4882a593Smuzhiyun 	if (err < 0)
508*4882a593Smuzhiyun 		return err;
509*4882a593Smuzhiyun 	snd_us122l_card_used[US122L(card)->card_index = dev] = 1;
510*4882a593Smuzhiyun 	card->private_free = snd_us122l_free;
511*4882a593Smuzhiyun 	US122L(card)->dev = device;
512*4882a593Smuzhiyun 	mutex_init(&US122L(card)->mutex);
513*4882a593Smuzhiyun 	init_waitqueue_head(&US122L(card)->sk.sleep);
514*4882a593Smuzhiyun 	US122L(card)->is_us144 = flags & US122L_FLAG_US144;
515*4882a593Smuzhiyun 	INIT_LIST_HEAD(&US122L(card)->midi_list);
516*4882a593Smuzhiyun 	strcpy(card->driver, "USB "NAME_ALLCAPS"");
517*4882a593Smuzhiyun 	sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
518*4882a593Smuzhiyun 	sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
519*4882a593Smuzhiyun 		card->shortname,
520*4882a593Smuzhiyun 		le16_to_cpu(device->descriptor.idVendor),
521*4882a593Smuzhiyun 		le16_to_cpu(device->descriptor.idProduct),
522*4882a593Smuzhiyun 		0,
523*4882a593Smuzhiyun 		US122L(card)->dev->bus->busnum,
524*4882a593Smuzhiyun 		US122L(card)->dev->devnum
525*4882a593Smuzhiyun 		);
526*4882a593Smuzhiyun 	*cardp = card;
527*4882a593Smuzhiyun 	return 0;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun 
us122l_usb_probe(struct usb_interface * intf,const struct usb_device_id * device_id,struct snd_card ** cardp)530*4882a593Smuzhiyun static int us122l_usb_probe(struct usb_interface *intf,
531*4882a593Smuzhiyun 			    const struct usb_device_id *device_id,
532*4882a593Smuzhiyun 			    struct snd_card **cardp)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun 	struct usb_device *device = interface_to_usbdev(intf);
535*4882a593Smuzhiyun 	struct snd_card *card;
536*4882a593Smuzhiyun 	int err;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	err = usx2y_create_card(device, intf, &card, device_id->driver_info);
539*4882a593Smuzhiyun 	if (err < 0)
540*4882a593Smuzhiyun 		return err;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (!us122l_create_card(card)) {
543*4882a593Smuzhiyun 		snd_card_free(card);
544*4882a593Smuzhiyun 		return -EINVAL;
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	err = snd_card_register(card);
548*4882a593Smuzhiyun 	if (err < 0) {
549*4882a593Smuzhiyun 		snd_card_free(card);
550*4882a593Smuzhiyun 		return err;
551*4882a593Smuzhiyun 	}
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	usb_get_intf(usb_ifnum_to_if(device, 0));
554*4882a593Smuzhiyun 	usb_get_dev(device);
555*4882a593Smuzhiyun 	*cardp = card;
556*4882a593Smuzhiyun 	return 0;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun 
snd_us122l_probe(struct usb_interface * intf,const struct usb_device_id * id)559*4882a593Smuzhiyun static int snd_us122l_probe(struct usb_interface *intf,
560*4882a593Smuzhiyun 			    const struct usb_device_id *id)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	struct usb_device *device = interface_to_usbdev(intf);
563*4882a593Smuzhiyun 	struct snd_card *card;
564*4882a593Smuzhiyun 	int err;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	if (id->driver_info & US122L_FLAG_US144 &&
567*4882a593Smuzhiyun 			device->speed == USB_SPEED_HIGH) {
568*4882a593Smuzhiyun 		snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n");
569*4882a593Smuzhiyun 		return -ENODEV;
570*4882a593Smuzhiyun 	}
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	snd_printdd(KERN_DEBUG"%p:%i\n",
573*4882a593Smuzhiyun 		    intf, intf->cur_altsetting->desc.bInterfaceNumber);
574*4882a593Smuzhiyun 	if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
575*4882a593Smuzhiyun 		return 0;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	err = us122l_usb_probe(usb_get_intf(intf), id, &card);
578*4882a593Smuzhiyun 	if (err < 0) {
579*4882a593Smuzhiyun 		usb_put_intf(intf);
580*4882a593Smuzhiyun 		return err;
581*4882a593Smuzhiyun 	}
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	usb_set_intfdata(intf, card);
584*4882a593Smuzhiyun 	return 0;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun 
snd_us122l_disconnect(struct usb_interface * intf)587*4882a593Smuzhiyun static void snd_us122l_disconnect(struct usb_interface *intf)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	struct snd_card *card;
590*4882a593Smuzhiyun 	struct us122l *us122l;
591*4882a593Smuzhiyun 	struct list_head *p;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	card = usb_get_intfdata(intf);
594*4882a593Smuzhiyun 	if (!card)
595*4882a593Smuzhiyun 		return;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	snd_card_disconnect(card);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	us122l = US122L(card);
600*4882a593Smuzhiyun 	mutex_lock(&us122l->mutex);
601*4882a593Smuzhiyun 	us122l_stop(us122l);
602*4882a593Smuzhiyun 	mutex_unlock(&us122l->mutex);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun /* release the midi resources */
605*4882a593Smuzhiyun 	list_for_each(p, &us122l->midi_list) {
606*4882a593Smuzhiyun 		snd_usbmidi_disconnect(p);
607*4882a593Smuzhiyun 	}
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	usb_put_intf(usb_ifnum_to_if(us122l->dev, 0));
610*4882a593Smuzhiyun 	usb_put_intf(usb_ifnum_to_if(us122l->dev, 1));
611*4882a593Smuzhiyun 	usb_put_dev(us122l->dev);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	while (atomic_read(&us122l->mmap_count))
614*4882a593Smuzhiyun 		msleep(500);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	snd_card_free(card);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun 
snd_us122l_suspend(struct usb_interface * intf,pm_message_t message)619*4882a593Smuzhiyun static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	struct snd_card *card;
622*4882a593Smuzhiyun 	struct us122l *us122l;
623*4882a593Smuzhiyun 	struct list_head *p;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	card = usb_get_intfdata(intf);
626*4882a593Smuzhiyun 	if (!card)
627*4882a593Smuzhiyun 		return 0;
628*4882a593Smuzhiyun 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	us122l = US122L(card);
631*4882a593Smuzhiyun 	if (!us122l)
632*4882a593Smuzhiyun 		return 0;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	list_for_each(p, &us122l->midi_list)
635*4882a593Smuzhiyun 		snd_usbmidi_input_stop(p);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	mutex_lock(&us122l->mutex);
638*4882a593Smuzhiyun 	usb_stream_stop(&us122l->sk);
639*4882a593Smuzhiyun 	mutex_unlock(&us122l->mutex);
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	return 0;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
snd_us122l_resume(struct usb_interface * intf)644*4882a593Smuzhiyun static int snd_us122l_resume(struct usb_interface *intf)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun 	struct snd_card *card;
647*4882a593Smuzhiyun 	struct us122l *us122l;
648*4882a593Smuzhiyun 	struct list_head *p;
649*4882a593Smuzhiyun 	int err;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	card = usb_get_intfdata(intf);
652*4882a593Smuzhiyun 	if (!card)
653*4882a593Smuzhiyun 		return 0;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	us122l = US122L(card);
656*4882a593Smuzhiyun 	if (!us122l)
657*4882a593Smuzhiyun 		return 0;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	mutex_lock(&us122l->mutex);
660*4882a593Smuzhiyun 	/* needed, doesn't restart without: */
661*4882a593Smuzhiyun 	if (us122l->is_us144) {
662*4882a593Smuzhiyun 		err = usb_set_interface(us122l->dev, 0, 1);
663*4882a593Smuzhiyun 		if (err) {
664*4882a593Smuzhiyun 			snd_printk(KERN_ERR "usb_set_interface error \n");
665*4882a593Smuzhiyun 			goto unlock;
666*4882a593Smuzhiyun 		}
667*4882a593Smuzhiyun 	}
668*4882a593Smuzhiyun 	err = usb_set_interface(us122l->dev, 1, 1);
669*4882a593Smuzhiyun 	if (err) {
670*4882a593Smuzhiyun 		snd_printk(KERN_ERR "usb_set_interface error \n");
671*4882a593Smuzhiyun 		goto unlock;
672*4882a593Smuzhiyun 	}
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	pt_info_set(us122l->dev, 0x11);
675*4882a593Smuzhiyun 	pt_info_set(us122l->dev, 0x10);
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	err = us122l_set_sample_rate(us122l->dev,
678*4882a593Smuzhiyun 				     us122l->sk.s->cfg.sample_rate);
679*4882a593Smuzhiyun 	if (err < 0) {
680*4882a593Smuzhiyun 		snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
681*4882a593Smuzhiyun 		goto unlock;
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun 	err = usb_stream_start(&us122l->sk);
684*4882a593Smuzhiyun 	if (err)
685*4882a593Smuzhiyun 		goto unlock;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	list_for_each(p, &us122l->midi_list)
688*4882a593Smuzhiyun 		snd_usbmidi_input_start(p);
689*4882a593Smuzhiyun unlock:
690*4882a593Smuzhiyun 	mutex_unlock(&us122l->mutex);
691*4882a593Smuzhiyun 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
692*4882a593Smuzhiyun 	return err;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun static const struct usb_device_id snd_us122l_usb_id_table[] = {
696*4882a593Smuzhiyun 	{
697*4882a593Smuzhiyun 		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
698*4882a593Smuzhiyun 		.idVendor =	0x0644,
699*4882a593Smuzhiyun 		.idProduct =	USB_ID_US122L
700*4882a593Smuzhiyun 	},
701*4882a593Smuzhiyun 	{	/* US-144 only works at USB1.1! Disable module ehci-hcd. */
702*4882a593Smuzhiyun 		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
703*4882a593Smuzhiyun 		.idVendor =	0x0644,
704*4882a593Smuzhiyun 		.idProduct =	USB_ID_US144,
705*4882a593Smuzhiyun 		.driver_info =	US122L_FLAG_US144
706*4882a593Smuzhiyun 	},
707*4882a593Smuzhiyun 	{
708*4882a593Smuzhiyun 		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
709*4882a593Smuzhiyun 		.idVendor =	0x0644,
710*4882a593Smuzhiyun 		.idProduct =	USB_ID_US122MKII
711*4882a593Smuzhiyun 	},
712*4882a593Smuzhiyun 	{
713*4882a593Smuzhiyun 		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
714*4882a593Smuzhiyun 		.idVendor =	0x0644,
715*4882a593Smuzhiyun 		.idProduct =	USB_ID_US144MKII,
716*4882a593Smuzhiyun 		.driver_info =	US122L_FLAG_US144
717*4882a593Smuzhiyun 	},
718*4882a593Smuzhiyun 	{ /* terminator */ }
719*4882a593Smuzhiyun };
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, snd_us122l_usb_id_table);
722*4882a593Smuzhiyun static struct usb_driver snd_us122l_usb_driver = {
723*4882a593Smuzhiyun 	.name =		"snd-usb-us122l",
724*4882a593Smuzhiyun 	.probe =	snd_us122l_probe,
725*4882a593Smuzhiyun 	.disconnect =	snd_us122l_disconnect,
726*4882a593Smuzhiyun 	.suspend =	snd_us122l_suspend,
727*4882a593Smuzhiyun 	.resume =	snd_us122l_resume,
728*4882a593Smuzhiyun 	.reset_resume =	snd_us122l_resume,
729*4882a593Smuzhiyun 	.id_table =	snd_us122l_usb_id_table,
730*4882a593Smuzhiyun 	.supports_autosuspend = 1
731*4882a593Smuzhiyun };
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun module_usb_driver(snd_us122l_usb_driver);
734