162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Linux driver for TerraTec DMX 6Fire USB 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Device communications 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Torsten Schenk <torsten.schenk@zoho.com> 862306a36Sopenharmony_ci * Created: Jan 01, 2011 962306a36Sopenharmony_ci * Copyright: (C) Torsten Schenk 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "comm.h" 1362306a36Sopenharmony_ci#include "chip.h" 1462306a36Sopenharmony_ci#include "midi.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cienum { 1762306a36Sopenharmony_ci COMM_EP = 1, 1862306a36Sopenharmony_ci COMM_FPGA_EP = 2 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb, 2262306a36Sopenharmony_ci u8 *buffer, void *context, void(*handler)(struct urb *urb)) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci usb_init_urb(urb); 2562306a36Sopenharmony_ci urb->transfer_buffer = buffer; 2662306a36Sopenharmony_ci urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP); 2762306a36Sopenharmony_ci urb->complete = handler; 2862306a36Sopenharmony_ci urb->context = context; 2962306a36Sopenharmony_ci urb->interval = 1; 3062306a36Sopenharmony_ci urb->dev = rt->chip->dev; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic void usb6fire_comm_receiver_handler(struct urb *urb) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct comm_runtime *rt = urb->context; 3662306a36Sopenharmony_ci struct midi_runtime *midi_rt = rt->chip->midi; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (!urb->status) { 3962306a36Sopenharmony_ci if (rt->receiver_buffer[0] == 0x10) /* midi in event */ 4062306a36Sopenharmony_ci if (midi_rt) 4162306a36Sopenharmony_ci midi_rt->in_received(midi_rt, 4262306a36Sopenharmony_ci rt->receiver_buffer + 2, 4362306a36Sopenharmony_ci rt->receiver_buffer[1]); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (!rt->chip->shutdown) { 4762306a36Sopenharmony_ci urb->status = 0; 4862306a36Sopenharmony_ci urb->actual_length = 0; 4962306a36Sopenharmony_ci if (usb_submit_urb(urb, GFP_ATOMIC) < 0) 5062306a36Sopenharmony_ci dev_warn(&urb->dev->dev, 5162306a36Sopenharmony_ci "comm data receiver aborted.\n"); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request, 5662306a36Sopenharmony_ci u8 reg, u8 vl, u8 vh) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci buffer[0] = 0x01; 5962306a36Sopenharmony_ci buffer[2] = request; 6062306a36Sopenharmony_ci buffer[3] = id; 6162306a36Sopenharmony_ci switch (request) { 6262306a36Sopenharmony_ci case 0x02: 6362306a36Sopenharmony_ci buffer[1] = 0x05; /* length (starting at buffer[2]) */ 6462306a36Sopenharmony_ci buffer[4] = reg; 6562306a36Sopenharmony_ci buffer[5] = vl; 6662306a36Sopenharmony_ci buffer[6] = vh; 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci case 0x12: 7062306a36Sopenharmony_ci buffer[1] = 0x0b; /* length (starting at buffer[2]) */ 7162306a36Sopenharmony_ci buffer[4] = 0x00; 7262306a36Sopenharmony_ci buffer[5] = 0x18; 7362306a36Sopenharmony_ci buffer[6] = 0x05; 7462306a36Sopenharmony_ci buffer[7] = 0x00; 7562306a36Sopenharmony_ci buffer[8] = 0x01; 7662306a36Sopenharmony_ci buffer[9] = 0x00; 7762306a36Sopenharmony_ci buffer[10] = 0x9e; 7862306a36Sopenharmony_ci buffer[11] = reg; 7962306a36Sopenharmony_ci buffer[12] = vl; 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci case 0x20: 8362306a36Sopenharmony_ci case 0x21: 8462306a36Sopenharmony_ci case 0x22: 8562306a36Sopenharmony_ci buffer[1] = 0x04; 8662306a36Sopenharmony_ci buffer[4] = reg; 8762306a36Sopenharmony_ci buffer[5] = vl; 8862306a36Sopenharmony_ci break; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci int ret; 9562306a36Sopenharmony_ci int actual_len; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP), 9862306a36Sopenharmony_ci buffer, buffer[1] + 2, &actual_len, 1000); 9962306a36Sopenharmony_ci if (ret < 0) 10062306a36Sopenharmony_ci return ret; 10162306a36Sopenharmony_ci else if (actual_len != buffer[1] + 2) 10262306a36Sopenharmony_ci return -EIO; 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int usb6fire_comm_write8(struct comm_runtime *rt, u8 request, 10762306a36Sopenharmony_ci u8 reg, u8 value) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci u8 *buffer; 11062306a36Sopenharmony_ci int ret; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* 13: maximum length of message */ 11362306a36Sopenharmony_ci buffer = kmalloc(13, GFP_KERNEL); 11462306a36Sopenharmony_ci if (!buffer) 11562306a36Sopenharmony_ci return -ENOMEM; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00); 11862306a36Sopenharmony_ci ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci kfree(buffer); 12162306a36Sopenharmony_ci return ret; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int usb6fire_comm_write16(struct comm_runtime *rt, u8 request, 12562306a36Sopenharmony_ci u8 reg, u8 vl, u8 vh) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci u8 *buffer; 12862306a36Sopenharmony_ci int ret; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13: maximum length of message */ 13162306a36Sopenharmony_ci buffer = kmalloc(13, GFP_KERNEL); 13262306a36Sopenharmony_ci if (!buffer) 13362306a36Sopenharmony_ci return -ENOMEM; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh); 13662306a36Sopenharmony_ci ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci kfree(buffer); 13962306a36Sopenharmony_ci return ret; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ciint usb6fire_comm_init(struct sfire_chip *chip) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime), 14562306a36Sopenharmony_ci GFP_KERNEL); 14662306a36Sopenharmony_ci struct urb *urb; 14762306a36Sopenharmony_ci int ret; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (!rt) 15062306a36Sopenharmony_ci return -ENOMEM; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL); 15362306a36Sopenharmony_ci if (!rt->receiver_buffer) { 15462306a36Sopenharmony_ci kfree(rt); 15562306a36Sopenharmony_ci return -ENOMEM; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci urb = &rt->receiver; 15962306a36Sopenharmony_ci rt->serial = 1; 16062306a36Sopenharmony_ci rt->chip = chip; 16162306a36Sopenharmony_ci usb_init_urb(urb); 16262306a36Sopenharmony_ci rt->init_urb = usb6fire_comm_init_urb; 16362306a36Sopenharmony_ci rt->write8 = usb6fire_comm_write8; 16462306a36Sopenharmony_ci rt->write16 = usb6fire_comm_write16; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* submit an urb that receives communication data from device */ 16762306a36Sopenharmony_ci urb->transfer_buffer = rt->receiver_buffer; 16862306a36Sopenharmony_ci urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE; 16962306a36Sopenharmony_ci urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP); 17062306a36Sopenharmony_ci urb->dev = chip->dev; 17162306a36Sopenharmony_ci urb->complete = usb6fire_comm_receiver_handler; 17262306a36Sopenharmony_ci urb->context = rt; 17362306a36Sopenharmony_ci urb->interval = 1; 17462306a36Sopenharmony_ci ret = usb_submit_urb(urb, GFP_KERNEL); 17562306a36Sopenharmony_ci if (ret < 0) { 17662306a36Sopenharmony_ci kfree(rt->receiver_buffer); 17762306a36Sopenharmony_ci kfree(rt); 17862306a36Sopenharmony_ci dev_err(&chip->dev->dev, "cannot create comm data receiver."); 17962306a36Sopenharmony_ci return ret; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci chip->comm = rt; 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_civoid usb6fire_comm_abort(struct sfire_chip *chip) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct comm_runtime *rt = chip->comm; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (rt) 19062306a36Sopenharmony_ci usb_poison_urb(&rt->receiver); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_civoid usb6fire_comm_destroy(struct sfire_chip *chip) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct comm_runtime *rt = chip->comm; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci kfree(rt->receiver_buffer); 19862306a36Sopenharmony_ci kfree(rt); 19962306a36Sopenharmony_ci chip->comm = NULL; 20062306a36Sopenharmony_ci} 201