]>
Commit | Line | Data |
---|---|---|
c6d43ba8 TS |
1 | /* |
2 | * Linux driver for TerraTec DMX 6Fire USB | |
3 | * | |
4 | * Device communications | |
5 | * | |
6 | * Author: Torsten Schenk <[email protected]> | |
7 | * Created: Jan 01, 2011 | |
c6d43ba8 TS |
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) | |
e3b3757b | 54 | dev_warn(&urb->dev->dev, |
c6d43ba8 TS |
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 | { | |
ddb6b5a9 JK |
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; | |
c6d43ba8 TS |
120 | |
121 | usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00); | |
ddb6b5a9 JK |
122 | ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); |
123 | ||
124 | kfree(buffer); | |
125 | return ret; | |
c6d43ba8 TS |
126 | } |
127 | ||
128 | static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request, | |
129 | u8 reg, u8 vl, u8 vh) | |
130 | { | |
ddb6b5a9 JK |
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; | |
c6d43ba8 TS |
138 | |
139 | usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh); | |
ddb6b5a9 JK |
140 | ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); |
141 | ||
142 | kfree(buffer); | |
143 | return ret; | |
c6d43ba8 TS |
144 | } |
145 | ||
87f9796a | 146 | int usb6fire_comm_init(struct sfire_chip *chip) |
c6d43ba8 TS |
147 | { |
148 | struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime), | |
149 | GFP_KERNEL); | |
27b2a22c | 150 | struct urb *urb; |
c6d43ba8 TS |
151 | int ret; |
152 | ||
153 | if (!rt) | |
154 | return -ENOMEM; | |
155 | ||
ddb6b5a9 JK |
156 | rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL); |
157 | if (!rt->receiver_buffer) { | |
158 | kfree(rt); | |
159 | return -ENOMEM; | |
160 | } | |
161 | ||
27b2a22c | 162 | urb = &rt->receiver; |
c6d43ba8 TS |
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) { | |
ddb6b5a9 | 180 | kfree(rt->receiver_buffer); |
c6d43ba8 | 181 | kfree(rt); |
e3b3757b | 182 | dev_err(&chip->dev->dev, "cannot create comm data receiver."); |
c6d43ba8 TS |
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 | { | |
ddb6b5a9 JK |
199 | struct comm_runtime *rt = chip->comm; |
200 | ||
201 | kfree(rt->receiver_buffer); | |
202 | kfree(rt); | |
c6d43ba8 TS |
203 | chip->comm = NULL; |
204 | } |