1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Linux driver for TerraTec DMX 6Fire USB 4 * 5 * Device communications 6 * 7 * Author: Torsten Schenk <torsten.schenk@zoho.com> 8 * Created: Jan 01, 2011 9 * Copyright: (C) Torsten Schenk 10 */ 11 12 #include "comm.h" 13 #include "chip.h" 14 #include "midi.h" 15 16 enum { 17 COMM_EP = 1, 18 COMM_FPGA_EP = 2 19 }; 20 21 static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb, 22 u8 *buffer, void *context, void(*handler)(struct urb *urb)) 23 { 24 usb_init_urb(urb); 25 urb->transfer_buffer = buffer; 26 urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP); 27 urb->complete = handler; 28 urb->context = context; 29 urb->interval = 1; 30 urb->dev = rt->chip->dev; 31 } 32 33 static void usb6fire_comm_receiver_handler(struct urb *urb) 34 { 35 struct comm_runtime *rt = urb->context; 36 struct midi_runtime *midi_rt = rt->chip->midi; 37 38 if (!urb->status) { 39 if (rt->receiver_buffer[0] == 0x10) /* midi in event */ 40 if (midi_rt) 41 midi_rt->in_received(midi_rt, 42 rt->receiver_buffer + 2, 43 rt->receiver_buffer[1]); 44 } 45 46 if (!rt->chip->shutdown) { 47 urb->status = 0; 48 urb->actual_length = 0; 49 if (usb_submit_urb(urb, GFP_ATOMIC) < 0) 50 dev_warn(&urb->dev->dev, 51 "comm data receiver aborted.\n"); 52 } 53 } 54 55 static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request, 56 u8 reg, u8 vl, u8 vh) 57 { 58 buffer[0] = 0x01; 59 buffer[2] = request; 60 buffer[3] = id; 61 switch (request) { 62 case 0x02: 63 buffer[1] = 0x05; /* length (starting at buffer[2]) */ 64 buffer[4] = reg; 65 buffer[5] = vl; 66 buffer[6] = vh; 67 break; 68 69 case 0x12: 70 buffer[1] = 0x0b; /* length (starting at buffer[2]) */ 71 buffer[4] = 0x00; 72 buffer[5] = 0x18; 73 buffer[6] = 0x05; 74 buffer[7] = 0x00; 75 buffer[8] = 0x01; 76 buffer[9] = 0x00; 77 buffer[10] = 0x9e; 78 buffer[11] = reg; 79 buffer[12] = vl; 80 break; 81 82 case 0x20: 83 case 0x21: 84 case 0x22: 85 buffer[1] = 0x04; 86 buffer[4] = reg; 87 buffer[5] = vl; 88 break; 89 } 90 } 91 92 static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev) 93 { 94 int ret; 95 int actual_len; 96 97 ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP), 98 buffer, buffer[1] + 2, &actual_len, 1000); 99 if (ret < 0) 100 return ret; 101 else if (actual_len != buffer[1] + 2) 102 return -EIO; 103 return 0; 104 } 105 106 static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request, 107 u8 reg, u8 value) 108 { 109 u8 *buffer; 110 int ret; 111 112 /* 13: maximum length of message */ 113 buffer = kmalloc(13, GFP_KERNEL); 114 if (!buffer) 115 return -ENOMEM; 116 117 usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00); 118 ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); 119 120 kfree(buffer); 121 return ret; 122 } 123 124 static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request, 125 u8 reg, u8 vl, u8 vh) 126 { 127 u8 *buffer; 128 int ret; 129 130 /* 13: maximum length of message */ 131 buffer = kmalloc(13, GFP_KERNEL); 132 if (!buffer) 133 return -ENOMEM; 134 135 usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh); 136 ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); 137 138 kfree(buffer); 139 return ret; 140 } 141 142 int usb6fire_comm_init(struct sfire_chip *chip) 143 { 144 struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime), 145 GFP_KERNEL); 146 struct urb *urb; 147 int ret; 148 149 if (!rt) 150 return -ENOMEM; 151 152 rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL); 153 if (!rt->receiver_buffer) { 154 kfree(rt); 155 return -ENOMEM; 156 } 157 158 urb = &rt->receiver; 159 rt->serial = 1; 160 rt->chip = chip; 161 usb_init_urb(urb); 162 rt->init_urb = usb6fire_comm_init_urb; 163 rt->write8 = usb6fire_comm_write8; 164 rt->write16 = usb6fire_comm_write16; 165 166 /* submit an urb that receives communication data from device */ 167 urb->transfer_buffer = rt->receiver_buffer; 168 urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE; 169 urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP); 170 urb->dev = chip->dev; 171 urb->complete = usb6fire_comm_receiver_handler; 172 urb->context = rt; 173 urb->interval = 1; 174 ret = usb_submit_urb(urb, GFP_KERNEL); 175 if (ret < 0) { 176 kfree(rt->receiver_buffer); 177 kfree(rt); 178 dev_err(&chip->dev->dev, "cannot create comm data receiver."); 179 return ret; 180 } 181 chip->comm = rt; 182 return 0; 183 } 184 185 void usb6fire_comm_abort(struct sfire_chip *chip) 186 { 187 struct comm_runtime *rt = chip->comm; 188 189 if (rt) 190 usb_poison_urb(&rt->receiver); 191 } 192 193 void usb6fire_comm_destroy(struct sfire_chip *chip) 194 { 195 struct comm_runtime *rt = chip->comm; 196 197 kfree(rt->receiver_buffer); 198 kfree(rt); 199 chip->comm = NULL; 200 } 201
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.