xref: /linux/sound/usb/6fire/comm.c (revision 93d90ad708b8da6efc0e487b66111aa9db7f70c7)
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  * 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)
54 			dev_warn(&urb->dev->dev,
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 {
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;
120 
121 	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
122 	ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
123 
124 	kfree(buffer);
125 	return ret;
126 }
127 
128 static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
129 		u8 reg, u8 vl, u8 vh)
130 {
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;
138 
139 	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
140 	ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
141 
142 	kfree(buffer);
143 	return ret;
144 }
145 
146 int usb6fire_comm_init(struct sfire_chip *chip)
147 {
148 	struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
149 			GFP_KERNEL);
150 	struct urb *urb;
151 	int ret;
152 
153 	if (!rt)
154 		return -ENOMEM;
155 
156 	rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);
157 	if (!rt->receiver_buffer) {
158 		kfree(rt);
159 		return -ENOMEM;
160 	}
161 
162 	urb = &rt->receiver;
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) {
180 		kfree(rt->receiver_buffer);
181 		kfree(rt);
182 		dev_err(&chip->dev->dev, "cannot create comm data receiver.");
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 {
199 	struct comm_runtime *rt = chip->comm;
200 
201 	kfree(rt->receiver_buffer);
202 	kfree(rt);
203 	chip->comm = NULL;
204 }
205