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
usb6fire_comm_init_urb(struct comm_runtime * rt,struct urb * urb,u8 * buffer,void * context,void (* handler)(struct urb * urb))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
usb6fire_comm_receiver_handler(struct urb * urb)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
usb6fire_comm_init_buffer(u8 * buffer,u8 id,u8 request,u8 reg,u8 vl,u8 vh)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
usb6fire_comm_send_buffer(u8 * buffer,struct usb_device * dev)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
usb6fire_comm_write8(struct comm_runtime * rt,u8 request,u8 reg,u8 value)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
usb6fire_comm_write16(struct comm_runtime * rt,u8 request,u8 reg,u8 vl,u8 vh)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
usb6fire_comm_init(struct sfire_chip * chip)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
usb6fire_comm_abort(struct sfire_chip * chip)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
usb6fire_comm_destroy(struct sfire_chip * chip)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