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