162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Line 6 Linux USB driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/export.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/usb.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <sound/core.h> 1562306a36Sopenharmony_ci#include <sound/initval.h> 1662306a36Sopenharmony_ci#include <sound/hwdep.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "capture.h" 1962306a36Sopenharmony_ci#include "driver.h" 2062306a36Sopenharmony_ci#include "midi.h" 2162306a36Sopenharmony_ci#include "playback.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>" 2462306a36Sopenharmony_ci#define DRIVER_DESC "Line 6 USB Driver" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci This is Line 6's MIDI manufacturer ID. 2862306a36Sopenharmony_ci*/ 2962306a36Sopenharmony_ciconst unsigned char line6_midi_id[3] = { 3062306a36Sopenharmony_ci 0x00, 0x01, 0x0c 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_midi_id); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci Code to request version of POD, Variax interface 3662306a36Sopenharmony_ci (and maybe other devices). 3762306a36Sopenharmony_ci*/ 3862306a36Sopenharmony_cistatic const char line6_request_version[] = { 3962306a36Sopenharmony_ci 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci Class for asynchronous messages. 4462306a36Sopenharmony_ci*/ 4562306a36Sopenharmony_cistruct message { 4662306a36Sopenharmony_ci struct usb_line6 *line6; 4762306a36Sopenharmony_ci const char *buffer; 4862306a36Sopenharmony_ci int size; 4962306a36Sopenharmony_ci int done; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci Forward declarations. 5462306a36Sopenharmony_ci*/ 5562306a36Sopenharmony_cistatic void line6_data_received(struct urb *urb); 5662306a36Sopenharmony_cistatic int line6_send_raw_message_async_part(struct message *msg, 5762306a36Sopenharmony_ci struct urb *urb); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* 6062306a36Sopenharmony_ci Start to listen on endpoint. 6162306a36Sopenharmony_ci*/ 6262306a36Sopenharmony_cistatic int line6_start_listen(struct usb_line6 *line6) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci int err; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) { 6762306a36Sopenharmony_ci usb_fill_int_urb(line6->urb_listen, line6->usbdev, 6862306a36Sopenharmony_ci usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r), 6962306a36Sopenharmony_ci line6->buffer_listen, LINE6_BUFSIZE_LISTEN, 7062306a36Sopenharmony_ci line6_data_received, line6, line6->interval); 7162306a36Sopenharmony_ci } else { 7262306a36Sopenharmony_ci usb_fill_bulk_urb(line6->urb_listen, line6->usbdev, 7362306a36Sopenharmony_ci usb_rcvbulkpipe(line6->usbdev, line6->properties->ep_ctrl_r), 7462306a36Sopenharmony_ci line6->buffer_listen, LINE6_BUFSIZE_LISTEN, 7562306a36Sopenharmony_ci line6_data_received, line6); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* sanity checks of EP before actually submitting */ 7962306a36Sopenharmony_ci if (usb_urb_ep_type_check(line6->urb_listen)) { 8062306a36Sopenharmony_ci dev_err(line6->ifcdev, "invalid control EP\n"); 8162306a36Sopenharmony_ci return -EINVAL; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci line6->urb_listen->actual_length = 0; 8562306a36Sopenharmony_ci err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); 8662306a36Sopenharmony_ci return err; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci Stop listening on endpoint. 9162306a36Sopenharmony_ci*/ 9262306a36Sopenharmony_cistatic void line6_stop_listen(struct usb_line6 *line6) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci usb_kill_urb(line6->urb_listen); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci Send raw message in pieces of wMaxPacketSize bytes. 9962306a36Sopenharmony_ci*/ 10062306a36Sopenharmony_ciint line6_send_raw_message(struct usb_line6 *line6, const char *buffer, 10162306a36Sopenharmony_ci int size) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int i, done = 0; 10462306a36Sopenharmony_ci const struct line6_properties *properties = line6->properties; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci for (i = 0; i < size; i += line6->max_packet_size) { 10762306a36Sopenharmony_ci int partial; 10862306a36Sopenharmony_ci const char *frag_buf = buffer + i; 10962306a36Sopenharmony_ci int frag_size = min(line6->max_packet_size, size - i); 11062306a36Sopenharmony_ci int retval; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) { 11362306a36Sopenharmony_ci retval = usb_interrupt_msg(line6->usbdev, 11462306a36Sopenharmony_ci usb_sndintpipe(line6->usbdev, properties->ep_ctrl_w), 11562306a36Sopenharmony_ci (char *)frag_buf, frag_size, 11662306a36Sopenharmony_ci &partial, LINE6_TIMEOUT); 11762306a36Sopenharmony_ci } else { 11862306a36Sopenharmony_ci retval = usb_bulk_msg(line6->usbdev, 11962306a36Sopenharmony_ci usb_sndbulkpipe(line6->usbdev, properties->ep_ctrl_w), 12062306a36Sopenharmony_ci (char *)frag_buf, frag_size, 12162306a36Sopenharmony_ci &partial, LINE6_TIMEOUT); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (retval) { 12562306a36Sopenharmony_ci dev_err(line6->ifcdev, 12662306a36Sopenharmony_ci "usb_bulk_msg failed (%d)\n", retval); 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci done += frag_size; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return done; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_send_raw_message); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* 13862306a36Sopenharmony_ci Notification of completion of asynchronous request transmission. 13962306a36Sopenharmony_ci*/ 14062306a36Sopenharmony_cistatic void line6_async_request_sent(struct urb *urb) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct message *msg = (struct message *)urb->context; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (msg->done >= msg->size) { 14562306a36Sopenharmony_ci usb_free_urb(urb); 14662306a36Sopenharmony_ci kfree(msg); 14762306a36Sopenharmony_ci } else 14862306a36Sopenharmony_ci line6_send_raw_message_async_part(msg, urb); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* 15262306a36Sopenharmony_ci Asynchronously send part of a raw message. 15362306a36Sopenharmony_ci*/ 15462306a36Sopenharmony_cistatic int line6_send_raw_message_async_part(struct message *msg, 15562306a36Sopenharmony_ci struct urb *urb) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci int retval; 15862306a36Sopenharmony_ci struct usb_line6 *line6 = msg->line6; 15962306a36Sopenharmony_ci int done = msg->done; 16062306a36Sopenharmony_ci int bytes = min(msg->size - done, line6->max_packet_size); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) { 16362306a36Sopenharmony_ci usb_fill_int_urb(urb, line6->usbdev, 16462306a36Sopenharmony_ci usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), 16562306a36Sopenharmony_ci (char *)msg->buffer + done, bytes, 16662306a36Sopenharmony_ci line6_async_request_sent, msg, line6->interval); 16762306a36Sopenharmony_ci } else { 16862306a36Sopenharmony_ci usb_fill_bulk_urb(urb, line6->usbdev, 16962306a36Sopenharmony_ci usb_sndbulkpipe(line6->usbdev, line6->properties->ep_ctrl_w), 17062306a36Sopenharmony_ci (char *)msg->buffer + done, bytes, 17162306a36Sopenharmony_ci line6_async_request_sent, msg); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci msg->done += bytes; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* sanity checks of EP before actually submitting */ 17762306a36Sopenharmony_ci retval = usb_urb_ep_type_check(urb); 17862306a36Sopenharmony_ci if (retval < 0) 17962306a36Sopenharmony_ci goto error; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 18262306a36Sopenharmony_ci if (retval < 0) 18362306a36Sopenharmony_ci goto error; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci error: 18862306a36Sopenharmony_ci dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", 18962306a36Sopenharmony_ci __func__, retval); 19062306a36Sopenharmony_ci usb_free_urb(urb); 19162306a36Sopenharmony_ci kfree(msg); 19262306a36Sopenharmony_ci return retval; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/* 19662306a36Sopenharmony_ci Asynchronously send raw message. 19762306a36Sopenharmony_ci*/ 19862306a36Sopenharmony_ciint line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, 19962306a36Sopenharmony_ci int size) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct message *msg; 20262306a36Sopenharmony_ci struct urb *urb; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* create message: */ 20562306a36Sopenharmony_ci msg = kmalloc(sizeof(struct message), GFP_ATOMIC); 20662306a36Sopenharmony_ci if (msg == NULL) 20762306a36Sopenharmony_ci return -ENOMEM; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* create URB: */ 21062306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (urb == NULL) { 21362306a36Sopenharmony_ci kfree(msg); 21462306a36Sopenharmony_ci return -ENOMEM; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* set message data: */ 21862306a36Sopenharmony_ci msg->line6 = line6; 21962306a36Sopenharmony_ci msg->buffer = buffer; 22062306a36Sopenharmony_ci msg->size = size; 22162306a36Sopenharmony_ci msg->done = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* start sending: */ 22462306a36Sopenharmony_ci return line6_send_raw_message_async_part(msg, urb); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_send_raw_message_async); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/* 22962306a36Sopenharmony_ci Send asynchronous device version request. 23062306a36Sopenharmony_ci*/ 23162306a36Sopenharmony_ciint line6_version_request_async(struct usb_line6 *line6) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci char *buffer; 23462306a36Sopenharmony_ci int retval; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci buffer = kmemdup(line6_request_version, 23762306a36Sopenharmony_ci sizeof(line6_request_version), GFP_ATOMIC); 23862306a36Sopenharmony_ci if (buffer == NULL) 23962306a36Sopenharmony_ci return -ENOMEM; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci retval = line6_send_raw_message_async(line6, buffer, 24262306a36Sopenharmony_ci sizeof(line6_request_version)); 24362306a36Sopenharmony_ci kfree(buffer); 24462306a36Sopenharmony_ci return retval; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_version_request_async); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/* 24962306a36Sopenharmony_ci Send sysex message in pieces of wMaxPacketSize bytes. 25062306a36Sopenharmony_ci*/ 25162306a36Sopenharmony_ciint line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, 25262306a36Sopenharmony_ci int size) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci return line6_send_raw_message(line6, buffer, 25562306a36Sopenharmony_ci size + SYSEX_EXTRA_SIZE) - 25662306a36Sopenharmony_ci SYSEX_EXTRA_SIZE; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_send_sysex_message); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* 26162306a36Sopenharmony_ci Allocate buffer for sysex message and prepare header. 26262306a36Sopenharmony_ci @param code sysex message code 26362306a36Sopenharmony_ci @param size number of bytes between code and sysex end 26462306a36Sopenharmony_ci*/ 26562306a36Sopenharmony_cichar *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, 26662306a36Sopenharmony_ci int size) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (!buffer) 27162306a36Sopenharmony_ci return NULL; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci buffer[0] = LINE6_SYSEX_BEGIN; 27462306a36Sopenharmony_ci memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id)); 27562306a36Sopenharmony_ci buffer[sizeof(line6_midi_id) + 1] = code1; 27662306a36Sopenharmony_ci buffer[sizeof(line6_midi_id) + 2] = code2; 27762306a36Sopenharmony_ci buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; 27862306a36Sopenharmony_ci return buffer; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* 28362306a36Sopenharmony_ci Notification of data received from the Line 6 device. 28462306a36Sopenharmony_ci*/ 28562306a36Sopenharmony_cistatic void line6_data_received(struct urb *urb) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct usb_line6 *line6 = (struct usb_line6 *)urb->context; 28862306a36Sopenharmony_ci struct midi_buffer *mb = &line6->line6midi->midibuf_in; 28962306a36Sopenharmony_ci int done; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (urb->status == -ESHUTDOWN) 29262306a36Sopenharmony_ci return; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) { 29562306a36Sopenharmony_ci done = 29662306a36Sopenharmony_ci line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (done < urb->actual_length) { 29962306a36Sopenharmony_ci line6_midibuf_ignore(mb, done); 30062306a36Sopenharmony_ci dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", 30162306a36Sopenharmony_ci done, urb->actual_length); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci for (;;) { 30562306a36Sopenharmony_ci done = 30662306a36Sopenharmony_ci line6_midibuf_read(mb, line6->buffer_message, 30762306a36Sopenharmony_ci LINE6_MIDI_MESSAGE_MAXLEN, 30862306a36Sopenharmony_ci LINE6_MIDIBUF_READ_RX); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (done <= 0) 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci line6->message_length = done; 31462306a36Sopenharmony_ci line6_midi_receive(line6, line6->buffer_message, done); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (line6->process_message) 31762306a36Sopenharmony_ci line6->process_message(line6); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci } else { 32062306a36Sopenharmony_ci line6->buffer_message = urb->transfer_buffer; 32162306a36Sopenharmony_ci line6->message_length = urb->actual_length; 32262306a36Sopenharmony_ci if (line6->process_message) 32362306a36Sopenharmony_ci line6->process_message(line6); 32462306a36Sopenharmony_ci line6->buffer_message = NULL; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci line6_start_listen(line6); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci#define LINE6_READ_WRITE_STATUS_DELAY 2 /* milliseconds */ 33162306a36Sopenharmony_ci#define LINE6_READ_WRITE_MAX_RETRIES 50 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci/* 33462306a36Sopenharmony_ci Read data from device. 33562306a36Sopenharmony_ci*/ 33662306a36Sopenharmony_ciint line6_read_data(struct usb_line6 *line6, unsigned address, void *data, 33762306a36Sopenharmony_ci unsigned datalen) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct usb_device *usbdev = line6->usbdev; 34062306a36Sopenharmony_ci int ret; 34162306a36Sopenharmony_ci u8 len; 34262306a36Sopenharmony_ci unsigned count; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (address > 0xffff || datalen > 0xff) 34562306a36Sopenharmony_ci return -EINVAL; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* query the serial number: */ 34862306a36Sopenharmony_ci ret = usb_control_msg_send(usbdev, 0, 0x67, 34962306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 35062306a36Sopenharmony_ci (datalen << 8) | 0x21, address, NULL, 0, 35162306a36Sopenharmony_ci LINE6_TIMEOUT, GFP_KERNEL); 35262306a36Sopenharmony_ci if (ret) { 35362306a36Sopenharmony_ci dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); 35462306a36Sopenharmony_ci goto exit; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Wait for data length. We'll get 0xff until length arrives. */ 35862306a36Sopenharmony_ci for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { 35962306a36Sopenharmony_ci mdelay(LINE6_READ_WRITE_STATUS_DELAY); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ret = usb_control_msg_recv(usbdev, 0, 0x67, 36262306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 36362306a36Sopenharmony_ci 0x0012, 0x0000, &len, 1, 36462306a36Sopenharmony_ci LINE6_TIMEOUT, GFP_KERNEL); 36562306a36Sopenharmony_ci if (ret) { 36662306a36Sopenharmony_ci dev_err(line6->ifcdev, 36762306a36Sopenharmony_ci "receive length failed (error %d)\n", ret); 36862306a36Sopenharmony_ci goto exit; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (len != 0xff) 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ret = -EIO; 37662306a36Sopenharmony_ci if (len == 0xff) { 37762306a36Sopenharmony_ci dev_err(line6->ifcdev, "read failed after %d retries\n", 37862306a36Sopenharmony_ci count); 37962306a36Sopenharmony_ci goto exit; 38062306a36Sopenharmony_ci } else if (len != datalen) { 38162306a36Sopenharmony_ci /* should be equal or something went wrong */ 38262306a36Sopenharmony_ci dev_err(line6->ifcdev, 38362306a36Sopenharmony_ci "length mismatch (expected %d, got %d)\n", 38462306a36Sopenharmony_ci (int)datalen, len); 38562306a36Sopenharmony_ci goto exit; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* receive the result: */ 38962306a36Sopenharmony_ci ret = usb_control_msg_recv(usbdev, 0, 0x67, 39062306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 39162306a36Sopenharmony_ci 0x0013, 0x0000, data, datalen, LINE6_TIMEOUT, 39262306a36Sopenharmony_ci GFP_KERNEL); 39362306a36Sopenharmony_ci if (ret) 39462306a36Sopenharmony_ci dev_err(line6->ifcdev, "read failed (error %d)\n", ret); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ciexit: 39762306a36Sopenharmony_ci return ret; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_read_data); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/* 40262306a36Sopenharmony_ci Write data to device. 40362306a36Sopenharmony_ci*/ 40462306a36Sopenharmony_ciint line6_write_data(struct usb_line6 *line6, unsigned address, void *data, 40562306a36Sopenharmony_ci unsigned datalen) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct usb_device *usbdev = line6->usbdev; 40862306a36Sopenharmony_ci int ret; 40962306a36Sopenharmony_ci unsigned char *status; 41062306a36Sopenharmony_ci int count; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (address > 0xffff || datalen > 0xffff) 41362306a36Sopenharmony_ci return -EINVAL; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci status = kmalloc(1, GFP_KERNEL); 41662306a36Sopenharmony_ci if (!status) 41762306a36Sopenharmony_ci return -ENOMEM; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ret = usb_control_msg_send(usbdev, 0, 0x67, 42062306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 42162306a36Sopenharmony_ci 0x0022, address, data, datalen, LINE6_TIMEOUT, 42262306a36Sopenharmony_ci GFP_KERNEL); 42362306a36Sopenharmony_ci if (ret) { 42462306a36Sopenharmony_ci dev_err(line6->ifcdev, 42562306a36Sopenharmony_ci "write request failed (error %d)\n", ret); 42662306a36Sopenharmony_ci goto exit; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { 43062306a36Sopenharmony_ci mdelay(LINE6_READ_WRITE_STATUS_DELAY); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci ret = usb_control_msg_recv(usbdev, 0, 0x67, 43362306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 43462306a36Sopenharmony_ci 0x0012, 0x0000, status, 1, LINE6_TIMEOUT, 43562306a36Sopenharmony_ci GFP_KERNEL); 43662306a36Sopenharmony_ci if (ret) { 43762306a36Sopenharmony_ci dev_err(line6->ifcdev, 43862306a36Sopenharmony_ci "receiving status failed (error %d)\n", ret); 43962306a36Sopenharmony_ci goto exit; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (*status != 0xff) 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (*status == 0xff) { 44762306a36Sopenharmony_ci dev_err(line6->ifcdev, "write failed after %d retries\n", 44862306a36Sopenharmony_ci count); 44962306a36Sopenharmony_ci ret = -EIO; 45062306a36Sopenharmony_ci } else if (*status != 0) { 45162306a36Sopenharmony_ci dev_err(line6->ifcdev, "write failed (error %d)\n", ret); 45262306a36Sopenharmony_ci ret = -EIO; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ciexit: 45562306a36Sopenharmony_ci kfree(status); 45662306a36Sopenharmony_ci return ret; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_write_data); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* 46162306a36Sopenharmony_ci Read Line 6 device serial number. 46262306a36Sopenharmony_ci (POD, TonePort, GuitarPort) 46362306a36Sopenharmony_ci*/ 46462306a36Sopenharmony_ciint line6_read_serial_number(struct usb_line6 *line6, u32 *serial_number) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci return line6_read_data(line6, 0x80d0, serial_number, 46762306a36Sopenharmony_ci sizeof(*serial_number)); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_read_serial_number); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* 47262306a36Sopenharmony_ci Card destructor. 47362306a36Sopenharmony_ci*/ 47462306a36Sopenharmony_cistatic void line6_destruct(struct snd_card *card) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct usb_line6 *line6 = card->private_data; 47762306a36Sopenharmony_ci struct usb_device *usbdev = line6->usbdev; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Free buffer memory first. We cannot depend on the existence of private 48062306a36Sopenharmony_ci * data from the (podhd) module, it may be gone already during this call 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci kfree(line6->buffer_message); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci kfree(line6->buffer_listen); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* then free URBs: */ 48762306a36Sopenharmony_ci usb_free_urb(line6->urb_listen); 48862306a36Sopenharmony_ci line6->urb_listen = NULL; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* decrement reference counters: */ 49162306a36Sopenharmony_ci usb_put_dev(usbdev); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic void line6_get_usb_properties(struct usb_line6 *line6) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct usb_device *usbdev = line6->usbdev; 49762306a36Sopenharmony_ci const struct line6_properties *properties = line6->properties; 49862306a36Sopenharmony_ci int pipe; 49962306a36Sopenharmony_ci struct usb_host_endpoint *ep = NULL; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (properties->capabilities & LINE6_CAP_CONTROL) { 50262306a36Sopenharmony_ci if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) { 50362306a36Sopenharmony_ci pipe = usb_rcvintpipe(line6->usbdev, 50462306a36Sopenharmony_ci line6->properties->ep_ctrl_r); 50562306a36Sopenharmony_ci } else { 50662306a36Sopenharmony_ci pipe = usb_rcvbulkpipe(line6->usbdev, 50762306a36Sopenharmony_ci line6->properties->ep_ctrl_r); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci ep = usbdev->ep_in[usb_pipeendpoint(pipe)]; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* Control data transfer properties */ 51362306a36Sopenharmony_ci if (ep) { 51462306a36Sopenharmony_ci line6->interval = ep->desc.bInterval; 51562306a36Sopenharmony_ci line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); 51662306a36Sopenharmony_ci } else { 51762306a36Sopenharmony_ci if (properties->capabilities & LINE6_CAP_CONTROL) { 51862306a36Sopenharmony_ci dev_err(line6->ifcdev, 51962306a36Sopenharmony_ci "endpoint not available, using fallback values"); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci line6->interval = LINE6_FALLBACK_INTERVAL; 52262306a36Sopenharmony_ci line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* Isochronous transfer properties */ 52662306a36Sopenharmony_ci if (usbdev->speed == USB_SPEED_LOW) { 52762306a36Sopenharmony_ci line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND; 52862306a36Sopenharmony_ci line6->iso_buffers = USB_LOW_ISO_BUFFERS; 52962306a36Sopenharmony_ci } else { 53062306a36Sopenharmony_ci line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND; 53162306a36Sopenharmony_ci line6->iso_buffers = USB_HIGH_ISO_BUFFERS; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* Enable buffering of incoming messages, flush the buffer */ 53662306a36Sopenharmony_cistatic int line6_hwdep_open(struct snd_hwdep *hw, struct file *file) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct usb_line6 *line6 = hw->private_data; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* NOTE: hwdep layer provides atomicity here */ 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci line6->messages.active = 1; 54362306a36Sopenharmony_ci line6->messages.nonblock = file->f_flags & O_NONBLOCK ? 1 : 0; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci/* Stop buffering */ 54962306a36Sopenharmony_cistatic int line6_hwdep_release(struct snd_hwdep *hw, struct file *file) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct usb_line6 *line6 = hw->private_data; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci line6->messages.active = 0; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/* Read from circular buffer, return to user */ 55962306a36Sopenharmony_cistatic long 56062306a36Sopenharmony_ciline6_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, 56162306a36Sopenharmony_ci loff_t *offset) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct usb_line6 *line6 = hwdep->private_data; 56462306a36Sopenharmony_ci long rv = 0; 56562306a36Sopenharmony_ci unsigned int out_count; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (mutex_lock_interruptible(&line6->messages.read_lock)) 56862306a36Sopenharmony_ci return -ERESTARTSYS; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci while (kfifo_len(&line6->messages.fifo) == 0) { 57162306a36Sopenharmony_ci mutex_unlock(&line6->messages.read_lock); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (line6->messages.nonblock) 57462306a36Sopenharmony_ci return -EAGAIN; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci rv = wait_event_interruptible( 57762306a36Sopenharmony_ci line6->messages.wait_queue, 57862306a36Sopenharmony_ci kfifo_len(&line6->messages.fifo) != 0); 57962306a36Sopenharmony_ci if (rv < 0) 58062306a36Sopenharmony_ci return rv; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (mutex_lock_interruptible(&line6->messages.read_lock)) 58362306a36Sopenharmony_ci return -ERESTARTSYS; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (kfifo_peek_len(&line6->messages.fifo) > count) { 58762306a36Sopenharmony_ci /* Buffer too small; allow re-read of the current item... */ 58862306a36Sopenharmony_ci rv = -EINVAL; 58962306a36Sopenharmony_ci } else { 59062306a36Sopenharmony_ci rv = kfifo_to_user(&line6->messages.fifo, buf, count, &out_count); 59162306a36Sopenharmony_ci if (rv == 0) 59262306a36Sopenharmony_ci rv = out_count; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci mutex_unlock(&line6->messages.read_lock); 59662306a36Sopenharmony_ci return rv; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci/* Write directly (no buffering) to device by user*/ 60062306a36Sopenharmony_cistatic long 60162306a36Sopenharmony_ciline6_hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count, 60262306a36Sopenharmony_ci loff_t *offset) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct usb_line6 *line6 = hwdep->private_data; 60562306a36Sopenharmony_ci int rv; 60662306a36Sopenharmony_ci char *data_copy; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (count > line6->max_packet_size * LINE6_RAW_MESSAGES_MAXCOUNT) { 60962306a36Sopenharmony_ci /* This is an arbitrary limit - still better than nothing... */ 61062306a36Sopenharmony_ci return -EINVAL; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci data_copy = memdup_user(data, count); 61462306a36Sopenharmony_ci if (IS_ERR(data_copy)) 61562306a36Sopenharmony_ci return PTR_ERR(data_copy); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci rv = line6_send_raw_message(line6, data_copy, count); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci kfree(data_copy); 62062306a36Sopenharmony_ci return rv; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic __poll_t 62462306a36Sopenharmony_ciline6_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci __poll_t rv; 62762306a36Sopenharmony_ci struct usb_line6 *line6 = hwdep->private_data; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci poll_wait(file, &line6->messages.wait_queue, wait); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci mutex_lock(&line6->messages.read_lock); 63262306a36Sopenharmony_ci rv = kfifo_len(&line6->messages.fifo) == 0 ? 0 : EPOLLIN | EPOLLRDNORM; 63362306a36Sopenharmony_ci mutex_unlock(&line6->messages.read_lock); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return rv; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic const struct snd_hwdep_ops hwdep_ops = { 63962306a36Sopenharmony_ci .open = line6_hwdep_open, 64062306a36Sopenharmony_ci .release = line6_hwdep_release, 64162306a36Sopenharmony_ci .read = line6_hwdep_read, 64262306a36Sopenharmony_ci .write = line6_hwdep_write, 64362306a36Sopenharmony_ci .poll = line6_hwdep_poll, 64462306a36Sopenharmony_ci}; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/* Insert into circular buffer */ 64762306a36Sopenharmony_cistatic void line6_hwdep_push_message(struct usb_line6 *line6) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci if (!line6->messages.active) 65062306a36Sopenharmony_ci return; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (kfifo_avail(&line6->messages.fifo) >= line6->message_length) { 65362306a36Sopenharmony_ci /* No race condition here, there's only one writer */ 65462306a36Sopenharmony_ci kfifo_in(&line6->messages.fifo, 65562306a36Sopenharmony_ci line6->buffer_message, line6->message_length); 65662306a36Sopenharmony_ci } /* else TODO: signal overflow */ 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci wake_up_interruptible(&line6->messages.wait_queue); 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic int line6_hwdep_init(struct usb_line6 *line6) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci int err; 66462306a36Sopenharmony_ci struct snd_hwdep *hwdep; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* TODO: usb_driver_claim_interface(); */ 66762306a36Sopenharmony_ci line6->process_message = line6_hwdep_push_message; 66862306a36Sopenharmony_ci line6->messages.active = 0; 66962306a36Sopenharmony_ci init_waitqueue_head(&line6->messages.wait_queue); 67062306a36Sopenharmony_ci mutex_init(&line6->messages.read_lock); 67162306a36Sopenharmony_ci INIT_KFIFO(line6->messages.fifo); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci err = snd_hwdep_new(line6->card, "config", 0, &hwdep); 67462306a36Sopenharmony_ci if (err < 0) 67562306a36Sopenharmony_ci goto end; 67662306a36Sopenharmony_ci strcpy(hwdep->name, "config"); 67762306a36Sopenharmony_ci hwdep->iface = SNDRV_HWDEP_IFACE_LINE6; 67862306a36Sopenharmony_ci hwdep->ops = hwdep_ops; 67962306a36Sopenharmony_ci hwdep->private_data = line6; 68062306a36Sopenharmony_ci hwdep->exclusive = true; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ciend: 68362306a36Sopenharmony_ci return err; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic int line6_init_cap_control(struct usb_line6 *line6) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci int ret; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* initialize USB buffers: */ 69162306a36Sopenharmony_ci line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); 69262306a36Sopenharmony_ci if (!line6->buffer_listen) 69362306a36Sopenharmony_ci return -ENOMEM; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); 69662306a36Sopenharmony_ci if (!line6->urb_listen) 69762306a36Sopenharmony_ci return -ENOMEM; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) { 70062306a36Sopenharmony_ci line6->buffer_message = kmalloc(LINE6_MIDI_MESSAGE_MAXLEN, GFP_KERNEL); 70162306a36Sopenharmony_ci if (!line6->buffer_message) 70262306a36Sopenharmony_ci return -ENOMEM; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = line6_init_midi(line6); 70562306a36Sopenharmony_ci if (ret < 0) 70662306a36Sopenharmony_ci return ret; 70762306a36Sopenharmony_ci } else { 70862306a36Sopenharmony_ci ret = line6_hwdep_init(line6); 70962306a36Sopenharmony_ci if (ret < 0) 71062306a36Sopenharmony_ci return ret; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci ret = line6_start_listen(line6); 71462306a36Sopenharmony_ci if (ret < 0) { 71562306a36Sopenharmony_ci dev_err(line6->ifcdev, "cannot start listening: %d\n", ret); 71662306a36Sopenharmony_ci return ret; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci return 0; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic void line6_startup_work(struct work_struct *work) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci struct usb_line6 *line6 = 72562306a36Sopenharmony_ci container_of(work, struct usb_line6, startup_work.work); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (line6->startup) 72862306a36Sopenharmony_ci line6->startup(line6); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci/* 73262306a36Sopenharmony_ci Probe USB device. 73362306a36Sopenharmony_ci*/ 73462306a36Sopenharmony_ciint line6_probe(struct usb_interface *interface, 73562306a36Sopenharmony_ci const struct usb_device_id *id, 73662306a36Sopenharmony_ci const char *driver_name, 73762306a36Sopenharmony_ci const struct line6_properties *properties, 73862306a36Sopenharmony_ci int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), 73962306a36Sopenharmony_ci size_t data_size) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct usb_device *usbdev = interface_to_usbdev(interface); 74262306a36Sopenharmony_ci struct snd_card *card; 74362306a36Sopenharmony_ci struct usb_line6 *line6; 74462306a36Sopenharmony_ci int interface_number; 74562306a36Sopenharmony_ci int ret; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (WARN_ON(data_size < sizeof(*line6))) 74862306a36Sopenharmony_ci return -EINVAL; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* we don't handle multiple configurations */ 75162306a36Sopenharmony_ci if (usbdev->descriptor.bNumConfigurations != 1) 75262306a36Sopenharmony_ci return -ENODEV; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = snd_card_new(&interface->dev, 75562306a36Sopenharmony_ci SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, 75662306a36Sopenharmony_ci THIS_MODULE, data_size, &card); 75762306a36Sopenharmony_ci if (ret < 0) 75862306a36Sopenharmony_ci return ret; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* store basic data: */ 76162306a36Sopenharmony_ci line6 = card->private_data; 76262306a36Sopenharmony_ci line6->card = card; 76362306a36Sopenharmony_ci line6->properties = properties; 76462306a36Sopenharmony_ci line6->usbdev = usbdev; 76562306a36Sopenharmony_ci line6->ifcdev = &interface->dev; 76662306a36Sopenharmony_ci INIT_DELAYED_WORK(&line6->startup_work, line6_startup_work); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci strcpy(card->id, properties->id); 76962306a36Sopenharmony_ci strcpy(card->driver, driver_name); 77062306a36Sopenharmony_ci strcpy(card->shortname, properties->name); 77162306a36Sopenharmony_ci sprintf(card->longname, "Line 6 %s at USB %s", properties->name, 77262306a36Sopenharmony_ci dev_name(line6->ifcdev)); 77362306a36Sopenharmony_ci card->private_free = line6_destruct; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci usb_set_intfdata(interface, line6); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* increment reference counters: */ 77862306a36Sopenharmony_ci usb_get_dev(usbdev); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* initialize device info: */ 78162306a36Sopenharmony_ci dev_info(&interface->dev, "Line 6 %s found\n", properties->name); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* query interface number */ 78462306a36Sopenharmony_ci interface_number = interface->cur_altsetting->desc.bInterfaceNumber; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* TODO reserves the bus bandwidth even without actual transfer */ 78762306a36Sopenharmony_ci ret = usb_set_interface(usbdev, interface_number, 78862306a36Sopenharmony_ci properties->altsetting); 78962306a36Sopenharmony_ci if (ret < 0) { 79062306a36Sopenharmony_ci dev_err(&interface->dev, "set_interface failed\n"); 79162306a36Sopenharmony_ci goto error; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci line6_get_usb_properties(line6); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (properties->capabilities & LINE6_CAP_CONTROL) { 79762306a36Sopenharmony_ci ret = line6_init_cap_control(line6); 79862306a36Sopenharmony_ci if (ret < 0) 79962306a36Sopenharmony_ci goto error; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* initialize device data based on device: */ 80362306a36Sopenharmony_ci ret = private_init(line6, id); 80462306a36Sopenharmony_ci if (ret < 0) 80562306a36Sopenharmony_ci goto error; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* creation of additional special files should go here */ 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci dev_info(&interface->dev, "Line 6 %s now attached\n", 81062306a36Sopenharmony_ci properties->name); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci error: 81562306a36Sopenharmony_ci /* we can call disconnect callback here because no close-sync is 81662306a36Sopenharmony_ci * needed yet at this point 81762306a36Sopenharmony_ci */ 81862306a36Sopenharmony_ci line6_disconnect(interface); 81962306a36Sopenharmony_ci return ret; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_probe); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci/* 82462306a36Sopenharmony_ci Line 6 device disconnected. 82562306a36Sopenharmony_ci*/ 82662306a36Sopenharmony_civoid line6_disconnect(struct usb_interface *interface) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct usb_line6 *line6 = usb_get_intfdata(interface); 82962306a36Sopenharmony_ci struct usb_device *usbdev = interface_to_usbdev(interface); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (!line6) 83262306a36Sopenharmony_ci return; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (WARN_ON(usbdev != line6->usbdev)) 83562306a36Sopenharmony_ci return; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci cancel_delayed_work_sync(&line6->startup_work); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (line6->urb_listen != NULL) 84062306a36Sopenharmony_ci line6_stop_listen(line6); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci snd_card_disconnect(line6->card); 84362306a36Sopenharmony_ci if (line6->line6pcm) 84462306a36Sopenharmony_ci line6_pcm_disconnect(line6->line6pcm); 84562306a36Sopenharmony_ci if (line6->disconnect) 84662306a36Sopenharmony_ci line6->disconnect(line6); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci dev_info(&interface->dev, "Line 6 %s now disconnected\n", 84962306a36Sopenharmony_ci line6->properties->name); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* make sure the device isn't destructed twice: */ 85262306a36Sopenharmony_ci usb_set_intfdata(interface, NULL); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci snd_card_free_when_closed(line6->card); 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_disconnect); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci#ifdef CONFIG_PM 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci/* 86162306a36Sopenharmony_ci Suspend Line 6 device. 86262306a36Sopenharmony_ci*/ 86362306a36Sopenharmony_ciint line6_suspend(struct usb_interface *interface, pm_message_t message) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct usb_line6 *line6 = usb_get_intfdata(interface); 86662306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = line6->line6pcm; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (line6->properties->capabilities & LINE6_CAP_CONTROL) 87162306a36Sopenharmony_ci line6_stop_listen(line6); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (line6pcm != NULL) 87462306a36Sopenharmony_ci line6pcm->flags = 0; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return 0; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_suspend); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci/* 88162306a36Sopenharmony_ci Resume Line 6 device. 88262306a36Sopenharmony_ci*/ 88362306a36Sopenharmony_ciint line6_resume(struct usb_interface *interface) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct usb_line6 *line6 = usb_get_intfdata(interface); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (line6->properties->capabilities & LINE6_CAP_CONTROL) 88862306a36Sopenharmony_ci line6_start_listen(line6); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); 89162306a36Sopenharmony_ci return 0; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_resume); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci#endif /* CONFIG_PM */ 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 89862306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 89962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 90062306a36Sopenharmony_ci 901