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