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