xref: /haiku/src/add-ons/kernel/drivers/common/usb_modeswitch.cpp (revision e5d65858f2361fe0552495b61620c84dcee6bc00)
1 /*
2  * Copyright 2010, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Jérôme Duval, korli@users.berlios.de
7  */
8 
9 /*
10 	Devices and messages reference: usb-modeswitch-data-20100826
11 */
12 
13 #include <ByteOrder.h>
14 #include <Drivers.h>
15 #include <KernelExport.h>
16 #include <lock.h>
17 #include <USB3.h>
18 
19 #include <malloc.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 #define DRIVER_NAME			"usb_modeswitch"
24 
25 #define TRACE_USB_MODESWITCH 1
26 #ifdef TRACE_USB_MODESWITCH
27 #define TRACE(x...)			dprintf(DRIVER_NAME": "x)
28 #else
29 #define TRACE(x...)			/* nothing */
30 #endif
31 #define TRACE_ALWAYS(x...)	dprintf(DRIVER_NAME": "x)
32 #define ENTER()	TRACE("%s", __FUNCTION__)
33 
34 
35 enum msgType {
36 	MSG_HUAWEI_1 = 0,
37 	MSG_HUAWEI_2,
38 	MSG_HUAWEI_3,
39 	MSG_NOKIA_1,
40 	MSG_OLIVETTI_1,
41 	MSG_OLIVETTI_2,
42 	MSG_OPTION_1,
43 	MSG_ATHEROS_1,
44 	MSG_ZTE_1,
45 	MSG_ZTE_2,
46 	MSG_ZTE_3,
47 	MSG_NONE
48 };
49 
50 
51 unsigned char kDevicesMsg[][31] = {
52 	{ 	/* MSG_HUAWEI_1 */
53 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
54 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
55 		0x06, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
56 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
57 	},
58 	{	/* MSG_HUAWEI_2 */
59 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
60 		0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x0a, 0x11,
61 		0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
63 	},
64 	{ 	/* MSG_HUAWEI_3 */
65 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
66 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
67 		0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
68 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
69 	},
70 	{	/* MSG_NOKIA_1 */
71 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
72 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1b,
73 		0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
74 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
75 	},
76 	{	/* MSG_OLIVETTI_1 */
77 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
78 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1b,
79 		0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
80 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81 	},
82 	{	/* MSG_OLIVETTI_2 */
83 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
84 		0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x06,
85 		0xf5, 0x04, 0x02, 0x52, 0x70, 0x00, 0x00, 0x00,
86 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
87 	},
88 	{	/* MSG_OPTION_1 */
89 		0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12,
90 		0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x10,
91 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
93 	},
94 	{	/* MSG_ATHEROS_1 */
95 		0x55, 0x53, 0x42, 0x43, 0x29, 0x00, 0x00, 0x00,
96 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1b,
97 		0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
98 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
99 	},
100 	{	/* MSG_ZTE_1 */
101 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
102 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1e,
103 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
105 	},
106 	{	/* MSG_ZTE_2 */
107 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x79,
108 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1b,
109 		0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
110 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
111 	},
112 	{	/* MSG_ZTE_3 */
113 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x70,
114 		0x20, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0c, 0x85,
115 		0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
116 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
117 	}
118 };
119 
120 
121 #define HUAWEI_VENDOR	0x12d1
122 #define NOKIA_VENDOR	0x0421
123 #define NOVATEL_VENDOR	0x1410
124 #define ZYDAS_VENDOR	0x0ace
125 #define ZTE_VENDOR	0x19d2
126 #define OLIVETTI_VENDOR	0x0b3c
127 #define OPTION_VENDOR	0x0af0
128 #define ATHEROS_VENDOR	0x0cf3
129 
130 
131 static const struct {
132 	usb_support_descriptor desc;
133 	msgType type, type2, type3;
134 } kDevices[] = {
135 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x101e}, MSG_HUAWEI_1},
136 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1446}, MSG_HUAWEI_1},
137 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1449}, MSG_HUAWEI_1},
138 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14ad}, MSG_HUAWEI_1},
139 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14b5}, MSG_HUAWEI_1},
140 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14b7}, MSG_HUAWEI_1},
141 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14ba}, MSG_HUAWEI_1},
142 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14c1}, MSG_HUAWEI_1},
143 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14c3}, MSG_HUAWEI_1},
144 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14c4}, MSG_HUAWEI_1},
145 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14c5}, MSG_HUAWEI_1},
146 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14d1}, MSG_HUAWEI_1},
147 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x14fe}, MSG_HUAWEI_1},
148 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1505}, MSG_HUAWEI_1},
149 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x151a}, MSG_HUAWEI_1},
150 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1520}, MSG_HUAWEI_1},
151 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1521}, MSG_HUAWEI_1},
152 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1523}, MSG_HUAWEI_1},
153 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1526}, MSG_HUAWEI_1},
154 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1553}, MSG_HUAWEI_1},
155 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1557}, MSG_HUAWEI_1},
156 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x155b}, MSG_HUAWEI_1},
157 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1c0b}, MSG_HUAWEI_1},
158 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1c24}, MSG_HUAWEI_1},
159 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1f11}, MSG_HUAWEI_1},
160 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1030}, MSG_HUAWEI_2},
161 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1031}, MSG_HUAWEI_2},
162 	{{ 0, 0, 0, HUAWEI_VENDOR, 0x1f01}, MSG_HUAWEI_3},
163 	{{ 0, 0, 0, NOKIA_VENDOR, 0x060c}, MSG_NOKIA_1},
164 	{{ 0, 0, 0, NOKIA_VENDOR, 0x0610}, MSG_NOKIA_1},
165 	{{ 0, 0, 0, NOKIA_VENDOR, 0x061d}, MSG_NOKIA_1},
166 	{{ 0, 0, 0, NOKIA_VENDOR, 0x0622}, MSG_NOKIA_1},
167 	{{ 0, 0, 0, NOKIA_VENDOR, 0x0627}, MSG_NOKIA_1},
168 	{{ 0, 0, 0, NOKIA_VENDOR, 0x062c}, MSG_NOKIA_1},
169 	{{ 0, 0, 0, NOKIA_VENDOR, 0x0632}, MSG_NOKIA_1},
170 	{{ 0, 0, 0, NOKIA_VENDOR, 0x0637}, MSG_NOKIA_1},
171 	{{ 0, 0, 0, NOVATEL_VENDOR, 0x5010}, MSG_NOKIA_1},
172 	{{ 0, 0, 0, NOVATEL_VENDOR, 0x5020}, MSG_NOKIA_1},
173 	{{ 0, 0, 0, NOVATEL_VENDOR, 0x5030}, MSG_NOKIA_1},
174 	{{ 0, 0, 0, NOVATEL_VENDOR, 0x5031}, MSG_NOKIA_1},
175 	{{ 0, 0, 0, NOVATEL_VENDOR, 0x5041}, MSG_NOKIA_1},
176 	{{ 0, 0, 0, NOVATEL_VENDOR, 0x5059}, MSG_NOKIA_1},
177 	{{ 0, 0, 0, NOVATEL_VENDOR, 0x7001}, MSG_NOKIA_1},
178 	{{ 0, 0, 0, ZYDAS_VENDOR, 0x2011}, MSG_NOKIA_1},
179 	{{ 0, 0, 0, ZYDAS_VENDOR, 0x20ff}, MSG_NOKIA_1},
180 	{{ 0, 0, 0, ZTE_VENDOR, 0x0013}, MSG_NOKIA_1},
181 	{{ 0, 0, 0, ZTE_VENDOR, 0x0026}, MSG_NOKIA_1},
182 	{{ 0, 0, 0, ZTE_VENDOR, 0x0031}, MSG_NOKIA_1},
183 	{{ 0, 0, 0, ZTE_VENDOR, 0x0083}, MSG_NOKIA_1},
184 	{{ 0, 0, 0, ZTE_VENDOR, 0x0101}, MSG_NOKIA_1},
185 	{{ 0, 0, 0, ZTE_VENDOR, 0x0115}, MSG_NOKIA_1},
186 	{{ 0, 0, 0, ZTE_VENDOR, 0x0120}, MSG_NOKIA_1},
187 	{{ 0, 0, 0, ZTE_VENDOR, 0x0169}, MSG_NOKIA_1},
188 	{{ 0, 0, 0, ZTE_VENDOR, 0x0325}, MSG_NOKIA_1},
189 	{{ 0, 0, 0, ZTE_VENDOR, 0x1001}, MSG_NOKIA_1},
190 	{{ 0, 0, 0, ZTE_VENDOR, 0x1007}, MSG_NOKIA_1},
191 	{{ 0, 0, 0, ZTE_VENDOR, 0x1009}, MSG_NOKIA_1},
192 	{{ 0, 0, 0, ZTE_VENDOR, 0x1013}, MSG_NOKIA_1},
193 	{{ 0, 0, 0, ZTE_VENDOR, 0x1017}, MSG_NOKIA_1},
194 	{{ 0, 0, 0, ZTE_VENDOR, 0x1171}, MSG_NOKIA_1},
195 	{{ 0, 0, 0, ZTE_VENDOR, 0x1175}, MSG_NOKIA_1},
196 	{{ 0, 0, 0, ZTE_VENDOR, 0x1179}, MSG_NOKIA_1},
197 	{{ 0, 0, 0, ZTE_VENDOR, 0x1201}, MSG_NOKIA_1},
198 	{{ 0, 0, 0, ZTE_VENDOR, 0x1523}, MSG_NOKIA_1},
199 	{{ 0, 0, 0, ZTE_VENDOR, 0xffde}, MSG_NOKIA_1},
200 	{{ 0, 0, 0, ZTE_VENDOR, 0x0003}, MSG_ZTE_1, MSG_ZTE_2},
201 	{{ 0, 0, 0, ZTE_VENDOR, 0x0053}, MSG_ZTE_1, MSG_ZTE_2},
202 	{{ 0, 0, 0, ZTE_VENDOR, 0x0103}, MSG_ZTE_1, MSG_ZTE_2},
203 	{{ 0, 0, 0, ZTE_VENDOR, 0x0154}, MSG_ZTE_1, MSG_ZTE_2},
204 	{{ 0, 0, 0, ZTE_VENDOR, 0x1224}, MSG_ZTE_1, MSG_ZTE_2},
205 	{{ 0, 0, 0, ZTE_VENDOR, 0x1517}, MSG_ZTE_1, MSG_ZTE_2},
206 	{{ 0, 0, 0, ZTE_VENDOR, 0x1542}, MSG_ZTE_1, MSG_ZTE_2},
207 	{{ 0, 0, 0, ZTE_VENDOR, 0x0149}, MSG_ZTE_1, MSG_ZTE_2, MSG_ZTE_3},
208 	{{ 0, 0, 0, ZTE_VENDOR, 0x2000}, MSG_ZTE_1, MSG_ZTE_2, MSG_ZTE_3},
209 	{{ 0, 0, 0, OLIVETTI_VENDOR, 0xc700}, MSG_OLIVETTI_1},
210 	{{ 0, 0, 0, OLIVETTI_VENDOR, 0xf000}, MSG_OLIVETTI_2},
211 	{{ 0, 0, 0, OPTION_VENDOR, 0x6711}, MSG_OPTION_1},
212 	{{ 0, 0, 0, OPTION_VENDOR, 0x6731}, MSG_OPTION_1},
213 	{{ 0, 0, 0, OPTION_VENDOR, 0x6751}, MSG_OPTION_1},
214 	{{ 0, 0, 0, OPTION_VENDOR, 0x6771}, MSG_OPTION_1},
215 	{{ 0, 0, 0, OPTION_VENDOR, 0x6791}, MSG_OPTION_1},
216 	{{ 0, 0, 0, OPTION_VENDOR, 0x6811}, MSG_OPTION_1},
217 	{{ 0, 0, 0, OPTION_VENDOR, 0x6911}, MSG_OPTION_1},
218 	{{ 0, 0, 0, OPTION_VENDOR, 0x6951}, MSG_OPTION_1},
219 	{{ 0, 0, 0, OPTION_VENDOR, 0x6971}, MSG_OPTION_1},
220 	{{ 0, 0, 0, OPTION_VENDOR, 0x7011}, MSG_OPTION_1},
221 	{{ 0, 0, 0, OPTION_VENDOR, 0x7031}, MSG_OPTION_1},
222 	{{ 0, 0, 0, OPTION_VENDOR, 0x7051}, MSG_OPTION_1},
223 	{{ 0, 0, 0, OPTION_VENDOR, 0x7071}, MSG_OPTION_1},
224 	{{ 0, 0, 0, OPTION_VENDOR, 0x7111}, MSG_OPTION_1},
225 	{{ 0, 0, 0, OPTION_VENDOR, 0x7211}, MSG_OPTION_1},
226 	{{ 0, 0, 0, OPTION_VENDOR, 0x7251}, MSG_OPTION_1},
227 	{{ 0, 0, 0, OPTION_VENDOR, 0x7271}, MSG_OPTION_1},
228 	{{ 0, 0, 0, OPTION_VENDOR, 0x7301}, MSG_OPTION_1},
229 	{{ 0, 0, 0, OPTION_VENDOR, 0x7311}, MSG_OPTION_1},
230 	{{ 0, 0, 0, OPTION_VENDOR, 0x7361}, MSG_OPTION_1},
231 	{{ 0, 0, 0, OPTION_VENDOR, 0x7381}, MSG_OPTION_1},
232 	{{ 0, 0, 0, OPTION_VENDOR, 0x7401}, MSG_OPTION_1},
233 	{{ 0, 0, 0, OPTION_VENDOR, 0x7501}, MSG_OPTION_1},
234 	{{ 0, 0, 0, OPTION_VENDOR, 0x7601}, MSG_OPTION_1},
235 	{{ 0, 0, 0, OPTION_VENDOR, 0x7701}, MSG_OPTION_1},
236 	{{ 0, 0, 0, OPTION_VENDOR, 0x7706}, MSG_OPTION_1},
237 	{{ 0, 0, 0, OPTION_VENDOR, 0x7801}, MSG_OPTION_1},
238 	{{ 0, 0, 0, OPTION_VENDOR, 0x7901}, MSG_OPTION_1},
239 	{{ 0, 0, 0, OPTION_VENDOR, 0x8006}, MSG_OPTION_1},
240 	{{ 0, 0, 0, OPTION_VENDOR, 0x8200}, MSG_OPTION_1},
241 	{{ 0, 0, 0, OPTION_VENDOR, 0x8201}, MSG_OPTION_1},
242 	{{ 0, 0, 0, OPTION_VENDOR, 0x8300}, MSG_OPTION_1},
243 	{{ 0, 0, 0, OPTION_VENDOR, 0x8302}, MSG_OPTION_1},
244 	{{ 0, 0, 0, OPTION_VENDOR, 0x8304}, MSG_OPTION_1},
245 	{{ 0, 0, 0, OPTION_VENDOR, 0x8400}, MSG_OPTION_1},
246 	{{ 0, 0, 0, OPTION_VENDOR, 0x8600}, MSG_OPTION_1},
247 	{{ 0, 0, 0, OPTION_VENDOR, 0x8800}, MSG_OPTION_1},
248 	{{ 0, 0, 0, OPTION_VENDOR, 0x8900}, MSG_OPTION_1},
249 	{{ 0, 0, 0, OPTION_VENDOR, 0x9000}, MSG_OPTION_1},
250 	{{ 0, 0, 0, OPTION_VENDOR, 0xc031}, MSG_OPTION_1},
251 	{{ 0, 0, 0, OPTION_VENDOR, 0xc100}, MSG_OPTION_1},
252 	{{ 0, 0, 0, OPTION_VENDOR, 0xc031}, MSG_OPTION_1},
253 	{{ 0, 0, 0, OPTION_VENDOR, 0xd013}, MSG_OPTION_1},
254 	{{ 0, 0, 0, OPTION_VENDOR, 0xd031}, MSG_OPTION_1},
255 	{{ 0, 0, 0, OPTION_VENDOR, 0xd033}, MSG_OPTION_1},
256 	{{ 0, 0, 0, OPTION_VENDOR, 0xd035}, MSG_OPTION_1},
257 	{{ 0, 0, 0, OPTION_VENDOR, 0xd055}, MSG_OPTION_1},
258 	{{ 0, 0, 0, OPTION_VENDOR, 0xd057}, MSG_OPTION_1},
259 	{{ 0, 0, 0, OPTION_VENDOR, 0xd058}, MSG_OPTION_1},
260 	{{ 0, 0, 0, OPTION_VENDOR, 0xd155}, MSG_OPTION_1},
261 	{{ 0, 0, 0, OPTION_VENDOR, 0xd157}, MSG_OPTION_1},
262 	{{ 0, 0, 0, OPTION_VENDOR, 0xd255}, MSG_OPTION_1},
263 	{{ 0, 0, 0, OPTION_VENDOR, 0xd257}, MSG_OPTION_1},
264 	{{ 0, 0, 0, OPTION_VENDOR, 0xd357}, MSG_OPTION_1},
265 	{{ 0, 0, 0, ATHEROS_VENDOR, 0x20ff}, MSG_ATHEROS_1},
266 };
267 static uint32 kDevicesCount = sizeof(kDevices) / sizeof(kDevices[0]);
268 
269 
270 typedef struct _my_device {
271 	usb_device	device;
272 	bool		removed;
273 	mutex		lock;
274 	struct _my_device *link;
275 
276 	// device state
277 	usb_pipe	bulk_in;
278 	usb_pipe	bulk_out;
279 	uint8		interface;
280 	uint8       alternate_setting;
281 
282 	// used to store callback information
283 	sem_id		notify;
284 	status_t	status;
285 	size_t		actual_length;
286 
287 	msgType		type[3];
288 } my_device;
289 
290 
291 int32 api_version = B_CUR_DRIVER_API_VERSION;
292 static usb_module_info *gUSBModule = NULL;
293 static my_device *gDeviceList = NULL;
294 static uint32 gDeviceCount = 0;
295 static mutex gDeviceListLock;
296 
297 
298 //
299 //#pragma mark - Device Allocation Helper Functions
300 //
301 
302 
303 static void
304 my_free_device(my_device *device)
305 {
306 	mutex_lock(&device->lock);
307 	mutex_destroy(&device->lock);
308 	delete_sem(device->notify);
309 	free(device);
310 }
311 
312 
313 //
314 //#pragma mark - Bulk-only Functions
315 //
316 
317 
318 static void
319 my_callback(void *cookie, status_t status, void *data,
320 	size_t actualLength)
321 {
322 	my_device *device = (my_device *)cookie;
323 	device->status = status;
324 	device->actual_length = actualLength;
325 	release_sem(device->notify);
326 }
327 
328 
329 static status_t
330 my_transfer_data(my_device *device, bool directionIn, void *data,
331 	size_t dataLength)
332 {
333 	status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in
334 		: device->bulk_out, data, dataLength, my_callback, device);
335 	if (result != B_OK) {
336 		TRACE_ALWAYS("failed to queue data transfer\n");
337 		return result;
338 	}
339 
340 	do {
341 		bigtime_t timeout = directionIn ? 500000 : 500000;
342 		result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT,
343 			timeout);
344 		if (result == B_TIMED_OUT) {
345 			// Cancel the transfer and collect the sem that should now be
346 			// released through the callback on cancel. Handling of device
347 			// reset is done in usb_printer_operation() when it detects that
348 			// the transfer failed.
349 			gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in
350 				: device->bulk_out);
351 			acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0);
352 		}
353 	} while (result == B_INTERRUPTED);
354 
355 	if (result != B_OK) {
356 		TRACE_ALWAYS("acquire_sem failed while waiting for data transfer\n");
357 		return result;
358 	}
359 
360 	return B_OK;
361 }
362 
363 
364 enum msgType
365 my_get_msg_type(const usb_device_descriptor *desc, int index)
366 {
367 	for (uint32 i = 0; i < kDevicesCount; i++) {
368 		if (kDevices[i].desc.dev_class != 0x0
369 			&& kDevices[i].desc.dev_class != desc->device_class)
370 			continue;
371 		if (kDevices[i].desc.dev_subclass != 0x0
372 			&& kDevices[i].desc.dev_subclass != desc->device_subclass)
373 			continue;
374 		if (kDevices[i].desc.dev_protocol != 0x0
375 			&& kDevices[i].desc.dev_protocol != desc->device_protocol)
376 			continue;
377 		if (kDevices[i].desc.vendor != 0x0
378 			&& kDevices[i].desc.vendor != desc->vendor_id)
379 			continue;
380 		if (kDevices[i].desc.product != 0x0
381 			&& kDevices[i].desc.product != desc->product_id)
382 			continue;
383 		switch (index) {
384 			case 0:
385 				return kDevices[i].type;
386 			case 1:
387 				return kDevices[i].type2;
388 			case 2:
389 				return kDevices[i].type3;
390 		}
391 
392 	}
393 
394 	return MSG_NONE;
395 }
396 
397 
398 
399 status_t
400 my_modeswitch(my_device* device)
401 {
402 	status_t err = B_OK;
403 	if (device->type[0] == MSG_NONE)
404 			return B_OK;
405 	for (int i = 0; i < 3; i++) {
406 		if (device->type[i] == MSG_NONE)
407 			break;
408 
409 		err = my_transfer_data(device, false, kDevicesMsg[device->type[i]],
410 			sizeof(kDevicesMsg[device->type[i]]));
411 		if (err != B_OK) {
412 			TRACE_ALWAYS("send message %d failed\n", i + 1);
413 			return err;
414 		}
415 
416 		TRACE("device switched: %p\n", device);
417 
418 		char data[36];
419 		err = my_transfer_data(device, true, data, sizeof(data));
420 		if (err != B_OK) {
421 			TRACE_ALWAYS("receive response %d failed 0x%lx\n",
422 				i + 1, device->status);
423 			return err;
424 		}
425 		TRACE("device switched (response length %ld)\n", device->actual_length);
426 	}
427 
428 	TRACE("device switched: %p\n", device);
429 
430 	return B_OK;
431 }
432 
433 
434 //
435 //#pragma mark - Device Attach/Detach Notifications and Callback
436 //
437 
438 
439 static status_t
440 my_device_added(usb_device newDevice, void **cookie)
441 {
442 	TRACE("device_added(0x%08lx)\n", newDevice);
443 	my_device *device = (my_device *)malloc(sizeof(my_device));
444 	device->device = newDevice;
445 	device->removed = false;
446 	device->interface = 0xff;
447 	device->alternate_setting = 0;
448 
449 	// scan through the interfaces to find our bulk-only data interface
450 	const usb_configuration_info *configuration =
451 		gUSBModule->get_configuration(newDevice);
452 	if (configuration == NULL) {
453 		free(device);
454 		return B_ERROR;
455 	}
456 
457 	for (size_t i = 0; i < configuration->interface_count; i++) {
458 		usb_interface_info *interface = configuration->interface[i].active;
459 		if (interface == NULL)
460 			continue;
461 
462 		if (true) {
463 
464 			bool hasIn = false;
465 			bool hasOut = false;
466 			for (size_t j = 0; j < interface->endpoint_count; j++) {
467 				usb_endpoint_info *endpoint = &interface->endpoint[j];
468 				if (endpoint == NULL
469 					|| endpoint->descr->attributes != USB_ENDPOINT_ATTR_BULK)
470 					continue;
471 
472 				if (!hasIn && (endpoint->descr->endpoint_address
473 					& USB_ENDPOINT_ADDR_DIR_IN)) {
474 					device->bulk_in = endpoint->handle;
475 					hasIn = true;
476 				} else if (!hasOut && (endpoint->descr->endpoint_address
477 					& USB_ENDPOINT_ADDR_DIR_IN) == 0) {
478 					device->bulk_out = endpoint->handle;
479 					hasOut = true;
480 				}
481 
482 				if (hasIn && hasOut)
483 					break;
484 			}
485 
486 			if (!(hasIn && hasOut))
487 				continue;
488 
489 			device->interface = interface->descr->interface_number;
490 			device->alternate_setting = interface->descr->alternate_setting;
491 
492 			break;
493 		}
494 	}
495 
496 	if (device->interface == 0xff) {
497 		TRACE_ALWAYS("no valid interface found\n");
498 		free(device);
499 		return B_ERROR;
500 	}
501 
502 	const usb_device_descriptor *descriptor
503 		= gUSBModule->get_device_descriptor(newDevice);
504 	if (descriptor == NULL) {
505 		free(device);
506 		return B_ERROR;
507 	}
508 	for (int i = 0; i < 3; i++) {
509 		device->type[i] = my_get_msg_type(descriptor, i);
510 	}
511 
512 	mutex_init(&device->lock, DRIVER_NAME " device lock");
513 
514 	device->notify = create_sem(0, DRIVER_NAME " callback notify");
515 	if (device->notify < B_OK) {
516 		mutex_destroy(&device->lock);
517 		free(device);
518 		return device->notify;
519 	}
520 
521 	mutex_lock(&gDeviceListLock);
522 	device->link = gDeviceList;
523 	gDeviceList = device;
524 	mutex_unlock(&gDeviceListLock);
525 
526 	*cookie = device;
527 
528 	return my_modeswitch(device);
529 }
530 
531 
532 static status_t
533 my_device_removed(void *cookie)
534 {
535 	TRACE("device_removed(0x%08lx)\n", (uint32)cookie);
536 	my_device *device = (my_device *)cookie;
537 
538 	mutex_lock(&gDeviceListLock);
539 	if (gDeviceList == device) {
540 		gDeviceList = device->link;
541 	} else {
542 		my_device *element = gDeviceList;
543 		while (element) {
544 			if (element->link == device) {
545 				element->link = device->link;
546 				break;
547 			}
548 
549 			element = element->link;
550 		}
551 	}
552 	gDeviceCount--;
553 
554 	device->removed = true;
555 	gUSBModule->cancel_queued_transfers(device->bulk_in);
556 	gUSBModule->cancel_queued_transfers(device->bulk_out);
557 	my_free_device(device);
558 
559 	mutex_unlock(&gDeviceListLock);
560 	return B_OK;
561 }
562 
563 
564 //
565 //#pragma mark - Driver Entry Points
566 //
567 
568 
569 status_t
570 init_hardware()
571 {
572 	TRACE("init_hardware()\n");
573 	return B_OK;
574 }
575 
576 
577 status_t
578 init_driver()
579 {
580 	TRACE("init_driver()\n");
581 	static usb_notify_hooks notifyHooks = {
582 		&my_device_added,
583 		&my_device_removed
584 	};
585 
586 	gDeviceList = NULL;
587 	gDeviceCount = 0;
588 	mutex_init(&gDeviceListLock, DRIVER_NAME " device list lock");
589 
590 	TRACE("trying module %s\n", B_USB_MODULE_NAME);
591 	status_t result = get_module(B_USB_MODULE_NAME,
592 		(module_info **)&gUSBModule);
593 	if (result < B_OK) {
594 		TRACE_ALWAYS("getting module failed 0x%08lx\n", result);
595 		mutex_destroy(&gDeviceListLock);
596 		return result;
597 	}
598 
599 	size_t descriptorsSize = kDevicesCount * sizeof(usb_support_descriptor);
600 	usb_support_descriptor *supportedDevices =
601 		(usb_support_descriptor *)malloc(descriptorsSize);
602 	if (supportedDevices == NULL) {
603 		TRACE_ALWAYS("descriptor allocation failed\n");
604 		put_module(B_USB_MODULE_NAME);
605 		mutex_destroy(&gDeviceListLock);
606 		return result;
607 	}
608 
609 	for (uint32 i = 0; i < kDevicesCount; i++)
610 		supportedDevices[i] = kDevices[i].desc;
611 
612 	gUSBModule->register_driver(DRIVER_NAME, supportedDevices, kDevicesCount,
613 		NULL);
614 	gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
615 	free(supportedDevices);
616 	return B_OK;
617 }
618 
619 
620 void
621 uninit_driver()
622 {
623 	TRACE("uninit_driver()\n");
624 	gUSBModule->uninstall_notify(DRIVER_NAME);
625 	mutex_lock(&gDeviceListLock);
626 	mutex_destroy(&gDeviceListLock);
627 	put_module(B_USB_MODULE_NAME);
628 }
629 
630 
631 const char **
632 publish_devices()
633 {
634 	TRACE("publish_devices()\n");
635 	return NULL;
636 }
637 
638 
639 device_hooks *
640 find_device(const char *name)
641 {
642 	TRACE("find_device()\n");
643 	return NULL;
644 }
645