xref: /linux/sound/usb/6fire/comm.c (revision 9fe49dbc023e82dfaee7b245997d820d01742a9a)
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 	urb->transfer_buffer = buffer;
25 	urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP);
26 	urb->complete = handler;
27 	urb->context = context;
28 	urb->interval = 1;
29 	urb->dev = rt->chip->dev;
30 }
31 
32 static void usb6fire_comm_receiver_handler(struct urb *urb)
33 {
34 	struct comm_runtime *rt = urb->context;
35 	struct midi_runtime *midi_rt = rt->chip->midi;
36 
37 	if (!urb->status) {
38 		u8 len = rt->receiver_buffer[1];
39 
40 		if (rt->receiver_buffer[0] == 0x10 && /* midi in event */
41 		    len <= COMM_RECEIVER_BUFSIZE - 2 &&
42 		    urb->actual_length >= len + 2)
43 			if (midi_rt)
44 				midi_rt->in_received(midi_rt,
45 						rt->receiver_buffer + 2, len);
46 	}
47 
48 	if (!rt->chip->shutdown) {
49 		urb->status = 0;
50 		urb->actual_length = 0;
51 		if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
52 			dev_warn(&urb->dev->dev,
53 					"comm data receiver aborted.\n");
54 	}
55 }
56 
57 static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request,
58 		u8 reg, u8 vl, u8 vh)
59 {
60 	buffer[0] = 0x01;
61 	buffer[2] = request;
62 	buffer[3] = id;
63 	switch (request) {
64 	case 0x02:
65 		buffer[1] = 0x05; /* length (starting at buffer[2]) */
66 		buffer[4] = reg;
67 		buffer[5] = vl;
68 		buffer[6] = vh;
69 		break;
70 
71 	case 0x12:
72 		buffer[1] = 0x0b; /* length (starting at buffer[2]) */
73 		buffer[4] = 0x00;
74 		buffer[5] = 0x18;
75 		buffer[6] = 0x05;
76 		buffer[7] = 0x00;
77 		buffer[8] = 0x01;
78 		buffer[9] = 0x00;
79 		buffer[10] = 0x9e;
80 		buffer[11] = reg;
81 		buffer[12] = vl;
82 		break;
83 
84 	case 0x20:
85 	case 0x21:
86 	case 0x22:
87 		buffer[1] = 0x04;
88 		buffer[4] = reg;
89 		buffer[5] = vl;
90 		break;
91 	}
92 }
93 
94 static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)
95 {
96 	int ret;
97 	int actual_len;
98 
99 	ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP),
100 			buffer, buffer[1] + 2, &actual_len, 1000);
101 	if (ret < 0)
102 		return ret;
103 	else if (actual_len != buffer[1] + 2)
104 		return -EIO;
105 	return 0;
106 }
107 
108 static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,
109 		u8 reg, u8 value)
110 {
111 	u8 *buffer;
112 	int ret;
113 
114 	/* 13: maximum length of message */
115 	buffer = kmalloc(13, GFP_KERNEL);
116 	if (!buffer)
117 		return -ENOMEM;
118 
119 	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
120 	ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
121 
122 	kfree(buffer);
123 	return ret;
124 }
125 
126 static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
127 		u8 reg, u8 vl, u8 vh)
128 {
129 	u8 *buffer;
130 	int ret;
131 
132 	/* 13: maximum length of message */
133 	buffer = kmalloc(13, GFP_KERNEL);
134 	if (!buffer)
135 		return -ENOMEM;
136 
137 	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
138 	ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
139 
140 	kfree(buffer);
141 	return ret;
142 }
143 
144 static void usb6fire_comm_free(struct comm_runtime *rt)
145 {
146 	if (!rt)
147 		return;
148 
149 	if (rt->chip)
150 		rt->chip->comm = NULL;
151 
152 	usb_free_urb(rt->receiver);
153 	kfree(rt->receiver_buffer);
154 	kfree(rt);
155 }
156 
157 int usb6fire_comm_init(struct sfire_chip *chip)
158 {
159 	struct comm_runtime *rt = kzalloc_obj(struct comm_runtime);
160 	struct urb *urb;
161 	int ret;
162 
163 	if (!rt)
164 		return -ENOMEM;
165 
166 	rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);
167 	if (!rt->receiver_buffer) {
168 		ret = -ENOMEM;
169 		goto error;
170 	}
171 
172 	urb = usb_alloc_urb(0, GFP_KERNEL);
173 	if (!urb) {
174 		ret = -ENOMEM;
175 		goto error;
176 	}
177 	rt->receiver = urb;
178 	rt->serial = 1;
179 	rt->chip = chip;
180 	rt->init_urb = usb6fire_comm_init_urb;
181 	rt->write8 = usb6fire_comm_write8;
182 	rt->write16 = usb6fire_comm_write16;
183 
184 	/* submit an urb that receives communication data from device */
185 	urb->transfer_buffer = rt->receiver_buffer;
186 	urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE;
187 	urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP);
188 	urb->dev = chip->dev;
189 	urb->complete = usb6fire_comm_receiver_handler;
190 	urb->context = rt;
191 	urb->interval = 1;
192 	ret = usb_submit_urb(urb, GFP_KERNEL);
193 	if (ret < 0) {
194 		dev_err(&chip->dev->dev, "cannot create comm data receiver.");
195 		goto error;
196 	}
197 	chip->comm = rt;
198 	return 0;
199 
200  error:
201 	usb6fire_comm_free(rt);
202 	return ret;
203 }
204 
205 void usb6fire_comm_abort(struct sfire_chip *chip)
206 {
207 	struct comm_runtime *rt = chip->comm;
208 
209 	if (rt)
210 		usb_poison_urb(rt->receiver);
211 }
212 
213 void usb6fire_comm_destroy(struct sfire_chip *chip)
214 {
215 	usb6fire_comm_free(chip->comm);
216 }
217