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