| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Line 6 Linux USB driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License as |
|---|
| 8 | | - * published by the Free Software Foundation, version 2. |
|---|
| 9 | | - * |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 101 | 97 | /* |
|---|
| 102 | 98 | Send raw message in pieces of wMaxPacketSize bytes. |
|---|
| 103 | 99 | */ |
|---|
| 104 | | -static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, |
|---|
| 100 | +int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, |
|---|
| 105 | 101 | int size) |
|---|
| 106 | 102 | { |
|---|
| 107 | 103 | int i, done = 0; |
|---|
| .. | .. |
|---|
| 136 | 132 | |
|---|
| 137 | 133 | return done; |
|---|
| 138 | 134 | } |
|---|
| 135 | +EXPORT_SYMBOL_GPL(line6_send_raw_message); |
|---|
| 139 | 136 | |
|---|
| 140 | 137 | /* |
|---|
| 141 | 138 | Notification of completion of asynchronous request transmission. |
|---|
| .. | .. |
|---|
| 194 | 191 | kfree(msg); |
|---|
| 195 | 192 | return retval; |
|---|
| 196 | 193 | } |
|---|
| 197 | | - |
|---|
| 198 | | -/* |
|---|
| 199 | | - Setup and start timer. |
|---|
| 200 | | -*/ |
|---|
| 201 | | -void line6_start_timer(struct timer_list *timer, unsigned long msecs, |
|---|
| 202 | | - void (*function)(struct timer_list *t)) |
|---|
| 203 | | -{ |
|---|
| 204 | | - timer->function = function; |
|---|
| 205 | | - mod_timer(timer, jiffies + msecs_to_jiffies(msecs)); |
|---|
| 206 | | -} |
|---|
| 207 | | -EXPORT_SYMBOL_GPL(line6_start_timer); |
|---|
| 208 | 194 | |
|---|
| 209 | 195 | /* |
|---|
| 210 | 196 | Asynchronously send raw message. |
|---|
| .. | .. |
|---|
| 318 | 304 | for (;;) { |
|---|
| 319 | 305 | done = |
|---|
| 320 | 306 | line6_midibuf_read(mb, line6->buffer_message, |
|---|
| 321 | | - LINE6_MIDI_MESSAGE_MAXLEN); |
|---|
| 307 | + LINE6_MIDI_MESSAGE_MAXLEN, |
|---|
| 308 | + LINE6_MIDIBUF_READ_RX); |
|---|
| 322 | 309 | |
|---|
| 323 | 310 | if (done <= 0) |
|---|
| 324 | 311 | break; |
|---|
| .. | .. |
|---|
| 351 | 338 | { |
|---|
| 352 | 339 | struct usb_device *usbdev = line6->usbdev; |
|---|
| 353 | 340 | int ret; |
|---|
| 354 | | - unsigned char *len; |
|---|
| 341 | + u8 len; |
|---|
| 355 | 342 | unsigned count; |
|---|
| 356 | 343 | |
|---|
| 357 | 344 | if (address > 0xffff || datalen > 0xff) |
|---|
| 358 | 345 | return -EINVAL; |
|---|
| 359 | 346 | |
|---|
| 360 | | - len = kmalloc(sizeof(*len), GFP_KERNEL); |
|---|
| 361 | | - if (!len) |
|---|
| 362 | | - return -ENOMEM; |
|---|
| 363 | | - |
|---|
| 364 | 347 | /* query the serial number: */ |
|---|
| 365 | | - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, |
|---|
| 366 | | - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
|---|
| 367 | | - (datalen << 8) | 0x21, address, |
|---|
| 368 | | - NULL, 0, LINE6_TIMEOUT); |
|---|
| 369 | | - |
|---|
| 370 | | - if (ret < 0) { |
|---|
| 348 | + ret = usb_control_msg_send(usbdev, 0, 0x67, |
|---|
| 349 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
|---|
| 350 | + (datalen << 8) | 0x21, address, NULL, 0, |
|---|
| 351 | + LINE6_TIMEOUT, GFP_KERNEL); |
|---|
| 352 | + if (ret) { |
|---|
| 371 | 353 | dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); |
|---|
| 372 | 354 | goto exit; |
|---|
| 373 | 355 | } |
|---|
| .. | .. |
|---|
| 376 | 358 | for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { |
|---|
| 377 | 359 | mdelay(LINE6_READ_WRITE_STATUS_DELAY); |
|---|
| 378 | 360 | |
|---|
| 379 | | - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, |
|---|
| 380 | | - USB_TYPE_VENDOR | USB_RECIP_DEVICE | |
|---|
| 381 | | - USB_DIR_IN, |
|---|
| 382 | | - 0x0012, 0x0000, len, 1, |
|---|
| 383 | | - LINE6_TIMEOUT); |
|---|
| 384 | | - if (ret < 0) { |
|---|
| 361 | + ret = usb_control_msg_recv(usbdev, 0, 0x67, |
|---|
| 362 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
|---|
| 363 | + 0x0012, 0x0000, &len, 1, |
|---|
| 364 | + LINE6_TIMEOUT, GFP_KERNEL); |
|---|
| 365 | + if (ret) { |
|---|
| 385 | 366 | dev_err(line6->ifcdev, |
|---|
| 386 | 367 | "receive length failed (error %d)\n", ret); |
|---|
| 387 | 368 | goto exit; |
|---|
| 388 | 369 | } |
|---|
| 389 | 370 | |
|---|
| 390 | | - if (*len != 0xff) |
|---|
| 371 | + if (len != 0xff) |
|---|
| 391 | 372 | break; |
|---|
| 392 | 373 | } |
|---|
| 393 | 374 | |
|---|
| 394 | 375 | ret = -EIO; |
|---|
| 395 | | - if (*len == 0xff) { |
|---|
| 376 | + if (len == 0xff) { |
|---|
| 396 | 377 | dev_err(line6->ifcdev, "read failed after %d retries\n", |
|---|
| 397 | 378 | count); |
|---|
| 398 | 379 | goto exit; |
|---|
| 399 | | - } else if (*len != datalen) { |
|---|
| 380 | + } else if (len != datalen) { |
|---|
| 400 | 381 | /* should be equal or something went wrong */ |
|---|
| 401 | 382 | dev_err(line6->ifcdev, |
|---|
| 402 | 383 | "length mismatch (expected %d, got %d)\n", |
|---|
| 403 | | - (int)datalen, (int)*len); |
|---|
| 384 | + (int)datalen, len); |
|---|
| 404 | 385 | goto exit; |
|---|
| 405 | 386 | } |
|---|
| 406 | 387 | |
|---|
| 407 | 388 | /* receive the result: */ |
|---|
| 408 | | - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, |
|---|
| 409 | | - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
|---|
| 410 | | - 0x0013, 0x0000, data, datalen, |
|---|
| 411 | | - LINE6_TIMEOUT); |
|---|
| 412 | | - |
|---|
| 413 | | - if (ret < 0) |
|---|
| 389 | + ret = usb_control_msg_recv(usbdev, 0, 0x67, |
|---|
| 390 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
|---|
| 391 | + 0x0013, 0x0000, data, datalen, LINE6_TIMEOUT, |
|---|
| 392 | + GFP_KERNEL); |
|---|
| 393 | + if (ret) |
|---|
| 414 | 394 | dev_err(line6->ifcdev, "read failed (error %d)\n", ret); |
|---|
| 415 | 395 | |
|---|
| 416 | 396 | exit: |
|---|
| 417 | | - kfree(len); |
|---|
| 418 | 397 | return ret; |
|---|
| 419 | 398 | } |
|---|
| 420 | 399 | EXPORT_SYMBOL_GPL(line6_read_data); |
|---|
| .. | .. |
|---|
| 433 | 412 | if (address > 0xffff || datalen > 0xffff) |
|---|
| 434 | 413 | return -EINVAL; |
|---|
| 435 | 414 | |
|---|
| 436 | | - status = kmalloc(sizeof(*status), GFP_KERNEL); |
|---|
| 415 | + status = kmalloc(1, GFP_KERNEL); |
|---|
| 437 | 416 | if (!status) |
|---|
| 438 | 417 | return -ENOMEM; |
|---|
| 439 | 418 | |
|---|
| 440 | | - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, |
|---|
| 441 | | - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
|---|
| 442 | | - 0x0022, address, data, datalen, |
|---|
| 443 | | - LINE6_TIMEOUT); |
|---|
| 444 | | - |
|---|
| 445 | | - if (ret < 0) { |
|---|
| 419 | + ret = usb_control_msg_send(usbdev, 0, 0x67, |
|---|
| 420 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
|---|
| 421 | + 0x0022, address, data, datalen, LINE6_TIMEOUT, |
|---|
| 422 | + GFP_KERNEL); |
|---|
| 423 | + if (ret) { |
|---|
| 446 | 424 | dev_err(line6->ifcdev, |
|---|
| 447 | 425 | "write request failed (error %d)\n", ret); |
|---|
| 448 | 426 | goto exit; |
|---|
| .. | .. |
|---|
| 451 | 429 | for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { |
|---|
| 452 | 430 | mdelay(LINE6_READ_WRITE_STATUS_DELAY); |
|---|
| 453 | 431 | |
|---|
| 454 | | - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), |
|---|
| 455 | | - 0x67, |
|---|
| 456 | | - USB_TYPE_VENDOR | USB_RECIP_DEVICE | |
|---|
| 457 | | - USB_DIR_IN, |
|---|
| 458 | | - 0x0012, 0x0000, |
|---|
| 459 | | - status, 1, LINE6_TIMEOUT); |
|---|
| 460 | | - |
|---|
| 461 | | - if (ret < 0) { |
|---|
| 432 | + ret = usb_control_msg_recv(usbdev, 0, 0x67, |
|---|
| 433 | + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
|---|
| 434 | + 0x0012, 0x0000, status, 1, LINE6_TIMEOUT, |
|---|
| 435 | + GFP_KERNEL); |
|---|
| 436 | + if (ret) { |
|---|
| 462 | 437 | dev_err(line6->ifcdev, |
|---|
| 463 | 438 | "receiving status failed (error %d)\n", ret); |
|---|
| 464 | 439 | goto exit; |
|---|
| .. | .. |
|---|
| 565 | 540 | /* NOTE: hwdep layer provides atomicity here */ |
|---|
| 566 | 541 | |
|---|
| 567 | 542 | line6->messages.active = 1; |
|---|
| 543 | + line6->messages.nonblock = file->f_flags & O_NONBLOCK ? 1 : 0; |
|---|
| 568 | 544 | |
|---|
| 569 | 545 | return 0; |
|---|
| 570 | 546 | } |
|---|
| .. | .. |
|---|
| 593 | 569 | |
|---|
| 594 | 570 | while (kfifo_len(&line6->messages.fifo) == 0) { |
|---|
| 595 | 571 | mutex_unlock(&line6->messages.read_lock); |
|---|
| 572 | + |
|---|
| 573 | + if (line6->messages.nonblock) |
|---|
| 574 | + return -EAGAIN; |
|---|
| 596 | 575 | |
|---|
| 597 | 576 | rv = wait_event_interruptible( |
|---|
| 598 | 577 | line6->messages.wait_queue, |
|---|
| .. | .. |
|---|
| 641 | 620 | return rv; |
|---|
| 642 | 621 | } |
|---|
| 643 | 622 | |
|---|
| 623 | +static __poll_t |
|---|
| 624 | +line6_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) |
|---|
| 625 | +{ |
|---|
| 626 | + __poll_t rv; |
|---|
| 627 | + struct usb_line6 *line6 = hwdep->private_data; |
|---|
| 628 | + |
|---|
| 629 | + poll_wait(file, &line6->messages.wait_queue, wait); |
|---|
| 630 | + |
|---|
| 631 | + mutex_lock(&line6->messages.read_lock); |
|---|
| 632 | + rv = kfifo_len(&line6->messages.fifo) == 0 ? 0 : EPOLLIN | EPOLLRDNORM; |
|---|
| 633 | + mutex_unlock(&line6->messages.read_lock); |
|---|
| 634 | + |
|---|
| 635 | + return rv; |
|---|
| 636 | +} |
|---|
| 637 | + |
|---|
| 644 | 638 | static const struct snd_hwdep_ops hwdep_ops = { |
|---|
| 645 | 639 | .open = line6_hwdep_open, |
|---|
| 646 | 640 | .release = line6_hwdep_release, |
|---|
| 647 | 641 | .read = line6_hwdep_read, |
|---|
| 648 | 642 | .write = line6_hwdep_write, |
|---|
| 643 | + .poll = line6_hwdep_poll, |
|---|
| 649 | 644 | }; |
|---|
| 650 | 645 | |
|---|
| 651 | 646 | /* Insert into circular buffer */ |
|---|
| .. | .. |
|---|
| 875 | 870 | if (line6->properties->capabilities & LINE6_CAP_CONTROL) |
|---|
| 876 | 871 | line6_stop_listen(line6); |
|---|
| 877 | 872 | |
|---|
| 878 | | - if (line6pcm != NULL) { |
|---|
| 879 | | - snd_pcm_suspend_all(line6pcm->pcm); |
|---|
| 873 | + if (line6pcm != NULL) |
|---|
| 880 | 874 | line6pcm->flags = 0; |
|---|
| 881 | | - } |
|---|
| 882 | 875 | |
|---|
| 883 | 876 | return 0; |
|---|
| 884 | 877 | } |
|---|