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
my_free_device(my_device * device)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
my_callback(void * cookie,status_t status,void * data,size_t actualLength)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
my_transfer_data(my_device * device,bool directionIn,void * data,size_t dataLength)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 = 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
my_get_msg_type(const usb_device_descriptor * desc,int index)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
my_modeswitch(my_device * device)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
my_device_added(usb_device newDevice,void ** cookie)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 sem_id callbackSem = create_sem(0, DRIVER_NAME " callback notify");
535 if (callbackSem < B_OK) {
536 mutex_destroy(&device->lock);
537 free(device);
538 return callbackSem;
539 }
540 device->notify = callbackSem;
541
542 mutex_lock(&gDeviceListLock);
543 device->link = gDeviceList;
544 gDeviceList = device;
545 mutex_unlock(&gDeviceListLock);
546
547 *cookie = device;
548
549 return my_modeswitch(device);
550 }
551
552
553 static status_t
my_device_removed(void * cookie)554 my_device_removed(void *cookie)
555 {
556 TRACE("device_removed(%p)\n", cookie);
557 my_device *device = (my_device *)cookie;
558
559 mutex_lock(&gDeviceListLock);
560 if (gDeviceList == device) {
561 gDeviceList = device->link;
562 } else {
563 my_device *element = gDeviceList;
564 while (element) {
565 if (element->link == device) {
566 element->link = device->link;
567 break;
568 }
569
570 element = element->link;
571 }
572 }
573 gDeviceCount--;
574
575 device->removed = true;
576 gUSBModule->cancel_queued_transfers(device->bulk_in);
577 gUSBModule->cancel_queued_transfers(device->bulk_out);
578 my_free_device(device);
579
580 mutex_unlock(&gDeviceListLock);
581 return B_OK;
582 }
583
584
585 //
586 //#pragma mark - Driver Entry Points
587 //
588
589
590 status_t
init_hardware()591 init_hardware()
592 {
593 TRACE("init_hardware()\n");
594 return B_OK;
595 }
596
597
598 status_t
init_driver()599 init_driver()
600 {
601 TRACE("init_driver()\n");
602 static usb_notify_hooks notifyHooks = {
603 &my_device_added,
604 &my_device_removed
605 };
606
607 gDeviceList = NULL;
608 gDeviceCount = 0;
609 mutex_init(&gDeviceListLock, DRIVER_NAME " device list lock");
610
611 TRACE("trying module %s\n", B_USB_MODULE_NAME);
612 status_t result = get_module(B_USB_MODULE_NAME,
613 (module_info **)&gUSBModule);
614 if (result < B_OK) {
615 TRACE_ALWAYS("getting module failed 0x%08" B_PRIx32 "\n", result);
616 mutex_destroy(&gDeviceListLock);
617 return result;
618 }
619
620 size_t descriptorsSize = kDevicesCount * sizeof(usb_support_descriptor);
621 usb_support_descriptor *supportedDevices =
622 (usb_support_descriptor *)malloc(descriptorsSize);
623 if (supportedDevices == NULL) {
624 TRACE_ALWAYS("descriptor allocation failed\n");
625 put_module(B_USB_MODULE_NAME);
626 mutex_destroy(&gDeviceListLock);
627 return result;
628 }
629
630 for (uint32 i = 0; i < kDevicesCount; i++)
631 supportedDevices[i] = kDevices[i].desc;
632
633 gUSBModule->register_driver(DRIVER_NAME, supportedDevices, kDevicesCount,
634 NULL);
635 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks);
636 free(supportedDevices);
637 return B_OK;
638 }
639
640
641 void
uninit_driver()642 uninit_driver()
643 {
644 TRACE("uninit_driver()\n");
645 gUSBModule->uninstall_notify(DRIVER_NAME);
646 mutex_lock(&gDeviceListLock);
647 mutex_destroy(&gDeviceListLock);
648 put_module(B_USB_MODULE_NAME);
649 }
650
651
652 const char **
publish_devices()653 publish_devices()
654 {
655 TRACE("publish_devices()\n");
656 return NULL;
657 }
658
659
660 device_hooks *
find_device(const char * name)661 find_device(const char *name)
662 {
663 TRACE("find_device()\n");
664 return NULL;
665 }
666