1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /* |
---|
4 | * Copyright (c) 2008 AnyWi Technologies |
---|
5 | * Author: Andrea Guzzo <aguzzo@anywi.com> |
---|
6 | * * based on uark.c 1.1 2006/08/14 08:30:22 jsg * |
---|
7 | * * parts from ubsa.c 183348 2008-09-25 12:00:56Z phk * |
---|
8 | * |
---|
9 | * Permission to use, copy, modify, and distribute this software for any |
---|
10 | * purpose with or without fee is hereby granted, provided that the above |
---|
11 | * copyright notice and this permission notice appear in all copies. |
---|
12 | * |
---|
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
---|
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
---|
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
---|
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
---|
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
---|
19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
---|
20 | * |
---|
21 | * $FreeBSD$ |
---|
22 | */ |
---|
23 | |
---|
24 | /* |
---|
25 | * NOTE: |
---|
26 | * |
---|
27 | * - The detour through the tty layer is ridiculously expensive wrt |
---|
28 | * buffering due to the high speeds. |
---|
29 | * |
---|
30 | * We should consider adding a simple r/w device which allows |
---|
31 | * attaching of PPP in a more efficient way. |
---|
32 | * |
---|
33 | */ |
---|
34 | |
---|
35 | |
---|
36 | #include <sys/stdint.h> |
---|
37 | #include <sys/stddef.h> |
---|
38 | #include <rtems/bsd/sys/param.h> |
---|
39 | #include <sys/queue.h> |
---|
40 | #include <sys/types.h> |
---|
41 | #include <sys/systm.h> |
---|
42 | #include <sys/kernel.h> |
---|
43 | #include <sys/bus.h> |
---|
44 | #include <sys/module.h> |
---|
45 | #include <rtems/bsd/sys/lock.h> |
---|
46 | #include <sys/mutex.h> |
---|
47 | #include <sys/condvar.h> |
---|
48 | #include <sys/sysctl.h> |
---|
49 | #include <sys/sx.h> |
---|
50 | #include <rtems/bsd/sys/unistd.h> |
---|
51 | #include <sys/callout.h> |
---|
52 | #include <sys/malloc.h> |
---|
53 | #include <sys/priv.h> |
---|
54 | |
---|
55 | #include <dev/usb/usb.h> |
---|
56 | #include <dev/usb/usbdi.h> |
---|
57 | #include <dev/usb/usbdi_util.h> |
---|
58 | #include <dev/usb/usb_cdc.h> |
---|
59 | #include <rtems/bsd/local/usbdevs.h> |
---|
60 | |
---|
61 | #define USB_DEBUG_VAR u3g_debug |
---|
62 | #include <dev/usb/usb_debug.h> |
---|
63 | #include <dev/usb/usb_process.h> |
---|
64 | #include <dev/usb/usb_msctest.h> |
---|
65 | |
---|
66 | #include <dev/usb/serial/usb_serial.h> |
---|
67 | #include <dev/usb/quirk/usb_quirk.h> |
---|
68 | |
---|
69 | #ifdef USB_DEBUG |
---|
70 | static int u3g_debug = 0; |
---|
71 | |
---|
72 | static SYSCTL_NODE(_hw_usb, OID_AUTO, u3g, CTLFLAG_RW, 0, "USB 3g"); |
---|
73 | SYSCTL_INT(_hw_usb_u3g, OID_AUTO, debug, CTLFLAG_RWTUN, |
---|
74 | &u3g_debug, 0, "Debug level"); |
---|
75 | #endif |
---|
76 | |
---|
77 | #define U3G_MAXPORTS 12 |
---|
78 | #define U3G_CONFIG_INDEX 0 |
---|
79 | #define U3G_BSIZE 2048 |
---|
80 | #define U3G_TXSIZE (U3G_BSIZE / U3G_TXFRAMES) |
---|
81 | #define U3G_TXFRAMES 4 |
---|
82 | |
---|
83 | /* Eject methods; See also usb_quirks.h:UQ_MSC_EJECT_* */ |
---|
84 | #define U3GINIT_HUAWEI 1 /* Requires Huawei init command */ |
---|
85 | #define U3GINIT_SIERRA 2 /* Requires Sierra init command */ |
---|
86 | #define U3GINIT_SCSIEJECT 3 /* Requires SCSI eject command */ |
---|
87 | #define U3GINIT_REZERO 4 /* Requires SCSI rezero command */ |
---|
88 | #define U3GINIT_ZTESTOR 5 /* Requires ZTE SCSI command */ |
---|
89 | #define U3GINIT_CMOTECH 6 /* Requires CMOTECH SCSI command */ |
---|
90 | #define U3GINIT_WAIT 7 /* Device reappears after a delay */ |
---|
91 | #define U3GINIT_SAEL_M460 8 /* Requires vendor init */ |
---|
92 | #define U3GINIT_HUAWEISCSI 9 /* Requires Huawei SCSI init command */ |
---|
93 | #define U3GINIT_HUAWEISCSI2 10 /* Requires Huawei SCSI init command (2) */ |
---|
94 | #define U3GINIT_TCT 11 /* Requires TCT Mobile init command */ |
---|
95 | |
---|
96 | enum { |
---|
97 | U3G_BULK_WR, |
---|
98 | U3G_BULK_RD, |
---|
99 | U3G_INTR, |
---|
100 | U3G_N_TRANSFER, |
---|
101 | }; |
---|
102 | |
---|
103 | struct u3g_softc { |
---|
104 | struct ucom_super_softc sc_super_ucom; |
---|
105 | struct ucom_softc sc_ucom[U3G_MAXPORTS]; |
---|
106 | |
---|
107 | struct usb_xfer *sc_xfer[U3G_MAXPORTS][U3G_N_TRANSFER]; |
---|
108 | uint8_t sc_iface[U3G_MAXPORTS]; /* local status register */ |
---|
109 | uint8_t sc_lsr[U3G_MAXPORTS]; /* local status register */ |
---|
110 | uint8_t sc_msr[U3G_MAXPORTS]; /* u3g status register */ |
---|
111 | uint16_t sc_line[U3G_MAXPORTS]; /* line status */ |
---|
112 | |
---|
113 | struct usb_device *sc_udev; |
---|
114 | struct mtx sc_mtx; |
---|
115 | |
---|
116 | uint8_t sc_numports; |
---|
117 | }; |
---|
118 | |
---|
119 | static device_probe_t u3g_probe; |
---|
120 | static device_attach_t u3g_attach; |
---|
121 | static device_detach_t u3g_detach; |
---|
122 | static void u3g_free_softc(struct u3g_softc *); |
---|
123 | |
---|
124 | static usb_callback_t u3g_write_callback; |
---|
125 | static usb_callback_t u3g_read_callback; |
---|
126 | static usb_callback_t u3g_intr_callback; |
---|
127 | |
---|
128 | static void u3g_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *); |
---|
129 | static void u3g_cfg_set_dtr(struct ucom_softc *, uint8_t); |
---|
130 | static void u3g_cfg_set_rts(struct ucom_softc *, uint8_t); |
---|
131 | static void u3g_start_read(struct ucom_softc *ucom); |
---|
132 | static void u3g_stop_read(struct ucom_softc *ucom); |
---|
133 | static void u3g_start_write(struct ucom_softc *ucom); |
---|
134 | static void u3g_stop_write(struct ucom_softc *ucom); |
---|
135 | static void u3g_poll(struct ucom_softc *ucom); |
---|
136 | static void u3g_free(struct ucom_softc *ucom); |
---|
137 | |
---|
138 | |
---|
139 | static void u3g_test_autoinst(void *, struct usb_device *, |
---|
140 | struct usb_attach_arg *); |
---|
141 | static int u3g_driver_loaded(struct module *mod, int what, void *arg); |
---|
142 | |
---|
143 | static eventhandler_tag u3g_etag; |
---|
144 | |
---|
145 | static const struct usb_config u3g_config[U3G_N_TRANSFER] = { |
---|
146 | |
---|
147 | [U3G_BULK_WR] = { |
---|
148 | .type = UE_BULK, |
---|
149 | .endpoint = UE_ADDR_ANY, |
---|
150 | .direction = UE_DIR_OUT, |
---|
151 | .bufsize = U3G_BSIZE,/* bytes */ |
---|
152 | .frames = U3G_TXFRAMES, |
---|
153 | .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, |
---|
154 | .callback = &u3g_write_callback, |
---|
155 | }, |
---|
156 | |
---|
157 | [U3G_BULK_RD] = { |
---|
158 | .type = UE_BULK, |
---|
159 | .endpoint = UE_ADDR_ANY, |
---|
160 | .direction = UE_DIR_IN, |
---|
161 | .bufsize = U3G_BSIZE,/* bytes */ |
---|
162 | .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, |
---|
163 | .callback = &u3g_read_callback, |
---|
164 | }, |
---|
165 | |
---|
166 | [U3G_INTR] = { |
---|
167 | .type = UE_INTERRUPT, |
---|
168 | .endpoint = UE_ADDR_ANY, |
---|
169 | .direction = UE_DIR_IN, |
---|
170 | .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, |
---|
171 | .bufsize = 0, /* use wMaxPacketSize */ |
---|
172 | .callback = &u3g_intr_callback, |
---|
173 | }, |
---|
174 | }; |
---|
175 | |
---|
176 | static const struct ucom_callback u3g_callback = { |
---|
177 | .ucom_cfg_get_status = &u3g_cfg_get_status, |
---|
178 | .ucom_cfg_set_dtr = &u3g_cfg_set_dtr, |
---|
179 | .ucom_cfg_set_rts = &u3g_cfg_set_rts, |
---|
180 | .ucom_start_read = &u3g_start_read, |
---|
181 | .ucom_stop_read = &u3g_stop_read, |
---|
182 | .ucom_start_write = &u3g_start_write, |
---|
183 | .ucom_stop_write = &u3g_stop_write, |
---|
184 | .ucom_poll = &u3g_poll, |
---|
185 | .ucom_free = &u3g_free, |
---|
186 | }; |
---|
187 | |
---|
188 | static device_method_t u3g_methods[] = { |
---|
189 | DEVMETHOD(device_probe, u3g_probe), |
---|
190 | DEVMETHOD(device_attach, u3g_attach), |
---|
191 | DEVMETHOD(device_detach, u3g_detach), |
---|
192 | DEVMETHOD_END |
---|
193 | }; |
---|
194 | |
---|
195 | static devclass_t u3g_devclass; |
---|
196 | |
---|
197 | static driver_t u3g_driver = { |
---|
198 | .name = "u3g", |
---|
199 | .methods = u3g_methods, |
---|
200 | .size = sizeof(struct u3g_softc), |
---|
201 | }; |
---|
202 | |
---|
203 | static const STRUCT_USB_HOST_ID u3g_devs[] = { |
---|
204 | #define U3G_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } |
---|
205 | U3G_DEV(ACERP, H10, 0), |
---|
206 | U3G_DEV(AIRPLUS, MCD650, 0), |
---|
207 | U3G_DEV(AIRPRIME, PC5220, 0), |
---|
208 | U3G_DEV(AIRPRIME, AC313U, 0), |
---|
209 | U3G_DEV(ALINK, 3G, 0), |
---|
210 | U3G_DEV(ALINK, 3GU, 0), |
---|
211 | U3G_DEV(ALINK, DWM652U5, 0), |
---|
212 | U3G_DEV(AMOI, H01, 0), |
---|
213 | U3G_DEV(AMOI, H01A, 0), |
---|
214 | U3G_DEV(AMOI, H02, 0), |
---|
215 | U3G_DEV(ANYDATA, ADU_500A, 0), |
---|
216 | U3G_DEV(ANYDATA, ADU_620UW, 0), |
---|
217 | U3G_DEV(ANYDATA, ADU_E100X, 0), |
---|
218 | U3G_DEV(AXESSTEL, DATAMODEM, 0), |
---|
219 | U3G_DEV(CMOTECH, CDMA_MODEM1, 0), |
---|
220 | U3G_DEV(CMOTECH, CGU628, U3GINIT_CMOTECH), |
---|
221 | U3G_DEV(DELL, U5500, 0), |
---|
222 | U3G_DEV(DELL, U5505, 0), |
---|
223 | U3G_DEV(DELL, U5510, 0), |
---|
224 | U3G_DEV(DELL, U5520, 0), |
---|
225 | U3G_DEV(DELL, U5520_2, 0), |
---|
226 | U3G_DEV(DELL, U5520_3, 0), |
---|
227 | U3G_DEV(DELL, U5700, 0), |
---|
228 | U3G_DEV(DELL, U5700_2, 0), |
---|
229 | U3G_DEV(DELL, U5700_3, 0), |
---|
230 | U3G_DEV(DELL, U5700_4, 0), |
---|
231 | U3G_DEV(DELL, U5720, 0), |
---|
232 | U3G_DEV(DELL, U5720_2, 0), |
---|
233 | U3G_DEV(DELL, U5730, 0), |
---|
234 | U3G_DEV(DELL, U5730_2, 0), |
---|
235 | U3G_DEV(DELL, U5730_3, 0), |
---|
236 | U3G_DEV(DELL, U740, 0), |
---|
237 | U3G_DEV(DLINK, DWR510_CD, U3GINIT_SCSIEJECT), |
---|
238 | U3G_DEV(DLINK, DWR510, 0), |
---|
239 | U3G_DEV(DLINK, DWM157_CD, U3GINIT_SCSIEJECT), |
---|
240 | U3G_DEV(DLINK, DWM157, 0), |
---|
241 | U3G_DEV(DLINK3, DWM652, 0), |
---|
242 | U3G_DEV(HP, EV2200, 0), |
---|
243 | U3G_DEV(HP, HS2300, 0), |
---|
244 | U3G_DEV(HP, UN2420_QDL, 0), |
---|
245 | U3G_DEV(HP, UN2420, 0), |
---|
246 | U3G_DEV(HUAWEI, E1401, U3GINIT_HUAWEI), |
---|
247 | U3G_DEV(HUAWEI, E1402, U3GINIT_HUAWEI), |
---|
248 | U3G_DEV(HUAWEI, E1403, U3GINIT_HUAWEI), |
---|
249 | U3G_DEV(HUAWEI, E1404, U3GINIT_HUAWEI), |
---|
250 | U3G_DEV(HUAWEI, E1405, U3GINIT_HUAWEI), |
---|
251 | U3G_DEV(HUAWEI, E1406, U3GINIT_HUAWEI), |
---|
252 | U3G_DEV(HUAWEI, E1407, U3GINIT_HUAWEI), |
---|
253 | U3G_DEV(HUAWEI, E1408, U3GINIT_HUAWEI), |
---|
254 | U3G_DEV(HUAWEI, E1409, U3GINIT_HUAWEI), |
---|
255 | U3G_DEV(HUAWEI, E140A, U3GINIT_HUAWEI), |
---|
256 | U3G_DEV(HUAWEI, E140B, U3GINIT_HUAWEI), |
---|
257 | U3G_DEV(HUAWEI, E140D, U3GINIT_HUAWEI), |
---|
258 | U3G_DEV(HUAWEI, E140E, U3GINIT_HUAWEI), |
---|
259 | U3G_DEV(HUAWEI, E140F, U3GINIT_HUAWEI), |
---|
260 | U3G_DEV(HUAWEI, E1410, U3GINIT_HUAWEI), |
---|
261 | U3G_DEV(HUAWEI, E1411, U3GINIT_HUAWEI), |
---|
262 | U3G_DEV(HUAWEI, E1412, U3GINIT_HUAWEI), |
---|
263 | U3G_DEV(HUAWEI, E1413, U3GINIT_HUAWEI), |
---|
264 | U3G_DEV(HUAWEI, E1414, U3GINIT_HUAWEI), |
---|
265 | U3G_DEV(HUAWEI, E1415, U3GINIT_HUAWEI), |
---|
266 | U3G_DEV(HUAWEI, E1416, U3GINIT_HUAWEI), |
---|
267 | U3G_DEV(HUAWEI, E1417, U3GINIT_HUAWEI), |
---|
268 | U3G_DEV(HUAWEI, E1418, U3GINIT_HUAWEI), |
---|
269 | U3G_DEV(HUAWEI, E1419, U3GINIT_HUAWEI), |
---|
270 | U3G_DEV(HUAWEI, E141A, U3GINIT_HUAWEI), |
---|
271 | U3G_DEV(HUAWEI, E141B, U3GINIT_HUAWEI), |
---|
272 | U3G_DEV(HUAWEI, E141C, U3GINIT_HUAWEI), |
---|
273 | U3G_DEV(HUAWEI, E141D, U3GINIT_HUAWEI), |
---|
274 | U3G_DEV(HUAWEI, E141E, U3GINIT_HUAWEI), |
---|
275 | U3G_DEV(HUAWEI, E141F, U3GINIT_HUAWEI), |
---|
276 | U3G_DEV(HUAWEI, E1420, U3GINIT_HUAWEI), |
---|
277 | U3G_DEV(HUAWEI, E1421, U3GINIT_HUAWEI), |
---|
278 | U3G_DEV(HUAWEI, E1422, U3GINIT_HUAWEI), |
---|
279 | U3G_DEV(HUAWEI, E1423, U3GINIT_HUAWEI), |
---|
280 | U3G_DEV(HUAWEI, E1424, U3GINIT_HUAWEI), |
---|
281 | U3G_DEV(HUAWEI, E1425, U3GINIT_HUAWEI), |
---|
282 | U3G_DEV(HUAWEI, E1426, U3GINIT_HUAWEI), |
---|
283 | U3G_DEV(HUAWEI, E1427, U3GINIT_HUAWEI), |
---|
284 | U3G_DEV(HUAWEI, E1428, U3GINIT_HUAWEI), |
---|
285 | U3G_DEV(HUAWEI, E1429, U3GINIT_HUAWEI), |
---|
286 | U3G_DEV(HUAWEI, E142A, U3GINIT_HUAWEI), |
---|
287 | U3G_DEV(HUAWEI, E142B, U3GINIT_HUAWEI), |
---|
288 | U3G_DEV(HUAWEI, E142C, U3GINIT_HUAWEI), |
---|
289 | U3G_DEV(HUAWEI, E142D, U3GINIT_HUAWEI), |
---|
290 | U3G_DEV(HUAWEI, E142E, U3GINIT_HUAWEI), |
---|
291 | U3G_DEV(HUAWEI, E142F, U3GINIT_HUAWEI), |
---|
292 | U3G_DEV(HUAWEI, E1430, U3GINIT_HUAWEI), |
---|
293 | U3G_DEV(HUAWEI, E1431, U3GINIT_HUAWEI), |
---|
294 | U3G_DEV(HUAWEI, E1432, U3GINIT_HUAWEI), |
---|
295 | U3G_DEV(HUAWEI, E1433, U3GINIT_HUAWEI), |
---|
296 | U3G_DEV(HUAWEI, E1434, U3GINIT_HUAWEI), |
---|
297 | U3G_DEV(HUAWEI, E1435, U3GINIT_HUAWEI), |
---|
298 | U3G_DEV(HUAWEI, E1436, U3GINIT_HUAWEI), |
---|
299 | U3G_DEV(HUAWEI, E1437, U3GINIT_HUAWEI), |
---|
300 | U3G_DEV(HUAWEI, E1438, U3GINIT_HUAWEI), |
---|
301 | U3G_DEV(HUAWEI, E1439, U3GINIT_HUAWEI), |
---|
302 | U3G_DEV(HUAWEI, E143A, U3GINIT_HUAWEI), |
---|
303 | U3G_DEV(HUAWEI, E143B, U3GINIT_HUAWEI), |
---|
304 | U3G_DEV(HUAWEI, E143C, U3GINIT_HUAWEI), |
---|
305 | U3G_DEV(HUAWEI, E143D, U3GINIT_HUAWEI), |
---|
306 | U3G_DEV(HUAWEI, E143E, U3GINIT_HUAWEI), |
---|
307 | U3G_DEV(HUAWEI, E143F, U3GINIT_HUAWEI), |
---|
308 | U3G_DEV(HUAWEI, E173, 0), |
---|
309 | U3G_DEV(HUAWEI, E173_INIT, U3GINIT_HUAWEISCSI), |
---|
310 | U3G_DEV(HUAWEI, E3131, 0), |
---|
311 | U3G_DEV(HUAWEI, E3131_INIT, U3GINIT_HUAWEISCSI), |
---|
312 | U3G_DEV(HUAWEI, E180V, U3GINIT_HUAWEI), |
---|
313 | U3G_DEV(HUAWEI, E220, U3GINIT_HUAWEI), |
---|
314 | U3G_DEV(HUAWEI, E220BIS, U3GINIT_HUAWEI), |
---|
315 | U3G_DEV(HUAWEI, E392, U3GINIT_HUAWEISCSI), |
---|
316 | U3G_DEV(HUAWEI, ME909U, U3GINIT_HUAWEISCSI2), |
---|
317 | U3G_DEV(HUAWEI, ME909S, U3GINIT_HUAWEISCSI2), |
---|
318 | U3G_DEV(HUAWEI, MOBILE, U3GINIT_HUAWEI), |
---|
319 | U3G_DEV(HUAWEI, E1752, U3GINIT_HUAWEISCSI), |
---|
320 | U3G_DEV(HUAWEI, E1820, U3GINIT_HUAWEISCSI), |
---|
321 | U3G_DEV(HUAWEI, K3771, U3GINIT_HUAWEI), |
---|
322 | U3G_DEV(HUAWEI, K3771_INIT, U3GINIT_HUAWEISCSI2), |
---|
323 | U3G_DEV(HUAWEI, K3772, U3GINIT_HUAWEI), |
---|
324 | U3G_DEV(HUAWEI, K3772_INIT, U3GINIT_HUAWEISCSI2), |
---|
325 | U3G_DEV(HUAWEI, K3765, U3GINIT_HUAWEI), |
---|
326 | U3G_DEV(HUAWEI, K3765_INIT, U3GINIT_HUAWEISCSI), |
---|
327 | U3G_DEV(HUAWEI, K3770, U3GINIT_HUAWEI), |
---|
328 | U3G_DEV(HUAWEI, K3770_INIT, U3GINIT_HUAWEISCSI), |
---|
329 | U3G_DEV(HUAWEI, K4505, U3GINIT_HUAWEI), |
---|
330 | U3G_DEV(HUAWEI, K4505_INIT, U3GINIT_HUAWEISCSI), |
---|
331 | U3G_DEV(HUAWEI, ETS2055, U3GINIT_HUAWEI), |
---|
332 | U3G_DEV(KYOCERA2, CDMA_MSM_K, 0), |
---|
333 | U3G_DEV(KYOCERA2, KPC680, 0), |
---|
334 | U3G_DEV(LONGCHEER, WM66, U3GINIT_HUAWEI), |
---|
335 | U3G_DEV(LONGCHEER, DISK, U3GINIT_TCT), |
---|
336 | U3G_DEV(LONGCHEER, W14, 0), |
---|
337 | U3G_DEV(LONGCHEER, XSSTICK, 0), |
---|
338 | U3G_DEV(MERLIN, V620, 0), |
---|
339 | U3G_DEV(NEOTEL, PRIME, 0), |
---|
340 | U3G_DEV(NOVATEL, E725, 0), |
---|
341 | U3G_DEV(NOVATEL, ES620, 0), |
---|
342 | U3G_DEV(NOVATEL, ES620_2, 0), |
---|
343 | U3G_DEV(NOVATEL, EU730, 0), |
---|
344 | U3G_DEV(NOVATEL, EU740, 0), |
---|
345 | U3G_DEV(NOVATEL, EU870D, 0), |
---|
346 | U3G_DEV(NOVATEL, MC760, 0), |
---|
347 | U3G_DEV(NOVATEL, MC547, 0), |
---|
348 | U3G_DEV(NOVATEL, MC679, 0), |
---|
349 | U3G_DEV(NOVATEL, MC950D, 0), |
---|
350 | U3G_DEV(NOVATEL, MC990D, 0), |
---|
351 | U3G_DEV(NOVATEL, MIFI2200, U3GINIT_SCSIEJECT), |
---|
352 | U3G_DEV(NOVATEL, MIFI2200V, U3GINIT_SCSIEJECT), |
---|
353 | U3G_DEV(NOVATEL, U720, 0), |
---|
354 | U3G_DEV(NOVATEL, U727, 0), |
---|
355 | U3G_DEV(NOVATEL, U727_2, 0), |
---|
356 | U3G_DEV(NOVATEL, U740, 0), |
---|
357 | U3G_DEV(NOVATEL, U740_2, 0), |
---|
358 | U3G_DEV(NOVATEL, U760, U3GINIT_SCSIEJECT), |
---|
359 | U3G_DEV(NOVATEL, U870, 0), |
---|
360 | U3G_DEV(NOVATEL, V620, 0), |
---|
361 | U3G_DEV(NOVATEL, V640, 0), |
---|
362 | U3G_DEV(NOVATEL, V720, 0), |
---|
363 | U3G_DEV(NOVATEL, V740, 0), |
---|
364 | U3G_DEV(NOVATEL, X950D, 0), |
---|
365 | U3G_DEV(NOVATEL, XU870, 0), |
---|
366 | U3G_DEV(MOTOROLA2, MB886, U3GINIT_SCSIEJECT), |
---|
367 | U3G_DEV(OPTION, E6500, 0), |
---|
368 | U3G_DEV(OPTION, E6501, 0), |
---|
369 | U3G_DEV(OPTION, E6601, 0), |
---|
370 | U3G_DEV(OPTION, E6721, 0), |
---|
371 | U3G_DEV(OPTION, E6741, 0), |
---|
372 | U3G_DEV(OPTION, E6761, 0), |
---|
373 | U3G_DEV(OPTION, E6800, 0), |
---|
374 | U3G_DEV(OPTION, E7021, 0), |
---|
375 | U3G_DEV(OPTION, E7041, 0), |
---|
376 | U3G_DEV(OPTION, E7061, 0), |
---|
377 | U3G_DEV(OPTION, E7100, 0), |
---|
378 | U3G_DEV(OPTION, GE40X, 0), |
---|
379 | U3G_DEV(OPTION, GT3G, 0), |
---|
380 | U3G_DEV(OPTION, GT3GPLUS, 0), |
---|
381 | U3G_DEV(OPTION, GT3GQUAD, 0), |
---|
382 | U3G_DEV(OPTION, GT3G_1, 0), |
---|
383 | U3G_DEV(OPTION, GT3G_2, 0), |
---|
384 | U3G_DEV(OPTION, GT3G_3, 0), |
---|
385 | U3G_DEV(OPTION, GT3G_4, 0), |
---|
386 | U3G_DEV(OPTION, GT3G_5, 0), |
---|
387 | U3G_DEV(OPTION, GT3G_6, 0), |
---|
388 | U3G_DEV(OPTION, GTHSDPA, 0), |
---|
389 | U3G_DEV(OPTION, GTM380, 0), |
---|
390 | U3G_DEV(OPTION, GTMAX36, 0), |
---|
391 | U3G_DEV(OPTION, GTMAX380HSUPAE, 0), |
---|
392 | U3G_DEV(OPTION, GTMAXHSUPA, 0), |
---|
393 | U3G_DEV(OPTION, GTMAXHSUPAE, 0), |
---|
394 | U3G_DEV(OPTION, VODAFONEMC3G, 0), |
---|
395 | U3G_DEV(QISDA, H20_1, 0), |
---|
396 | U3G_DEV(QISDA, H20_2, 0), |
---|
397 | U3G_DEV(QISDA, H21_1, 0), |
---|
398 | U3G_DEV(QISDA, H21_2, 0), |
---|
399 | U3G_DEV(QUALCOMM, NTT_L02C_MODEM, U3GINIT_SCSIEJECT), |
---|
400 | U3G_DEV(QUALCOMM2, AC8700, 0), |
---|
401 | U3G_DEV(QUALCOMM2, MF330, 0), |
---|
402 | U3G_DEV(QUALCOMM2, SIM5218, 0), |
---|
403 | U3G_DEV(QUALCOMM2, WM620, 0), |
---|
404 | U3G_DEV(QUALCOMM2, VW110L, U3GINIT_SCSIEJECT), |
---|
405 | U3G_DEV(QUALCOMM2, GOBI2000_QDL, 0), |
---|
406 | U3G_DEV(QUALCOMM2, GOBI2000, 0), |
---|
407 | U3G_DEV(QUALCOMM2, VT80N, 0), |
---|
408 | U3G_DEV(QUALCOMM3, VFAST2, 0), |
---|
409 | U3G_DEV(QUALCOMMINC, AC2726, 0), |
---|
410 | U3G_DEV(QUALCOMMINC, AC682_INIT, U3GINIT_SCSIEJECT), |
---|
411 | U3G_DEV(QUALCOMMINC, AC682, 0), |
---|
412 | U3G_DEV(QUALCOMMINC, AC8700, 0), |
---|
413 | U3G_DEV(QUALCOMMINC, AC8710, 0), |
---|
414 | U3G_DEV(QUALCOMMINC, CDMA_MSM, U3GINIT_SCSIEJECT), |
---|
415 | U3G_DEV(QUALCOMMINC, E0002, 0), |
---|
416 | U3G_DEV(QUALCOMMINC, E0003, 0), |
---|
417 | U3G_DEV(QUALCOMMINC, E0004, 0), |
---|
418 | U3G_DEV(QUALCOMMINC, E0005, 0), |
---|
419 | U3G_DEV(QUALCOMMINC, E0006, 0), |
---|
420 | U3G_DEV(QUALCOMMINC, E0007, 0), |
---|
421 | U3G_DEV(QUALCOMMINC, E0008, 0), |
---|
422 | U3G_DEV(QUALCOMMINC, E0009, 0), |
---|
423 | U3G_DEV(QUALCOMMINC, E000A, 0), |
---|
424 | U3G_DEV(QUALCOMMINC, E000B, 0), |
---|
425 | U3G_DEV(QUALCOMMINC, E000C, 0), |
---|
426 | U3G_DEV(QUALCOMMINC, E000D, 0), |
---|
427 | U3G_DEV(QUALCOMMINC, E000E, 0), |
---|
428 | U3G_DEV(QUALCOMMINC, E000F, 0), |
---|
429 | U3G_DEV(QUALCOMMINC, E0010, 0), |
---|
430 | U3G_DEV(QUALCOMMINC, E0011, 0), |
---|
431 | U3G_DEV(QUALCOMMINC, E0012, 0), |
---|
432 | U3G_DEV(QUALCOMMINC, E0013, 0), |
---|
433 | U3G_DEV(QUALCOMMINC, E0014, 0), |
---|
434 | U3G_DEV(QUALCOMMINC, E0017, 0), |
---|
435 | U3G_DEV(QUALCOMMINC, E0018, 0), |
---|
436 | U3G_DEV(QUALCOMMINC, E0019, 0), |
---|
437 | U3G_DEV(QUALCOMMINC, E0020, 0), |
---|
438 | U3G_DEV(QUALCOMMINC, E0021, 0), |
---|
439 | U3G_DEV(QUALCOMMINC, E0022, 0), |
---|
440 | U3G_DEV(QUALCOMMINC, E0023, 0), |
---|
441 | U3G_DEV(QUALCOMMINC, E0024, 0), |
---|
442 | U3G_DEV(QUALCOMMINC, E0025, 0), |
---|
443 | U3G_DEV(QUALCOMMINC, E0026, 0), |
---|
444 | U3G_DEV(QUALCOMMINC, E0027, 0), |
---|
445 | U3G_DEV(QUALCOMMINC, E0028, 0), |
---|
446 | U3G_DEV(QUALCOMMINC, E0029, 0), |
---|
447 | U3G_DEV(QUALCOMMINC, E0030, 0), |
---|
448 | U3G_DEV(QUALCOMMINC, E0032, 0), |
---|
449 | U3G_DEV(QUALCOMMINC, E0033, 0), |
---|
450 | U3G_DEV(QUALCOMMINC, E0037, 0), |
---|
451 | U3G_DEV(QUALCOMMINC, E0039, 0), |
---|
452 | U3G_DEV(QUALCOMMINC, E0042, 0), |
---|
453 | U3G_DEV(QUALCOMMINC, E0043, 0), |
---|
454 | U3G_DEV(QUALCOMMINC, E0048, 0), |
---|
455 | U3G_DEV(QUALCOMMINC, E0049, 0), |
---|
456 | U3G_DEV(QUALCOMMINC, E0051, 0), |
---|
457 | U3G_DEV(QUALCOMMINC, E0052, 0), |
---|
458 | U3G_DEV(QUALCOMMINC, E0054, 0), |
---|
459 | U3G_DEV(QUALCOMMINC, E0055, 0), |
---|
460 | U3G_DEV(QUALCOMMINC, E0057, 0), |
---|
461 | U3G_DEV(QUALCOMMINC, E0058, 0), |
---|
462 | U3G_DEV(QUALCOMMINC, E0059, 0), |
---|
463 | U3G_DEV(QUALCOMMINC, E0060, 0), |
---|
464 | U3G_DEV(QUALCOMMINC, E0061, 0), |
---|
465 | U3G_DEV(QUALCOMMINC, E0062, 0), |
---|
466 | U3G_DEV(QUALCOMMINC, E0063, 0), |
---|
467 | U3G_DEV(QUALCOMMINC, E0064, 0), |
---|
468 | U3G_DEV(QUALCOMMINC, E0066, 0), |
---|
469 | U3G_DEV(QUALCOMMINC, E0069, 0), |
---|
470 | U3G_DEV(QUALCOMMINC, E0070, 0), |
---|
471 | U3G_DEV(QUALCOMMINC, E0073, 0), |
---|
472 | U3G_DEV(QUALCOMMINC, E0076, 0), |
---|
473 | U3G_DEV(QUALCOMMINC, E0078, 0), |
---|
474 | U3G_DEV(QUALCOMMINC, E0082, 0), |
---|
475 | U3G_DEV(QUALCOMMINC, E0086, 0), |
---|
476 | U3G_DEV(QUALCOMMINC, SURFSTICK, 0), |
---|
477 | U3G_DEV(QUALCOMMINC, E2002, 0), |
---|
478 | U3G_DEV(QUALCOMMINC, E2003, 0), |
---|
479 | U3G_DEV(QUALCOMMINC, K3772_Z, 0), |
---|
480 | U3G_DEV(QUALCOMMINC, K3772_Z_INIT, U3GINIT_SCSIEJECT), |
---|
481 | U3G_DEV(QUALCOMMINC, MF112, U3GINIT_ZTESTOR), |
---|
482 | U3G_DEV(QUALCOMMINC, MF195E, 0), |
---|
483 | U3G_DEV(QUALCOMMINC, MF195E_INIT, U3GINIT_SCSIEJECT), |
---|
484 | U3G_DEV(QUALCOMMINC, MF626, 0), |
---|
485 | U3G_DEV(QUALCOMMINC, MF628, 0), |
---|
486 | U3G_DEV(QUALCOMMINC, MF633R, 0), |
---|
487 | /* the following is a RNDIS device, no modem features */ |
---|
488 | U3G_DEV(QUALCOMMINC, ZTE_MF730M, U3GINIT_SCSIEJECT), |
---|
489 | U3G_DEV(QUANTA, GKE, 0), |
---|
490 | U3G_DEV(QUANTA, GLE, 0), |
---|
491 | U3G_DEV(QUANTA, GLX, 0), |
---|
492 | U3G_DEV(QUANTA, Q101, 0), |
---|
493 | U3G_DEV(QUANTA, Q111, 0), |
---|
494 | U3G_DEV(SIERRA, AC402, 0), |
---|
495 | U3G_DEV(SIERRA, AC595U, 0), |
---|
496 | U3G_DEV(SIERRA, AC313U, 0), |
---|
497 | U3G_DEV(SIERRA, AC597E, 0), |
---|
498 | U3G_DEV(SIERRA, AC875, 0), |
---|
499 | U3G_DEV(SIERRA, AC875E, 0), |
---|
500 | U3G_DEV(SIERRA, AC875U, 0), |
---|
501 | U3G_DEV(SIERRA, AC875U_2, 0), |
---|
502 | U3G_DEV(SIERRA, AC880, 0), |
---|
503 | U3G_DEV(SIERRA, AC880E, 0), |
---|
504 | U3G_DEV(SIERRA, AC880U, 0), |
---|
505 | U3G_DEV(SIERRA, AC881, 0), |
---|
506 | U3G_DEV(SIERRA, AC881E, 0), |
---|
507 | U3G_DEV(SIERRA, AC881U, 0), |
---|
508 | U3G_DEV(SIERRA, AC885E, 0), |
---|
509 | U3G_DEV(SIERRA, AC885E_2, 0), |
---|
510 | U3G_DEV(SIERRA, AC885U, 0), |
---|
511 | U3G_DEV(SIERRA, AIRCARD580, 0), |
---|
512 | U3G_DEV(SIERRA, AIRCARD595, 0), |
---|
513 | U3G_DEV(SIERRA, C22, 0), |
---|
514 | U3G_DEV(SIERRA, C597, 0), |
---|
515 | U3G_DEV(SIERRA, C888, 0), |
---|
516 | U3G_DEV(SIERRA, E0029, 0), |
---|
517 | U3G_DEV(SIERRA, E6892, 0), |
---|
518 | U3G_DEV(SIERRA, E6893, 0), |
---|
519 | U3G_DEV(SIERRA, EM5625, 0), |
---|
520 | U3G_DEV(SIERRA, EM5725, 0), |
---|
521 | U3G_DEV(SIERRA, MC5720, 0), |
---|
522 | U3G_DEV(SIERRA, MC5720_2, 0), |
---|
523 | U3G_DEV(SIERRA, MC5725, 0), |
---|
524 | U3G_DEV(SIERRA, MC5727, 0), |
---|
525 | U3G_DEV(SIERRA, MC5727_2, 0), |
---|
526 | U3G_DEV(SIERRA, MC5728, 0), |
---|
527 | U3G_DEV(SIERRA, MC7354, 0), |
---|
528 | U3G_DEV(SIERRA, MC7355, 0), |
---|
529 | U3G_DEV(SIERRA, MC7430, 0), |
---|
530 | U3G_DEV(SIERRA, MC8700, 0), |
---|
531 | U3G_DEV(SIERRA, MC8755, 0), |
---|
532 | U3G_DEV(SIERRA, MC8755_2, 0), |
---|
533 | U3G_DEV(SIERRA, MC8755_3, 0), |
---|
534 | U3G_DEV(SIERRA, MC8755_4, 0), |
---|
535 | U3G_DEV(SIERRA, MC8765, 0), |
---|
536 | U3G_DEV(SIERRA, MC8765_2, 0), |
---|
537 | U3G_DEV(SIERRA, MC8765_3, 0), |
---|
538 | U3G_DEV(SIERRA, MC8775, 0), |
---|
539 | U3G_DEV(SIERRA, MC8775_2, 0), |
---|
540 | U3G_DEV(SIERRA, MC8780, 0), |
---|
541 | U3G_DEV(SIERRA, MC8780_2, 0), |
---|
542 | U3G_DEV(SIERRA, MC8780_3, 0), |
---|
543 | U3G_DEV(SIERRA, MC8781, 0), |
---|
544 | U3G_DEV(SIERRA, MC8781_2, 0), |
---|
545 | U3G_DEV(SIERRA, MC8781_3, 0), |
---|
546 | U3G_DEV(SIERRA, MC8785, 0), |
---|
547 | U3G_DEV(SIERRA, MC8785_2, 0), |
---|
548 | U3G_DEV(SIERRA, MC8790, 0), |
---|
549 | U3G_DEV(SIERRA, MC8791, 0), |
---|
550 | U3G_DEV(SIERRA, MC8792, 0), |
---|
551 | U3G_DEV(SIERRA, MINI5725, 0), |
---|
552 | U3G_DEV(SIERRA, T11, 0), |
---|
553 | U3G_DEV(SIERRA, T598, 0), |
---|
554 | U3G_DEV(SILABS, SAEL, U3GINIT_SAEL_M460), |
---|
555 | U3G_DEV(STELERA, C105, 0), |
---|
556 | U3G_DEV(STELERA, E1003, 0), |
---|
557 | U3G_DEV(STELERA, E1004, 0), |
---|
558 | U3G_DEV(STELERA, E1005, 0), |
---|
559 | U3G_DEV(STELERA, E1006, 0), |
---|
560 | U3G_DEV(STELERA, E1007, 0), |
---|
561 | U3G_DEV(STELERA, E1008, 0), |
---|
562 | U3G_DEV(STELERA, E1009, 0), |
---|
563 | U3G_DEV(STELERA, E100A, 0), |
---|
564 | U3G_DEV(STELERA, E100B, 0), |
---|
565 | U3G_DEV(STELERA, E100C, 0), |
---|
566 | U3G_DEV(STELERA, E100D, 0), |
---|
567 | U3G_DEV(STELERA, E100E, 0), |
---|
568 | U3G_DEV(STELERA, E100F, 0), |
---|
569 | U3G_DEV(STELERA, E1010, 0), |
---|
570 | U3G_DEV(STELERA, E1011, 0), |
---|
571 | U3G_DEV(STELERA, E1012, 0), |
---|
572 | U3G_DEV(TCTMOBILE, X060S, 0), |
---|
573 | U3G_DEV(TCTMOBILE, X080S, U3GINIT_TCT), |
---|
574 | U3G_DEV(TELIT, UC864E, 0), |
---|
575 | U3G_DEV(TELIT, UC864G, 0), |
---|
576 | U3G_DEV(TLAYTECH, TEU800, 0), |
---|
577 | U3G_DEV(TOSHIBA, G450, 0), |
---|
578 | U3G_DEV(TOSHIBA, HSDPA, 0), |
---|
579 | U3G_DEV(YISO, C893, 0), |
---|
580 | U3G_DEV(WETELECOM, WM_D200, 0), |
---|
581 | /* Autoinstallers */ |
---|
582 | U3G_DEV(NOVATEL, ZEROCD, U3GINIT_SCSIEJECT), |
---|
583 | U3G_DEV(OPTION, GTICON322, U3GINIT_REZERO), |
---|
584 | U3G_DEV(QUALCOMMINC, ZTE_STOR, U3GINIT_ZTESTOR), |
---|
585 | U3G_DEV(QUALCOMMINC, ZTE_STOR2, U3GINIT_SCSIEJECT), |
---|
586 | U3G_DEV(QUANTA, Q101_STOR, U3GINIT_SCSIEJECT), |
---|
587 | U3G_DEV(SIERRA, TRUINSTALL, U3GINIT_SIERRA), |
---|
588 | #undef U3G_DEV |
---|
589 | }; |
---|
590 | |
---|
591 | DRIVER_MODULE(u3g, uhub, u3g_driver, u3g_devclass, u3g_driver_loaded, 0); |
---|
592 | MODULE_DEPEND(u3g, ucom, 1, 1, 1); |
---|
593 | MODULE_DEPEND(u3g, usb, 1, 1, 1); |
---|
594 | MODULE_VERSION(u3g, 1); |
---|
595 | USB_PNP_HOST_INFO(u3g_devs); |
---|
596 | |
---|
597 | static int |
---|
598 | u3g_sierra_init(struct usb_device *udev) |
---|
599 | { |
---|
600 | struct usb_device_request req; |
---|
601 | |
---|
602 | req.bmRequestType = UT_VENDOR; |
---|
603 | req.bRequest = UR_SET_INTERFACE; |
---|
604 | USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); |
---|
605 | USETW(req.wIndex, UHF_PORT_CONNECTION); |
---|
606 | USETW(req.wLength, 0); |
---|
607 | |
---|
608 | if (usbd_do_request_flags(udev, NULL, &req, |
---|
609 | NULL, 0, NULL, USB_MS_HZ)) { |
---|
610 | /* ignore any errors */ |
---|
611 | } |
---|
612 | return (0); |
---|
613 | } |
---|
614 | |
---|
615 | static int |
---|
616 | u3g_huawei_init(struct usb_device *udev) |
---|
617 | { |
---|
618 | struct usb_device_request req; |
---|
619 | |
---|
620 | req.bmRequestType = UT_WRITE_DEVICE; |
---|
621 | req.bRequest = UR_SET_FEATURE; |
---|
622 | USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); |
---|
623 | USETW(req.wIndex, UHF_PORT_SUSPEND); |
---|
624 | USETW(req.wLength, 0); |
---|
625 | |
---|
626 | if (usbd_do_request_flags(udev, NULL, &req, |
---|
627 | NULL, 0, NULL, USB_MS_HZ)) { |
---|
628 | /* ignore any errors */ |
---|
629 | } |
---|
630 | return (0); |
---|
631 | } |
---|
632 | |
---|
633 | static void |
---|
634 | u3g_sael_m460_init(struct usb_device *udev) |
---|
635 | { |
---|
636 | static const uint8_t setup[][24] = { |
---|
637 | { 0x41, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, |
---|
638 | { 0x41, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, |
---|
639 | { 0x41, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, |
---|
640 | 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, |
---|
641 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, |
---|
642 | { 0xc1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02 }, |
---|
643 | { 0xc1, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 }, |
---|
644 | { 0x41, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, |
---|
645 | { 0xc1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }, |
---|
646 | { 0x41, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, |
---|
647 | { 0x41, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, |
---|
648 | { 0x41, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00 }, |
---|
649 | { 0x41, 0x19, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, |
---|
650 | 0x00, 0x00, 0x00, 0x00, 0x11, 0x13 }, |
---|
651 | { 0x41, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, |
---|
652 | 0x09, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, |
---|
653 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00 }, |
---|
654 | { 0x41, 0x12, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, |
---|
655 | { 0x41, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, |
---|
656 | { 0x41, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, |
---|
657 | { 0x41, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00 }, |
---|
658 | { 0x41, 0x19, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, |
---|
659 | 0x00, 0x00, 0x00, 0x00, 0x11, 0x13 }, |
---|
660 | { 0x41, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, |
---|
661 | 0x09, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, |
---|
662 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00 }, |
---|
663 | { 0x41, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, |
---|
664 | }; |
---|
665 | |
---|
666 | struct usb_device_request req; |
---|
667 | usb_error_t err; |
---|
668 | uint16_t len; |
---|
669 | uint8_t buf[0x300]; |
---|
670 | uint8_t n; |
---|
671 | |
---|
672 | DPRINTFN(1, "\n"); |
---|
673 | |
---|
674 | if (usbd_req_set_alt_interface_no(udev, NULL, 0, 0)) { |
---|
675 | DPRINTFN(0, "Alt setting 0 failed\n"); |
---|
676 | return; |
---|
677 | } |
---|
678 | |
---|
679 | for (n = 0; n != nitems(setup); n++) { |
---|
680 | |
---|
681 | memcpy(&req, setup[n], sizeof(req)); |
---|
682 | |
---|
683 | len = UGETW(req.wLength); |
---|
684 | if (req.bmRequestType & UE_DIR_IN) { |
---|
685 | if (len > sizeof(buf)) { |
---|
686 | DPRINTFN(0, "too small buffer\n"); |
---|
687 | continue; |
---|
688 | } |
---|
689 | err = usbd_do_request(udev, NULL, &req, buf); |
---|
690 | } else { |
---|
691 | if (len > (sizeof(setup[0]) - 8)) { |
---|
692 | DPRINTFN(0, "too small buffer\n"); |
---|
693 | continue; |
---|
694 | } |
---|
695 | err = usbd_do_request(udev, NULL, &req, |
---|
696 | __DECONST(uint8_t *, &setup[n][8])); |
---|
697 | } |
---|
698 | if (err) { |
---|
699 | DPRINTFN(1, "request %u failed\n", |
---|
700 | (unsigned int)n); |
---|
701 | /* |
---|
702 | * Some of the requests will fail. Stop doing |
---|
703 | * requests when we are getting timeouts so |
---|
704 | * that we don't block the explore/attach |
---|
705 | * thread forever. |
---|
706 | */ |
---|
707 | if (err == USB_ERR_TIMEOUT) |
---|
708 | break; |
---|
709 | } |
---|
710 | } |
---|
711 | } |
---|
712 | |
---|
713 | /* |
---|
714 | * The following function handles 3G modem devices (E220, Mobile, |
---|
715 | * etc.) with auto-install flash disks for Windows/MacOSX on the first |
---|
716 | * interface. After some command or some delay they change appearance |
---|
717 | * to a modem. |
---|
718 | */ |
---|
719 | static void |
---|
720 | u3g_test_autoinst(void *arg, struct usb_device *udev, |
---|
721 | struct usb_attach_arg *uaa) |
---|
722 | { |
---|
723 | struct usb_interface *iface; |
---|
724 | struct usb_interface_descriptor *id; |
---|
725 | int error; |
---|
726 | unsigned long method; |
---|
727 | |
---|
728 | if (uaa->dev_state != UAA_DEV_READY) |
---|
729 | return; |
---|
730 | |
---|
731 | iface = usbd_get_iface(udev, 0); |
---|
732 | if (iface == NULL) |
---|
733 | return; |
---|
734 | id = iface->idesc; |
---|
735 | if (id == NULL || id->bInterfaceClass != UICLASS_MASS) |
---|
736 | return; |
---|
737 | |
---|
738 | if (usb_test_quirk(uaa, UQ_MSC_EJECT_HUAWEI)) |
---|
739 | method = U3GINIT_HUAWEI; |
---|
740 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_SIERRA)) |
---|
741 | method = U3GINIT_SIERRA; |
---|
742 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_SCSIEJECT)) |
---|
743 | method = U3GINIT_SCSIEJECT; |
---|
744 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_REZERO)) |
---|
745 | method = U3GINIT_REZERO; |
---|
746 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_ZTESTOR)) |
---|
747 | method = U3GINIT_ZTESTOR; |
---|
748 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_CMOTECH)) |
---|
749 | method = U3GINIT_CMOTECH; |
---|
750 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_WAIT)) |
---|
751 | method = U3GINIT_WAIT; |
---|
752 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_HUAWEISCSI)) |
---|
753 | method = U3GINIT_HUAWEISCSI; |
---|
754 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_HUAWEISCSI2)) |
---|
755 | method = U3GINIT_HUAWEISCSI2; |
---|
756 | else if (usb_test_quirk(uaa, UQ_MSC_EJECT_TCT)) |
---|
757 | method = U3GINIT_TCT; |
---|
758 | else if (usbd_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa) == 0) |
---|
759 | method = USB_GET_DRIVER_INFO(uaa); |
---|
760 | else |
---|
761 | return; /* no device match */ |
---|
762 | |
---|
763 | if (bootverbose) { |
---|
764 | printf("Ejecting %s %s using method %ld\n", |
---|
765 | usb_get_manufacturer(udev), |
---|
766 | usb_get_product(udev), method); |
---|
767 | } |
---|
768 | |
---|
769 | switch (method) { |
---|
770 | case U3GINIT_HUAWEI: |
---|
771 | error = u3g_huawei_init(udev); |
---|
772 | break; |
---|
773 | case U3GINIT_HUAWEISCSI: |
---|
774 | error = usb_msc_eject(udev, 0, MSC_EJECT_HUAWEI); |
---|
775 | break; |
---|
776 | case U3GINIT_HUAWEISCSI2: |
---|
777 | error = usb_msc_eject(udev, 0, MSC_EJECT_HUAWEI2); |
---|
778 | break; |
---|
779 | case U3GINIT_SCSIEJECT: |
---|
780 | error = usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT); |
---|
781 | break; |
---|
782 | case U3GINIT_REZERO: |
---|
783 | error = usb_msc_eject(udev, 0, MSC_EJECT_REZERO); |
---|
784 | break; |
---|
785 | case U3GINIT_ZTESTOR: |
---|
786 | error = usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT); |
---|
787 | if (error == 0) |
---|
788 | error = usb_msc_eject(udev, 0, MSC_EJECT_ZTESTOR); |
---|
789 | break; |
---|
790 | case U3GINIT_CMOTECH: |
---|
791 | error = usb_msc_eject(udev, 0, MSC_EJECT_CMOTECH); |
---|
792 | break; |
---|
793 | case U3GINIT_TCT: |
---|
794 | error = usb_msc_eject(udev, 0, MSC_EJECT_TCT); |
---|
795 | break; |
---|
796 | case U3GINIT_SIERRA: |
---|
797 | error = u3g_sierra_init(udev); |
---|
798 | break; |
---|
799 | case U3GINIT_WAIT: |
---|
800 | /* Just pretend we ejected, the card will timeout */ |
---|
801 | error = 0; |
---|
802 | break; |
---|
803 | default: |
---|
804 | /* no 3G eject quirks */ |
---|
805 | error = EOPNOTSUPP; |
---|
806 | break; |
---|
807 | } |
---|
808 | if (error == 0) { |
---|
809 | /* success, mark the udev as disappearing */ |
---|
810 | uaa->dev_state = UAA_DEV_EJECTING; |
---|
811 | } |
---|
812 | } |
---|
813 | |
---|
814 | static int |
---|
815 | u3g_driver_loaded(struct module *mod, int what, void *arg) |
---|
816 | { |
---|
817 | switch (what) { |
---|
818 | case MOD_LOAD: |
---|
819 | /* register our autoinstall handler */ |
---|
820 | u3g_etag = EVENTHANDLER_REGISTER(usb_dev_configured, |
---|
821 | u3g_test_autoinst, NULL, EVENTHANDLER_PRI_ANY); |
---|
822 | break; |
---|
823 | case MOD_UNLOAD: |
---|
824 | EVENTHANDLER_DEREGISTER(usb_dev_configured, u3g_etag); |
---|
825 | break; |
---|
826 | default: |
---|
827 | return (EOPNOTSUPP); |
---|
828 | } |
---|
829 | return (0); |
---|
830 | } |
---|
831 | |
---|
832 | static int |
---|
833 | u3g_probe(device_t self) |
---|
834 | { |
---|
835 | struct usb_attach_arg *uaa = device_get_ivars(self); |
---|
836 | |
---|
837 | if (uaa->usb_mode != USB_MODE_HOST) { |
---|
838 | return (ENXIO); |
---|
839 | } |
---|
840 | if (uaa->info.bConfigIndex != U3G_CONFIG_INDEX) { |
---|
841 | return (ENXIO); |
---|
842 | } |
---|
843 | if (uaa->info.bInterfaceClass != UICLASS_VENDOR) { |
---|
844 | return (ENXIO); |
---|
845 | } |
---|
846 | return (usbd_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa)); |
---|
847 | } |
---|
848 | |
---|
849 | static int |
---|
850 | u3g_attach(device_t dev) |
---|
851 | { |
---|
852 | struct usb_config u3g_config_tmp[U3G_N_TRANSFER]; |
---|
853 | struct usb_attach_arg *uaa = device_get_ivars(dev); |
---|
854 | struct u3g_softc *sc = device_get_softc(dev); |
---|
855 | struct usb_interface *iface; |
---|
856 | struct usb_interface_descriptor *id; |
---|
857 | uint32_t iface_valid; |
---|
858 | int error, type, nports; |
---|
859 | int ep, n; |
---|
860 | uint8_t i; |
---|
861 | |
---|
862 | DPRINTF("sc=%p\n", sc); |
---|
863 | |
---|
864 | type = USB_GET_DRIVER_INFO(uaa); |
---|
865 | if (type == U3GINIT_SAEL_M460 |
---|
866 | || usb_test_quirk(uaa, UQ_MSC_EJECT_SAEL_M460)) { |
---|
867 | u3g_sael_m460_init(uaa->device); |
---|
868 | } |
---|
869 | |
---|
870 | /* copy in USB config */ |
---|
871 | for (n = 0; n != U3G_N_TRANSFER; n++) |
---|
872 | u3g_config_tmp[n] = u3g_config[n]; |
---|
873 | |
---|
874 | device_set_usb_desc(dev); |
---|
875 | mtx_init(&sc->sc_mtx, "u3g", NULL, MTX_DEF); |
---|
876 | ucom_ref(&sc->sc_super_ucom); |
---|
877 | |
---|
878 | sc->sc_udev = uaa->device; |
---|
879 | |
---|
880 | /* Claim all interfaces on the device */ |
---|
881 | iface_valid = 0; |
---|
882 | for (i = uaa->info.bIfaceIndex; i < USB_IFACE_MAX; i++) { |
---|
883 | iface = usbd_get_iface(uaa->device, i); |
---|
884 | if (iface == NULL) |
---|
885 | break; |
---|
886 | id = usbd_get_interface_descriptor(iface); |
---|
887 | if (id == NULL || id->bInterfaceClass != UICLASS_VENDOR) |
---|
888 | continue; |
---|
889 | usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); |
---|
890 | iface_valid |= (1<<i); |
---|
891 | } |
---|
892 | |
---|
893 | i = 0; /* interface index */ |
---|
894 | ep = 0; /* endpoint index */ |
---|
895 | nports = 0; /* number of ports */ |
---|
896 | while (i < USB_IFACE_MAX) { |
---|
897 | if ((iface_valid & (1<<i)) == 0) { |
---|
898 | i++; |
---|
899 | continue; |
---|
900 | } |
---|
901 | |
---|
902 | /* update BULK endpoint index */ |
---|
903 | for (n = 0; n < U3G_N_TRANSFER; n++) |
---|
904 | u3g_config_tmp[n].ep_index = ep; |
---|
905 | |
---|
906 | /* try to allocate a set of BULK endpoints */ |
---|
907 | error = usbd_transfer_setup(uaa->device, &i, |
---|
908 | sc->sc_xfer[nports], u3g_config_tmp, U3G_N_TRANSFER, |
---|
909 | &sc->sc_ucom[nports], &sc->sc_mtx); |
---|
910 | if (error) { |
---|
911 | /* next interface */ |
---|
912 | i++; |
---|
913 | ep = 0; |
---|
914 | continue; |
---|
915 | } |
---|
916 | |
---|
917 | iface = usbd_get_iface(uaa->device, i); |
---|
918 | id = usbd_get_interface_descriptor(iface); |
---|
919 | sc->sc_iface[nports] = id->bInterfaceNumber; |
---|
920 | |
---|
921 | if (bootverbose && sc->sc_xfer[nports][U3G_INTR]) { |
---|
922 | device_printf(dev, "port %d supports modem control\n", |
---|
923 | nports); |
---|
924 | } |
---|
925 | |
---|
926 | /* set stall by default */ |
---|
927 | mtx_lock(&sc->sc_mtx); |
---|
928 | usbd_xfer_set_stall(sc->sc_xfer[nports][U3G_BULK_WR]); |
---|
929 | usbd_xfer_set_stall(sc->sc_xfer[nports][U3G_BULK_RD]); |
---|
930 | mtx_unlock(&sc->sc_mtx); |
---|
931 | |
---|
932 | nports++; /* found one port */ |
---|
933 | ep++; |
---|
934 | if (nports == U3G_MAXPORTS) |
---|
935 | break; |
---|
936 | } |
---|
937 | if (nports == 0) { |
---|
938 | device_printf(dev, "no ports found\n"); |
---|
939 | goto detach; |
---|
940 | } |
---|
941 | sc->sc_numports = nports; |
---|
942 | |
---|
943 | error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, |
---|
944 | sc->sc_numports, sc, &u3g_callback, &sc->sc_mtx); |
---|
945 | if (error) { |
---|
946 | DPRINTF("ucom_attach failed\n"); |
---|
947 | goto detach; |
---|
948 | } |
---|
949 | ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); |
---|
950 | device_printf(dev, "Found %u port%s.\n", sc->sc_numports, |
---|
951 | sc->sc_numports > 1 ? "s":""); |
---|
952 | |
---|
953 | return (0); |
---|
954 | |
---|
955 | detach: |
---|
956 | u3g_detach(dev); |
---|
957 | return (ENXIO); |
---|
958 | } |
---|
959 | |
---|
960 | static int |
---|
961 | u3g_detach(device_t dev) |
---|
962 | { |
---|
963 | struct u3g_softc *sc = device_get_softc(dev); |
---|
964 | uint8_t subunit; |
---|
965 | |
---|
966 | DPRINTF("sc=%p\n", sc); |
---|
967 | |
---|
968 | /* NOTE: It is not dangerous to detach more ports than attached! */ |
---|
969 | ucom_detach(&sc->sc_super_ucom, sc->sc_ucom); |
---|
970 | |
---|
971 | for (subunit = 0; subunit != U3G_MAXPORTS; subunit++) |
---|
972 | usbd_transfer_unsetup(sc->sc_xfer[subunit], U3G_N_TRANSFER); |
---|
973 | |
---|
974 | device_claim_softc(dev); |
---|
975 | |
---|
976 | u3g_free_softc(sc); |
---|
977 | |
---|
978 | return (0); |
---|
979 | } |
---|
980 | |
---|
981 | UCOM_UNLOAD_DRAIN(u3g); |
---|
982 | |
---|
983 | static void |
---|
984 | u3g_free_softc(struct u3g_softc *sc) |
---|
985 | { |
---|
986 | if (ucom_unref(&sc->sc_super_ucom)) { |
---|
987 | mtx_destroy(&sc->sc_mtx); |
---|
988 | device_free_softc(sc); |
---|
989 | } |
---|
990 | } |
---|
991 | |
---|
992 | static void |
---|
993 | u3g_free(struct ucom_softc *ucom) |
---|
994 | { |
---|
995 | u3g_free_softc(ucom->sc_parent); |
---|
996 | } |
---|
997 | |
---|
998 | static void |
---|
999 | u3g_start_read(struct ucom_softc *ucom) |
---|
1000 | { |
---|
1001 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1002 | |
---|
1003 | /* start interrupt endpoint (if configured) */ |
---|
1004 | usbd_transfer_start(sc->sc_xfer[ucom->sc_subunit][U3G_INTR]); |
---|
1005 | |
---|
1006 | /* start read endpoint */ |
---|
1007 | usbd_transfer_start(sc->sc_xfer[ucom->sc_subunit][U3G_BULK_RD]); |
---|
1008 | } |
---|
1009 | |
---|
1010 | static void |
---|
1011 | u3g_stop_read(struct ucom_softc *ucom) |
---|
1012 | { |
---|
1013 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1014 | |
---|
1015 | /* stop interrupt endpoint (if configured) */ |
---|
1016 | usbd_transfer_stop(sc->sc_xfer[ucom->sc_subunit][U3G_INTR]); |
---|
1017 | |
---|
1018 | /* stop read endpoint */ |
---|
1019 | usbd_transfer_stop(sc->sc_xfer[ucom->sc_subunit][U3G_BULK_RD]); |
---|
1020 | } |
---|
1021 | |
---|
1022 | static void |
---|
1023 | u3g_start_write(struct ucom_softc *ucom) |
---|
1024 | { |
---|
1025 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1026 | |
---|
1027 | usbd_transfer_start(sc->sc_xfer[ucom->sc_subunit][U3G_BULK_WR]); |
---|
1028 | } |
---|
1029 | |
---|
1030 | static void |
---|
1031 | u3g_stop_write(struct ucom_softc *ucom) |
---|
1032 | { |
---|
1033 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1034 | |
---|
1035 | usbd_transfer_stop(sc->sc_xfer[ucom->sc_subunit][U3G_BULK_WR]); |
---|
1036 | } |
---|
1037 | |
---|
1038 | static void |
---|
1039 | u3g_write_callback(struct usb_xfer *xfer, usb_error_t error) |
---|
1040 | { |
---|
1041 | struct ucom_softc *ucom = usbd_xfer_softc(xfer); |
---|
1042 | struct usb_page_cache *pc; |
---|
1043 | uint32_t actlen; |
---|
1044 | uint32_t frame; |
---|
1045 | |
---|
1046 | switch (USB_GET_STATE(xfer)) { |
---|
1047 | case USB_ST_TRANSFERRED: |
---|
1048 | case USB_ST_SETUP: |
---|
1049 | tr_setup: |
---|
1050 | for (frame = 0; frame != U3G_TXFRAMES; frame++) { |
---|
1051 | usbd_xfer_set_frame_offset(xfer, frame * U3G_TXSIZE, frame); |
---|
1052 | |
---|
1053 | pc = usbd_xfer_get_frame(xfer, frame); |
---|
1054 | if (ucom_get_data(ucom, pc, 0, U3G_TXSIZE, &actlen) == 0) |
---|
1055 | break; |
---|
1056 | usbd_xfer_set_frame_len(xfer, frame, actlen); |
---|
1057 | } |
---|
1058 | if (frame != 0) { |
---|
1059 | usbd_xfer_set_frames(xfer, frame); |
---|
1060 | usbd_transfer_submit(xfer); |
---|
1061 | } |
---|
1062 | break; |
---|
1063 | |
---|
1064 | default: /* Error */ |
---|
1065 | if (error != USB_ERR_CANCELLED) { |
---|
1066 | /* do a builtin clear-stall */ |
---|
1067 | usbd_xfer_set_stall(xfer); |
---|
1068 | goto tr_setup; |
---|
1069 | } |
---|
1070 | break; |
---|
1071 | } |
---|
1072 | } |
---|
1073 | |
---|
1074 | static void |
---|
1075 | u3g_read_callback(struct usb_xfer *xfer, usb_error_t error) |
---|
1076 | { |
---|
1077 | struct ucom_softc *ucom = usbd_xfer_softc(xfer); |
---|
1078 | struct usb_page_cache *pc; |
---|
1079 | int actlen; |
---|
1080 | |
---|
1081 | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); |
---|
1082 | |
---|
1083 | switch (USB_GET_STATE(xfer)) { |
---|
1084 | case USB_ST_TRANSFERRED: |
---|
1085 | pc = usbd_xfer_get_frame(xfer, 0); |
---|
1086 | ucom_put_data(ucom, pc, 0, actlen); |
---|
1087 | |
---|
1088 | case USB_ST_SETUP: |
---|
1089 | tr_setup: |
---|
1090 | usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); |
---|
1091 | usbd_transfer_submit(xfer); |
---|
1092 | break; |
---|
1093 | |
---|
1094 | default: /* Error */ |
---|
1095 | if (error != USB_ERR_CANCELLED) { |
---|
1096 | /* do a builtin clear-stall */ |
---|
1097 | usbd_xfer_set_stall(xfer); |
---|
1098 | goto tr_setup; |
---|
1099 | } |
---|
1100 | break; |
---|
1101 | } |
---|
1102 | } |
---|
1103 | |
---|
1104 | static void |
---|
1105 | u3g_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) |
---|
1106 | { |
---|
1107 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1108 | |
---|
1109 | /* XXX Note: sc_lsr is always zero */ |
---|
1110 | *lsr = sc->sc_lsr[ucom->sc_subunit]; |
---|
1111 | *msr = sc->sc_msr[ucom->sc_subunit]; |
---|
1112 | } |
---|
1113 | |
---|
1114 | static void |
---|
1115 | u3g_cfg_set_line(struct ucom_softc *ucom) |
---|
1116 | { |
---|
1117 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1118 | struct usb_device_request req; |
---|
1119 | |
---|
1120 | req.bmRequestType = UT_WRITE_CLASS_INTERFACE; |
---|
1121 | req.bRequest = UCDC_SET_CONTROL_LINE_STATE; |
---|
1122 | USETW(req.wValue, sc->sc_line[ucom->sc_subunit]); |
---|
1123 | req.wIndex[0] = sc->sc_iface[ucom->sc_subunit]; |
---|
1124 | req.wIndex[1] = 0; |
---|
1125 | USETW(req.wLength, 0); |
---|
1126 | |
---|
1127 | ucom_cfg_do_request(sc->sc_udev, ucom, |
---|
1128 | &req, NULL, 0, 1000); |
---|
1129 | } |
---|
1130 | |
---|
1131 | static void |
---|
1132 | u3g_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) |
---|
1133 | { |
---|
1134 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1135 | |
---|
1136 | DPRINTF("onoff = %d\n", onoff); |
---|
1137 | |
---|
1138 | if (onoff) |
---|
1139 | sc->sc_line[ucom->sc_subunit] |= UCDC_LINE_DTR; |
---|
1140 | else |
---|
1141 | sc->sc_line[ucom->sc_subunit] &= ~UCDC_LINE_DTR; |
---|
1142 | |
---|
1143 | u3g_cfg_set_line(ucom); |
---|
1144 | } |
---|
1145 | |
---|
1146 | static void |
---|
1147 | u3g_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) |
---|
1148 | { |
---|
1149 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1150 | |
---|
1151 | DPRINTF("onoff = %d\n", onoff); |
---|
1152 | |
---|
1153 | if (onoff) |
---|
1154 | sc->sc_line[ucom->sc_subunit] |= UCDC_LINE_RTS; |
---|
1155 | else |
---|
1156 | sc->sc_line[ucom->sc_subunit] &= ~UCDC_LINE_RTS; |
---|
1157 | |
---|
1158 | u3g_cfg_set_line(ucom); |
---|
1159 | } |
---|
1160 | |
---|
1161 | static void |
---|
1162 | u3g_intr_callback(struct usb_xfer *xfer, usb_error_t error) |
---|
1163 | { |
---|
1164 | struct ucom_softc *ucom = usbd_xfer_softc(xfer); |
---|
1165 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1166 | struct usb_page_cache *pc; |
---|
1167 | struct usb_cdc_notification pkt; |
---|
1168 | int actlen; |
---|
1169 | uint16_t wLen; |
---|
1170 | uint8_t mstatus; |
---|
1171 | |
---|
1172 | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); |
---|
1173 | |
---|
1174 | switch (USB_GET_STATE(xfer)) { |
---|
1175 | case USB_ST_TRANSFERRED: |
---|
1176 | if (actlen < 8) { /* usb_cdc_notification with 2 data bytes */ |
---|
1177 | DPRINTF("message too short (expected 8, received %d)\n", actlen); |
---|
1178 | goto tr_setup; |
---|
1179 | } |
---|
1180 | pc = usbd_xfer_get_frame(xfer, 0); |
---|
1181 | usbd_copy_out(pc, 0, &pkt, actlen); |
---|
1182 | |
---|
1183 | wLen = UGETW(pkt.wLength); |
---|
1184 | if (wLen < 2) { |
---|
1185 | DPRINTF("message too short (expected 2 data bytes, received %d)\n", wLen); |
---|
1186 | goto tr_setup; |
---|
1187 | } |
---|
1188 | |
---|
1189 | if (pkt.bmRequestType == UCDC_NOTIFICATION |
---|
1190 | && pkt.bNotification == UCDC_N_SERIAL_STATE) { |
---|
1191 | /* |
---|
1192 | * Set the serial state in ucom driver based on |
---|
1193 | * the bits from the notify message |
---|
1194 | */ |
---|
1195 | DPRINTF("notify bytes = 0x%02x, 0x%02x\n", |
---|
1196 | pkt.data[0], pkt.data[1]); |
---|
1197 | |
---|
1198 | /* currently, lsr is always zero. */ |
---|
1199 | sc->sc_lsr[ucom->sc_subunit] = 0; |
---|
1200 | sc->sc_msr[ucom->sc_subunit] = 0; |
---|
1201 | |
---|
1202 | mstatus = pkt.data[0]; |
---|
1203 | |
---|
1204 | if (mstatus & UCDC_N_SERIAL_RI) |
---|
1205 | sc->sc_msr[ucom->sc_subunit] |= SER_RI; |
---|
1206 | if (mstatus & UCDC_N_SERIAL_DSR) |
---|
1207 | sc->sc_msr[ucom->sc_subunit] |= SER_DSR; |
---|
1208 | if (mstatus & UCDC_N_SERIAL_DCD) |
---|
1209 | sc->sc_msr[ucom->sc_subunit] |= SER_DCD; |
---|
1210 | ucom_status_change(ucom); |
---|
1211 | } |
---|
1212 | |
---|
1213 | case USB_ST_SETUP: |
---|
1214 | tr_setup: |
---|
1215 | usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); |
---|
1216 | usbd_transfer_submit(xfer); |
---|
1217 | return; |
---|
1218 | |
---|
1219 | default: /* Error */ |
---|
1220 | if (error != USB_ERR_CANCELLED) { |
---|
1221 | /* try to clear stall first */ |
---|
1222 | usbd_xfer_set_stall(xfer); |
---|
1223 | goto tr_setup; |
---|
1224 | } |
---|
1225 | return; |
---|
1226 | } |
---|
1227 | } |
---|
1228 | |
---|
1229 | static void |
---|
1230 | u3g_poll(struct ucom_softc *ucom) |
---|
1231 | { |
---|
1232 | struct u3g_softc *sc = ucom->sc_parent; |
---|
1233 | usbd_transfer_poll(sc->sc_xfer[ucom->sc_subunit], U3G_N_TRANSFER); |
---|
1234 | } |
---|