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