File: | dev/usb/if_bwfm_usb.c |
Warning: | line 728, column 2 Value stored to 'rdlbytes' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: if_bwfm_usb.c,v 1.20 2021/11/05 11:38:51 mpi Exp $ */ |
2 | /* |
3 | * Copyright (c) 2010-2016 Broadcom Corporation |
4 | * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> |
5 | * |
6 | * Permission to use, copy, modify, and/or distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include "bpfilter.h" |
20 | |
21 | #include <sys/param.h> |
22 | #include <sys/systm.h> |
23 | #include <sys/buf.h> |
24 | #include <sys/kernel.h> |
25 | #include <sys/malloc.h> |
26 | #include <sys/device.h> |
27 | #include <sys/queue.h> |
28 | #include <sys/socket.h> |
29 | |
30 | #if NBPFILTER1 > 0 |
31 | #include <net/bpf.h> |
32 | #endif |
33 | #include <net/if.h> |
34 | #include <net/if_dl.h> |
35 | #include <net/if_media.h> |
36 | |
37 | #include <netinet/in.h> |
38 | #include <netinet/if_ether.h> |
39 | |
40 | #include <net80211/ieee80211_var.h> |
41 | |
42 | #include <machine/bus.h> |
43 | |
44 | #include <dev/usb/usb.h> |
45 | #include <dev/usb/usbdi.h> |
46 | #include <dev/usb/usbdi_util.h> |
47 | #include <dev/usb/usbdivar.h> |
48 | #include <dev/usb/usb_mem.h> |
49 | #include <dev/usb/usbdevs.h> |
50 | |
51 | #include <dev/ic/bwfmvar.h> |
52 | #include <dev/ic/bwfmreg.h> |
53 | |
54 | /* |
55 | * Various supported device vendors/products. |
56 | */ |
57 | static const struct usb_devno bwfm_usbdevs[] = { |
58 | { USB_VENDOR_BROADCOM0x0a5c, USB_PRODUCT_BROADCOM_BCM431430xbd1e }, |
59 | { USB_VENDOR_BROADCOM0x0a5c, USB_PRODUCT_BROADCOM_BCM432360xbd17 }, |
60 | { USB_VENDOR_BROADCOM0x0a5c, USB_PRODUCT_BROADCOM_BCM432420xbd1f }, |
61 | { USB_VENDOR_BROADCOM0x0a5c, USB_PRODUCT_BROADCOM_BCM435690xbd27 }, |
62 | { USB_VENDOR_BROADCOM0x0a5c, USB_PRODUCT_BROADCOM_BCMFW0x0bdc }, |
63 | }; |
64 | |
65 | #ifdef BWFM_DEBUG |
66 | #define DPRINTF(x)do { ; } while (0) do { if (bwfm_debug > 0) printf x; } while (0) |
67 | #define DPRINTFN(n, x)do { ; } while (0) do { if (bwfm_debug >= (n)) printf x; } while (0) |
68 | static int bwfm_debug = 2; |
69 | #else |
70 | #define DPRINTF(x)do { ; } while (0) do { ; } while (0) |
71 | #define DPRINTFN(n, x)do { ; } while (0) do { ; } while (0) |
72 | #endif |
73 | |
74 | #define DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname) ((sc)->sc_sc.sc_dev.dv_xname) |
75 | |
76 | #define BRCMF_POSTBOOT_ID0xA123 0xA123 /* ID to detect if dongle |
77 | * has boot up |
78 | */ |
79 | |
80 | #define TRX_MAGIC0x30524448 0x30524448 /* "HDR0" */ |
81 | #define TRX_MAX_OFFSET3 3 /* Max number of file offsets */ |
82 | #define TRX_UNCOMP_IMAGE0x20 0x20 /* Trx holds uncompressed img */ |
83 | #define TRX_RDL_CHUNK1500 1500 /* size of each dl transfer */ |
84 | #define TRX_OFFSETS_DLFWLEN_IDX0 0 |
85 | |
86 | /* Control messages: bRequest values */ |
87 | #define DL_GETSTATE0 0 /* returns the rdl_state_t struct */ |
88 | #define DL_CHECK_CRC1 1 /* currently unused */ |
89 | #define DL_GO2 2 /* execute downloaded image */ |
90 | #define DL_START3 3 /* initialize dl state */ |
91 | #define DL_REBOOT4 4 /* reboot the device in 2 seconds */ |
92 | #define DL_GETVER5 5 /* returns the bootrom_id_t struct */ |
93 | #define DL_GO_PROTECTED6 6 /* execute the downloaded code and set reset |
94 | * event to occur in 2 seconds. It is the |
95 | * responsibility of the downloaded code to |
96 | * clear this event |
97 | */ |
98 | #define DL_EXEC7 7 /* jump to a supplied address */ |
99 | #define DL_RESETCFG8 8 /* To support single enum on dongle |
100 | * - Not used by bootloader |
101 | */ |
102 | #define DL_DEFER_RESP_OK9 9 /* Potentially defer the response to setup |
103 | * if resp unavailable |
104 | */ |
105 | |
106 | /* states */ |
107 | #define DL_WAITING0 0 /* waiting to rx first pkt */ |
108 | #define DL_READY1 1 /* hdr was good, waiting for more of the |
109 | * compressed image |
110 | */ |
111 | #define DL_BAD_HDR2 2 /* hdr was corrupted */ |
112 | #define DL_BAD_CRC3 3 /* compressed image was corrupted */ |
113 | #define DL_RUNNABLE4 4 /* download was successful,waiting for go cmd */ |
114 | #define DL_START_FAIL5 5 /* failed to initialize correctly */ |
115 | #define DL_NVRAM_TOOBIG6 6 /* host specified nvram data exceeds DL_NVRAM |
116 | * value |
117 | */ |
118 | #define DL_IMAGE_TOOBIG7 7 /* firmware image too big */ |
119 | |
120 | |
121 | struct trx_header { |
122 | uint32_t magic; /* "HDR0" */ |
123 | uint32_t len; /* Length of file including header */ |
124 | uint32_t crc32; /* CRC from flag_version to end of file */ |
125 | uint32_t flag_version; /* 0:15 flags, 16:31 version */ |
126 | uint32_t offsets[TRX_MAX_OFFSET3];/* Offsets of partitions from start of |
127 | * header |
128 | */ |
129 | }; |
130 | |
131 | struct rdl_state { |
132 | uint32_t state; |
133 | uint32_t bytes; |
134 | }; |
135 | |
136 | struct bootrom_id { |
137 | uint32_t chip; /* Chip id */ |
138 | uint32_t chiprev; /* Chip rev */ |
139 | uint32_t ramsize; /* Size of RAM */ |
140 | uint32_t remapbase; /* Current remap base address */ |
141 | uint32_t boardtype; /* Type of board */ |
142 | uint32_t boardrev; /* Board revision */ |
143 | }; |
144 | |
145 | struct bwfm_usb_rx_data { |
146 | struct bwfm_usb_softc *sc; |
147 | struct usbd_xfer *xfer; |
148 | uint8_t *buf; |
149 | }; |
150 | |
151 | struct bwfm_usb_tx_data { |
152 | struct bwfm_usb_softc *sc; |
153 | struct usbd_xfer *xfer; |
154 | uint8_t *buf; |
155 | struct mbuf *mbuf; |
156 | TAILQ_ENTRY(bwfm_usb_tx_data)struct { struct bwfm_usb_tx_data *tqe_next; struct bwfm_usb_tx_data **tqe_prev; } next; |
157 | }; |
158 | |
159 | #define BWFM_RX_LIST_COUNT50 50 |
160 | #define BWFM_TX_LIST_COUNT50 50 |
161 | #define BWFM_RXBUFSZ1600 1600 |
162 | #define BWFM_TXBUFSZ1600 1600 |
163 | struct bwfm_usb_softc { |
164 | struct bwfm_softc sc_sc; |
165 | struct usbd_device *sc_udev; |
166 | struct usbd_interface *sc_iface; |
167 | uint8_t sc_ifaceno; |
168 | |
169 | int sc_initialized; |
170 | |
171 | uint16_t sc_vendor; |
172 | uint16_t sc_product; |
173 | |
174 | uint32_t sc_chip; |
175 | uint32_t sc_chiprev; |
176 | |
177 | int sc_rx_no; |
178 | int sc_tx_no; |
179 | |
180 | struct usbd_pipe *sc_rx_pipeh; |
181 | struct usbd_pipe *sc_tx_pipeh; |
182 | |
183 | struct bwfm_usb_rx_data sc_rx_data[BWFM_RX_LIST_COUNT50]; |
184 | struct bwfm_usb_tx_data sc_tx_data[BWFM_TX_LIST_COUNT50]; |
185 | TAILQ_HEAD(, bwfm_usb_tx_data)struct { struct bwfm_usb_tx_data *tqh_first; struct bwfm_usb_tx_data **tqh_last; } sc_tx_free_list; |
186 | }; |
187 | |
188 | int bwfm_usb_match(struct device *, void *, void *); |
189 | void bwfm_usb_attach(struct device *, struct device *, void *); |
190 | int bwfm_usb_detach(struct device *, int); |
191 | |
192 | int bwfm_usb_dl_cmd(struct bwfm_usb_softc *, uint8_t, void *, int); |
193 | int bwfm_usb_load_microcode(struct bwfm_usb_softc *, const u_char *, |
194 | size_t); |
195 | |
196 | int bwfm_usb_alloc_rx_list(struct bwfm_usb_softc *); |
197 | void bwfm_usb_free_rx_list(struct bwfm_usb_softc *); |
198 | int bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *); |
199 | void bwfm_usb_free_tx_list(struct bwfm_usb_softc *); |
200 | |
201 | int bwfm_usb_preinit(struct bwfm_softc *); |
202 | int bwfm_usb_txcheck(struct bwfm_softc *); |
203 | int bwfm_usb_txdata(struct bwfm_softc *, struct mbuf *); |
204 | int bwfm_usb_txctl(struct bwfm_softc *, void *); |
205 | void bwfm_usb_txctl_cb(struct usbd_xfer *, void *, usbd_status); |
206 | |
207 | struct mbuf * bwfm_usb_newbuf(void); |
208 | void bwfm_usb_rxeof(struct usbd_xfer *, void *, usbd_status); |
209 | void bwfm_usb_txeof(struct usbd_xfer *, void *, usbd_status); |
210 | |
211 | struct bwfm_bus_ops bwfm_usb_bus_ops = { |
212 | .bs_preinit = bwfm_usb_preinit, |
213 | .bs_stop = NULL((void *)0), |
214 | .bs_txcheck = bwfm_usb_txcheck, |
215 | .bs_txdata = bwfm_usb_txdata, |
216 | .bs_txctl = bwfm_usb_txctl, |
217 | }; |
218 | |
219 | const struct cfattach bwfm_usb_ca = { |
220 | sizeof(struct bwfm_usb_softc), |
221 | bwfm_usb_match, |
222 | bwfm_usb_attach, |
223 | bwfm_usb_detach, |
224 | }; |
225 | |
226 | int |
227 | bwfm_usb_match(struct device *parent, void *match, void *aux) |
228 | { |
229 | struct usb_attach_arg *uaa = aux; |
230 | |
231 | if (uaa->iface == NULL((void *)0) || uaa->configno != 1) |
232 | return UMATCH_NONE0; |
233 | |
234 | return (usb_lookup(bwfm_usbdevs, uaa->vendor, uaa->product)usbd_match_device((const struct usb_devno *)(bwfm_usbdevs), sizeof (bwfm_usbdevs) / sizeof ((bwfm_usbdevs)[0]), sizeof ((bwfm_usbdevs )[0]), (uaa->vendor), (uaa->product)) != NULL((void *)0)) ? |
235 | UMATCH_VENDOR_PRODUCT_CONF_IFACE8 : UMATCH_NONE0; |
236 | } |
237 | |
238 | void |
239 | bwfm_usb_attach(struct device *parent, struct device *self, void *aux) |
240 | { |
241 | struct bwfm_usb_softc *sc = (struct bwfm_usb_softc *)self; |
242 | struct usb_attach_arg *uaa = aux; |
243 | usb_device_descriptor_t *dd; |
244 | usb_interface_descriptor_t *id; |
245 | usb_endpoint_descriptor_t *ed; |
246 | int i; |
247 | |
248 | sc->sc_udev = uaa->device; |
249 | sc->sc_iface = uaa->iface; |
250 | sc->sc_ifaceno = uaa->ifaceno; |
251 | sc->sc_vendor = uaa->vendor; |
252 | sc->sc_product = uaa->product; |
253 | sc->sc_sc.sc_bus_ops = &bwfm_usb_bus_ops; |
254 | sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops; |
255 | |
256 | /* Check number of configurations. */ |
257 | dd = usbd_get_device_descriptor(sc->sc_udev); |
258 | if (dd->bNumConfigurations != 1) { |
259 | printf("%s: number of configurations not supported\n", |
260 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
261 | return; |
262 | } |
263 | |
264 | /* Get endpoints. */ |
265 | id = usbd_get_interface_descriptor(sc->sc_iface); |
266 | |
267 | sc->sc_rx_no = sc->sc_tx_no = -1; |
268 | for (i = 0; i < id->bNumEndpoints; i++) { |
269 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); |
270 | if (ed == NULL((void *)0)) { |
271 | printf("%s: no endpoint descriptor for iface %d\n", |
272 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), i); |
273 | return; |
274 | } |
275 | |
276 | if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_IN0x80 && |
277 | UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02 && |
278 | sc->sc_rx_no == -1) |
279 | sc->sc_rx_no = ed->bEndpointAddress; |
280 | else if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_OUT0x00 && |
281 | UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02 && |
282 | sc->sc_tx_no == -1) |
283 | sc->sc_tx_no = ed->bEndpointAddress; |
284 | } |
285 | if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) { |
286 | printf("%s: missing endpoint\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
287 | return; |
288 | } |
289 | |
290 | bwfm_attach(&sc->sc_sc); |
291 | config_mountroot(self, bwfm_attachhook); |
292 | } |
293 | |
294 | int |
295 | bwfm_usb_preinit(struct bwfm_softc *bwfm) |
296 | { |
297 | struct bwfm_usb_softc *sc = (void *)bwfm; |
298 | struct bwfm_usb_rx_data *data; |
299 | const char *name = NULL((void *)0); |
300 | struct bootrom_id brom; |
301 | usbd_status error; |
302 | u_char *ucode; |
303 | size_t size; |
304 | int i; |
305 | |
306 | if (sc->sc_initialized) |
307 | return 0; |
308 | |
309 | /* Read chip id and chip rev to check the firmware. */ |
310 | memset(&brom, 0, sizeof(brom))__builtin_memset((&brom), (0), (sizeof(brom))); |
311 | bwfm_usb_dl_cmd(sc, DL_GETVER5, &brom, sizeof(brom)); |
312 | sc->sc_chip = letoh32(brom.chip)((__uint32_t)(brom.chip)); |
313 | sc->sc_chiprev = letoh32(brom.chiprev)((__uint32_t)(brom.chiprev)); |
314 | |
315 | /* Setup data pipes */ |
316 | error = usbd_open_pipe(sc->sc_iface, sc->sc_rx_no, USBD_EXCLUSIVE_USE0x01, |
317 | &sc->sc_rx_pipeh); |
318 | if (error != 0) { |
319 | printf("%s: could not open rx pipe: %s\n", |
320 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), usbd_errstr(error)); |
321 | return 1; |
322 | } |
323 | error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE0x01, |
324 | &sc->sc_tx_pipeh); |
325 | if (error != 0) { |
326 | printf("%s: could not open tx pipe: %s\n", |
327 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), usbd_errstr(error)); |
328 | goto cleanup; |
329 | } |
330 | |
331 | /* Firmware not yet loaded? */ |
332 | if (sc->sc_chip != BRCMF_POSTBOOT_ID0xA123) { |
333 | switch (sc->sc_chip) |
334 | { |
335 | case BRCM_CC_43143_CHIP_ID43143: |
336 | name = "brcmfmac43143.bin"; |
337 | break; |
338 | case BRCM_CC_43235_CHIP_ID43235: |
339 | case BRCM_CC_43236_CHIP_ID43236: |
340 | case BRCM_CC_43238_CHIP_ID43238: |
341 | if (sc->sc_chiprev == 3) |
342 | name = "brcmfmac43236b.bin"; |
343 | break; |
344 | case BRCM_CC_43242_CHIP_ID43242: |
345 | name = "brcmfmac43242a.bin"; |
346 | break; |
347 | case BRCM_CC_43566_CHIP_ID43566: |
348 | case BRCM_CC_43569_CHIP_ID43569: |
349 | name = "brcmfmac43569.bin"; |
350 | break; |
351 | default: |
352 | break; |
353 | } |
354 | |
355 | if (name == NULL((void *)0)) { |
356 | printf("%s: unknown firmware\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
357 | goto cleanup; |
358 | } |
359 | |
360 | if (loadfirmware(name, &ucode, &size) != 0) { |
361 | printf("%s: failed loadfirmware of file %s\n", |
362 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), name); |
363 | goto cleanup; |
364 | } |
365 | |
366 | if (bwfm_usb_load_microcode(sc, ucode, size) != 0) { |
367 | printf("%s: could not load microcode\n", |
368 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
369 | free(ucode, M_DEVBUF2, size); |
370 | goto cleanup; |
371 | } |
372 | |
373 | free(ucode, M_DEVBUF2, size); |
374 | |
375 | for (i = 0; i < 10; i++) { |
376 | delay(100 * 1000)(*delay_func)(100 * 1000); |
377 | memset(&brom, 0, sizeof(brom))__builtin_memset((&brom), (0), (sizeof(brom))); |
378 | bwfm_usb_dl_cmd(sc, DL_GETVER5, &brom, sizeof(brom)); |
379 | if (letoh32(brom.chip)((__uint32_t)(brom.chip)) == BRCMF_POSTBOOT_ID0xA123) |
380 | break; |
381 | } |
382 | |
383 | if (letoh32(brom.chip)((__uint32_t)(brom.chip)) != BRCMF_POSTBOOT_ID0xA123) { |
384 | printf("%s: firmware did not start up\n", |
385 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
386 | goto cleanup; |
387 | } |
388 | |
389 | sc->sc_chip = letoh32(brom.chip)((__uint32_t)(brom.chip)); |
390 | sc->sc_chiprev = letoh32(brom.chiprev)((__uint32_t)(brom.chiprev)); |
391 | } |
392 | |
393 | bwfm_usb_dl_cmd(sc, DL_RESETCFG8, &brom, sizeof(brom)); |
394 | |
395 | if (bwfm_usb_alloc_rx_list(sc) || bwfm_usb_alloc_tx_list(sc)) { |
396 | printf("%s: cannot allocate rx/tx lists\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
397 | goto cleanup; |
398 | } |
399 | |
400 | for (i = 0; i < BWFM_RX_LIST_COUNT50; i++) { |
401 | data = &sc->sc_rx_data[i]; |
402 | |
403 | usbd_setup_xfer(data->xfer, sc->sc_rx_pipeh, data, data->buf, |
404 | BWFM_RXBUFSZ1600, USBD_SHORT_XFER_OK0x04 | USBD_NO_COPY0x01, USBD_NO_TIMEOUT0, |
405 | bwfm_usb_rxeof); |
406 | error = usbd_transfer(data->xfer); |
407 | if (error != 0 && error != USBD_IN_PROGRESS) |
408 | printf("%s: could not set up new transfer: %s\n", |
409 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), usbd_errstr(error)); |
410 | } |
411 | |
412 | sc->sc_initialized = 1; |
413 | return 0; |
414 | |
415 | cleanup: |
416 | if (sc->sc_rx_pipeh) { |
417 | usbd_close_pipe(sc->sc_rx_pipeh); |
418 | sc->sc_rx_pipeh = NULL((void *)0); |
419 | } |
420 | if (sc->sc_tx_pipeh) { |
421 | usbd_close_pipe(sc->sc_tx_pipeh); |
422 | sc->sc_tx_pipeh = NULL((void *)0); |
423 | } |
424 | bwfm_usb_free_rx_list(sc); |
425 | bwfm_usb_free_tx_list(sc); |
426 | return 1; |
427 | } |
428 | |
429 | struct mbuf * |
430 | bwfm_usb_newbuf(void) |
431 | { |
432 | struct mbuf *m; |
433 | |
434 | MGETHDR(m, M_DONTWAIT, MT_DATA)m = m_gethdr((0x0002), (1)); |
435 | if (m == NULL((void *)0)) |
436 | return (NULL((void *)0)); |
437 | |
438 | MCLGET(m, M_DONTWAIT)(void) m_clget((m), (0x0002), (1 << 11)); |
439 | if (!(m->m_flagsm_hdr.mh_flags & M_EXT0x0001)) { |
440 | m_freem(m); |
441 | return (NULL((void *)0)); |
442 | } |
443 | |
444 | m->m_lenm_hdr.mh_len = m->m_pkthdrM_dat.MH.MH_pkthdr.len = MCLBYTES(1 << 11); |
445 | |
446 | return (m); |
447 | } |
448 | |
449 | void |
450 | bwfm_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) |
451 | { |
452 | struct bwfm_usb_rx_data *data = priv; |
453 | struct bwfm_usb_softc *sc = data->sc; |
454 | struct mbuf_list ml = MBUF_LIST_INITIALIZER(){ ((void *)0), ((void *)0), 0 }; |
455 | struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_ific_ac.ac_if; |
456 | usbd_status error; |
457 | struct mbuf *m; |
458 | uint32_t len; |
459 | |
460 | DPRINTFN(2, ("%s: %s status %s\n", DEVNAME(sc), __func__,do { ; } while (0) |
461 | usbd_errstr(status)))do { ; } while (0); |
462 | |
463 | if (usbd_is_dying(sc->sc_udev)) |
464 | return; |
465 | |
466 | if (__predict_false(status != USBD_NORMAL_COMPLETION)__builtin_expect(((status != USBD_NORMAL_COMPLETION) != 0), 0 )) { |
467 | usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh); |
468 | if (status != USBD_CANCELLED) |
469 | goto resubmit; |
470 | return; |
471 | } |
472 | usbd_get_xfer_status(xfer, NULL((void *)0), NULL((void *)0), &len, NULL((void *)0)); |
473 | |
474 | m = bwfm_usb_newbuf(); |
475 | if (m == NULL((void *)0)) |
476 | goto resubmit; |
477 | |
478 | memcpy(mtod(m, char *), data->buf, len)__builtin_memcpy((((char *)((m)->m_hdr.mh_data))), (data-> buf), (len)); |
479 | m->m_lenm_hdr.mh_len = m->m_pkthdrM_dat.MH.MH_pkthdr.len = len; |
480 | sc->sc_sc.sc_proto_ops->proto_rx(&sc->sc_sc, m, &ml); |
481 | if_input(ifp, &ml); |
482 | |
483 | resubmit: |
484 | usbd_setup_xfer(data->xfer, sc->sc_rx_pipeh, data, data->buf, |
485 | BWFM_RXBUFSZ1600, USBD_SHORT_XFER_OK0x04 | USBD_NO_COPY0x01, USBD_NO_TIMEOUT0, |
486 | bwfm_usb_rxeof); |
487 | error = usbd_transfer(data->xfer); |
488 | if (error != 0 && error != USBD_IN_PROGRESS) |
489 | printf("%s: could not set up new transfer: %s\n", |
490 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), usbd_errstr(error)); |
491 | } |
492 | |
493 | int |
494 | bwfm_usb_alloc_rx_list(struct bwfm_usb_softc *sc) |
495 | { |
496 | struct bwfm_usb_rx_data *data; |
497 | int i, error = 0; |
498 | |
499 | for (i = 0; i < BWFM_RX_LIST_COUNT50; i++) { |
500 | data = &sc->sc_rx_data[i]; |
501 | |
502 | data->sc = sc; /* Backpointer for callbacks. */ |
503 | |
504 | data->xfer = usbd_alloc_xfer(sc->sc_udev); |
505 | if (data->xfer == NULL((void *)0)) { |
506 | printf("%s: could not allocate xfer\n", |
507 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
508 | error = ENOMEM12; |
509 | break; |
510 | } |
511 | data->buf = usbd_alloc_buffer(data->xfer, BWFM_RXBUFSZ1600); |
512 | if (data->buf == NULL((void *)0)) { |
513 | printf("%s: could not allocate xfer buffer\n", |
514 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
515 | error = ENOMEM12; |
516 | break; |
517 | } |
518 | } |
519 | if (error != 0) |
520 | bwfm_usb_free_rx_list(sc); |
521 | return (error); |
522 | } |
523 | |
524 | void |
525 | bwfm_usb_free_rx_list(struct bwfm_usb_softc *sc) |
526 | { |
527 | int i; |
528 | |
529 | /* NB: Caller must abort pipe first. */ |
530 | for (i = 0; i < BWFM_RX_LIST_COUNT50; i++) { |
531 | if (sc->sc_rx_data[i].xfer != NULL((void *)0)) |
532 | usbd_free_xfer(sc->sc_rx_data[i].xfer); |
533 | sc->sc_rx_data[i].xfer = NULL((void *)0); |
534 | } |
535 | } |
536 | |
537 | int |
538 | bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *sc) |
539 | { |
540 | struct bwfm_usb_tx_data *data; |
541 | int i, error = 0; |
542 | |
543 | TAILQ_INIT(&sc->sc_tx_free_list)do { (&sc->sc_tx_free_list)->tqh_first = ((void *)0 ); (&sc->sc_tx_free_list)->tqh_last = &(&sc ->sc_tx_free_list)->tqh_first; } while (0); |
544 | for (i = 0; i < BWFM_TX_LIST_COUNT50; i++) { |
545 | data = &sc->sc_tx_data[i]; |
546 | |
547 | data->sc = sc; /* Backpointer for callbacks. */ |
548 | |
549 | data->xfer = usbd_alloc_xfer(sc->sc_udev); |
550 | if (data->xfer == NULL((void *)0)) { |
551 | printf("%s: could not allocate xfer\n", |
552 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
553 | error = ENOMEM12; |
554 | break; |
555 | } |
556 | data->buf = usbd_alloc_buffer(data->xfer, BWFM_TXBUFSZ1600); |
557 | if (data->buf == NULL((void *)0)) { |
558 | printf("%s: could not allocate xfer buffer\n", |
559 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
560 | error = ENOMEM12; |
561 | break; |
562 | } |
563 | /* Append this Tx buffer to our free list. */ |
564 | TAILQ_INSERT_TAIL(&sc->sc_tx_free_list, data, next)do { (data)->next.tqe_next = ((void *)0); (data)->next. tqe_prev = (&sc->sc_tx_free_list)->tqh_last; *(& sc->sc_tx_free_list)->tqh_last = (data); (&sc->sc_tx_free_list )->tqh_last = &(data)->next.tqe_next; } while (0); |
565 | } |
566 | if (error != 0) |
567 | bwfm_usb_free_tx_list(sc); |
568 | return (error); |
569 | } |
570 | |
571 | void |
572 | bwfm_usb_free_tx_list(struct bwfm_usb_softc *sc) |
573 | { |
574 | int i; |
575 | |
576 | /* NB: Caller must abort pipe first. */ |
577 | for (i = 0; i < BWFM_TX_LIST_COUNT50; i++) { |
578 | if (sc->sc_tx_data[i].xfer != NULL((void *)0)) |
579 | usbd_free_xfer(sc->sc_tx_data[i].xfer); |
580 | sc->sc_tx_data[i].xfer = NULL((void *)0); |
581 | } |
582 | } |
583 | |
584 | void |
585 | bwfm_usb_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) |
586 | { |
587 | struct bwfm_usb_tx_data *data = priv; |
588 | struct bwfm_usb_softc *sc = data->sc; |
589 | struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_ific_ac.ac_if; |
590 | int s; |
591 | |
592 | DPRINTFN(2, ("%s: %s status %s\n", DEVNAME(sc), __func__,do { ; } while (0) |
593 | usbd_errstr(status)))do { ; } while (0); |
594 | |
595 | if (usbd_is_dying(sc->sc_udev)) |
596 | return; |
597 | |
598 | s = splnet()splraise(0x4); |
599 | /* Put this Tx buffer back to our free list. */ |
600 | TAILQ_INSERT_TAIL(&sc->sc_tx_free_list, data, next)do { (data)->next.tqe_next = ((void *)0); (data)->next. tqe_prev = (&sc->sc_tx_free_list)->tqh_last; *(& sc->sc_tx_free_list)->tqh_last = (data); (&sc->sc_tx_free_list )->tqh_last = &(data)->next.tqe_next; } while (0); |
601 | |
602 | if (__predict_false(status != USBD_NORMAL_COMPLETION)__builtin_expect(((status != USBD_NORMAL_COMPLETION) != 0), 0 )) { |
603 | if (status == USBD_CANCELLED) |
604 | usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh); |
605 | ifp->if_oerrorsif_data.ifi_oerrors++; |
606 | splx(s)spllower(s); |
607 | return; |
608 | } |
609 | |
610 | m_freem(data->mbuf); |
611 | data->mbuf = NULL((void *)0); |
612 | |
613 | /* We just released a Tx buffer, notify Tx. */ |
614 | if (ifq_is_oactive(&ifp->if_snd)) { |
615 | ifq_restart(&ifp->if_snd); |
616 | } |
617 | splx(s)spllower(s); |
618 | } |
619 | |
620 | int |
621 | bwfm_usb_detach(struct device *self, int flags) |
622 | { |
623 | struct bwfm_usb_softc *sc = (struct bwfm_usb_softc *)self; |
624 | |
625 | bwfm_detach(&sc->sc_sc, flags); |
626 | |
627 | if (sc->sc_rx_pipeh != NULL((void *)0)) |
628 | usbd_close_pipe(sc->sc_rx_pipeh); |
629 | if (sc->sc_tx_pipeh != NULL((void *)0)) |
630 | usbd_close_pipe(sc->sc_tx_pipeh); |
631 | |
632 | bwfm_usb_free_rx_list(sc); |
633 | bwfm_usb_free_tx_list(sc); |
634 | |
635 | return 0; |
636 | } |
637 | |
638 | int |
639 | bwfm_usb_dl_cmd(struct bwfm_usb_softc *sc, uByte cmd, void *buf, int len) |
640 | { |
641 | usb_device_request_t req; |
642 | usbd_status error; |
643 | |
644 | req.bmRequestType = UT_READ_VENDOR_INTERFACE(0x80 | 0x40 | 0x01); |
645 | req.bRequest = cmd; |
646 | |
647 | USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0)); |
648 | USETW(req.wIndex, sc->sc_ifaceno)(*(u_int16_t *)(req.wIndex) = (sc->sc_ifaceno)); |
649 | USETW(req.wLength, len)(*(u_int16_t *)(req.wLength) = (len)); |
650 | |
651 | error = usbd_do_request(sc->sc_udev, &req, buf); |
652 | if (error != 0) { |
653 | printf("%s: could not read register: %s\n", |
654 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), usbd_errstr(error)); |
655 | } |
656 | return error; |
657 | } |
658 | |
659 | int |
660 | bwfm_usb_load_microcode(struct bwfm_usb_softc *sc, const u_char *ucode, size_t size) |
661 | { |
662 | struct trx_header *trx = (struct trx_header *)ucode; |
663 | struct rdl_state state; |
664 | uint32_t rdlstate, rdlbytes, sent = 0, sendlen = 0; |
665 | struct usbd_xfer *xfer; |
666 | usbd_status error; |
667 | char *buf; |
668 | |
669 | if (letoh32(trx->magic)((__uint32_t)(trx->magic)) != TRX_MAGIC0x30524448 || |
670 | (letoh32(trx->flag_version)((__uint32_t)(trx->flag_version)) & TRX_UNCOMP_IMAGE0x20) == 0) { |
671 | printf("%s: invalid firmware\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
672 | return 1; |
673 | } |
674 | |
675 | bwfm_usb_dl_cmd(sc, DL_START3, &state, sizeof(state)); |
676 | rdlstate = letoh32(state.state)((__uint32_t)(state.state)); |
677 | rdlbytes = letoh32(state.bytes)((__uint32_t)(state.bytes)); |
678 | |
679 | if (rdlstate != DL_WAITING0) { |
680 | printf("%s: cannot start fw download\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
681 | return 1; |
682 | } |
683 | |
684 | xfer = usbd_alloc_xfer(sc->sc_udev); |
685 | if (xfer == NULL((void *)0)) { |
686 | printf("%s: cannot alloc xfer\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
687 | goto err; |
688 | } |
689 | |
690 | buf = usbd_alloc_buffer(xfer, TRX_RDL_CHUNK1500); |
691 | if (buf == NULL((void *)0)) { |
692 | printf("%s: cannot alloc buf\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
693 | goto err; |
694 | } |
695 | |
696 | while (rdlbytes != size) { |
697 | sendlen = MIN(size - sent, TRX_RDL_CHUNK)(((size - sent)<(1500))?(size - sent):(1500)); |
698 | memcpy(buf, ucode + sent, sendlen)__builtin_memcpy((buf), (ucode + sent), (sendlen)); |
699 | |
700 | usbd_setup_xfer(xfer, sc->sc_tx_pipeh, NULL((void *)0), buf, sendlen, |
701 | USBD_SYNCHRONOUS0x02 | USBD_NO_COPY0x01, USBD_NO_TIMEOUT0, NULL((void *)0)); |
702 | error = usbd_transfer(xfer); |
703 | if (error != 0 && error != USBD_IN_PROGRESS) { |
704 | printf("%s: transfer error\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
705 | goto err; |
706 | } |
707 | sent += sendlen; |
708 | |
709 | bwfm_usb_dl_cmd(sc, DL_GETSTATE0, &state, sizeof(state)); |
710 | rdlstate = letoh32(state.state)((__uint32_t)(state.state)); |
711 | rdlbytes = letoh32(state.bytes)((__uint32_t)(state.bytes)); |
712 | |
713 | if (rdlbytes != sent) { |
714 | printf("%s: device reported different size\n", |
715 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
716 | goto err; |
717 | } |
718 | |
719 | if (rdlstate == DL_BAD_HDR2 || rdlstate == DL_BAD_CRC3) { |
720 | printf("%s: device reported bad hdr/crc\n", |
721 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
722 | goto err; |
723 | } |
724 | } |
725 | |
726 | bwfm_usb_dl_cmd(sc, DL_GETSTATE0, &state, sizeof(state)); |
727 | rdlstate = letoh32(state.state)((__uint32_t)(state.state)); |
728 | rdlbytes = letoh32(state.bytes)((__uint32_t)(state.bytes)); |
Value stored to 'rdlbytes' is never read | |
729 | |
730 | if (rdlstate != DL_RUNNABLE4) { |
731 | printf("%s: dongle not runnable\n", DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname)); |
732 | goto err; |
733 | } |
734 | |
735 | bwfm_usb_dl_cmd(sc, DL_GO2, &state, sizeof(state)); |
736 | |
737 | return 0; |
738 | err: |
739 | if (sc->sc_tx_pipeh != NULL((void *)0)) { |
740 | usbd_close_pipe(sc->sc_tx_pipeh); |
741 | sc->sc_tx_pipeh = NULL((void *)0); |
742 | } |
743 | if (xfer != NULL((void *)0)) |
744 | usbd_free_xfer(xfer); |
745 | return 1; |
746 | } |
747 | |
748 | int |
749 | bwfm_usb_txcheck(struct bwfm_softc *bwfm) |
750 | { |
751 | struct bwfm_usb_softc *sc = (void *)bwfm; |
752 | |
753 | if (TAILQ_EMPTY(&sc->sc_tx_free_list)(((&sc->sc_tx_free_list)->tqh_first) == ((void *)0) )) |
754 | return ENOBUFS55; |
755 | |
756 | return 0; |
757 | } |
758 | |
759 | int |
760 | bwfm_usb_txdata(struct bwfm_softc *bwfm, struct mbuf *m) |
761 | { |
762 | struct bwfm_usb_softc *sc = (void *)bwfm; |
763 | struct bwfm_proto_bcdc_hdr *hdr; |
764 | struct bwfm_usb_tx_data *data; |
765 | uint32_t len = 0; |
766 | int error; |
767 | |
768 | DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__))do { ; } while (0); |
769 | |
770 | if (TAILQ_EMPTY(&sc->sc_tx_free_list)(((&sc->sc_tx_free_list)->tqh_first) == ((void *)0) )) |
771 | return ENOBUFS55; |
772 | |
773 | /* Grab a Tx buffer from our free list. */ |
774 | data = TAILQ_FIRST(&sc->sc_tx_free_list)((&sc->sc_tx_free_list)->tqh_first); |
775 | TAILQ_REMOVE(&sc->sc_tx_free_list, data, next)do { if (((data)->next.tqe_next) != ((void *)0)) (data)-> next.tqe_next->next.tqe_prev = (data)->next.tqe_prev; else (&sc->sc_tx_free_list)->tqh_last = (data)->next .tqe_prev; *(data)->next.tqe_prev = (data)->next.tqe_next ; ((data)->next.tqe_prev) = ((void *)-1); ((data)->next .tqe_next) = ((void *)-1); } while (0); |
776 | |
777 | hdr = (void *)&data->buf[len]; |
778 | hdr->data_offset = 0; |
779 | hdr->priority = ieee80211_classify(&sc->sc_sc.sc_ic, m); |
780 | hdr->flags = BWFM_BCDC_FLAG_VER(BWFM_BCDC_FLAG_PROTO_VER)(((2) & 0xf) << 4); |
781 | hdr->flags2 = 0; |
782 | len += sizeof(*hdr); |
783 | |
784 | m_copydata(m, 0, m->m_pkthdrM_dat.MH.MH_pkthdr.len, (caddr_t)&data->buf[len]); |
785 | len += m->m_pkthdrM_dat.MH.MH_pkthdr.len; |
786 | |
787 | data->mbuf = m; |
788 | |
789 | usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, |
790 | len, USBD_FORCE_SHORT_XFER0x08 | USBD_NO_COPY0x01, USBD_NO_TIMEOUT0, |
791 | bwfm_usb_txeof); |
792 | error = usbd_transfer(data->xfer); |
793 | if (error != 0 && error != USBD_IN_PROGRESS) |
794 | printf("%s: could not set up new transfer: %s\n", |
795 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), usbd_errstr(error)); |
796 | return 0; |
797 | } |
798 | |
799 | int |
800 | bwfm_usb_txctl(struct bwfm_softc *bwfm, void *arg) |
801 | { |
802 | struct bwfm_usb_softc *sc = (void *)bwfm; |
803 | struct bwfm_proto_bcdc_ctl *ctl = arg; |
804 | usb_device_request_t req; |
805 | struct usbd_xfer *xfer; |
806 | usbd_status error; |
807 | char *buf; |
808 | |
809 | DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__))do { ; } while (0); |
810 | |
811 | /* Send out control packet. */ |
812 | req.bmRequestType = UT_WRITE_CLASS_INTERFACE(0x00 | 0x20 | 0x01); |
813 | req.bRequest = 0; |
814 | USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0)); |
815 | USETW(req.wIndex, sc->sc_ifaceno)(*(u_int16_t *)(req.wIndex) = (sc->sc_ifaceno)); |
816 | USETW(req.wLength, ctl->len)(*(u_int16_t *)(req.wLength) = (ctl->len)); |
817 | |
818 | error = usbd_do_request(sc->sc_udev, &req, ctl->buf); |
819 | if (error != 0) { |
820 | printf("%s: could not write ctl packet: %s\n", |
821 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), usbd_errstr(error)); |
822 | free(ctl->buf, M_TEMP127, ctl->len); |
823 | free(ctl, M_TEMP127, sizeof(*ctl)); |
824 | return 1; |
825 | } |
826 | |
827 | /* Setup asynchronous receive. */ |
828 | if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL((void *)0)) { |
829 | free(ctl->buf, M_TEMP127, ctl->len); |
830 | free(ctl, M_TEMP127, sizeof(*ctl)); |
831 | return 1; |
832 | } |
833 | if ((buf = usbd_alloc_buffer(xfer, ctl->len)) == NULL((void *)0)) { |
834 | free(ctl->buf, M_TEMP127, ctl->len); |
835 | free(ctl, M_TEMP127, sizeof(*ctl)); |
836 | usbd_free_xfer(xfer); |
837 | return 1; |
838 | } |
839 | |
840 | memset(buf, 0, ctl->len)__builtin_memset((buf), (0), (ctl->len)); |
841 | req.bmRequestType = UT_READ_CLASS_INTERFACE(0x80 | 0x20 | 0x01); |
842 | req.bRequest = 1; |
843 | USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0)); |
844 | USETW(req.wIndex, sc->sc_ifaceno)(*(u_int16_t *)(req.wIndex) = (sc->sc_ifaceno)); |
845 | USETW(req.wLength, ctl->len)(*(u_int16_t *)(req.wLength) = (ctl->len)); |
846 | |
847 | error = usbd_request_async(xfer, &req, sc, bwfm_usb_txctl_cb); |
848 | if (error != 0) { |
849 | printf("%s: could not read ctl packet: %s\n", |
850 | DEVNAME(sc)((sc)->sc_sc.sc_dev.dv_xname), usbd_errstr(error)); |
851 | free(ctl->buf, M_TEMP127, ctl->len); |
852 | free(ctl, M_TEMP127, sizeof(*ctl)); |
853 | return 1; |
854 | } |
855 | |
856 | TAILQ_INSERT_TAIL(&sc->sc_sc.sc_bcdc_rxctlq, ctl, next)do { (ctl)->next.tqe_next = ((void *)0); (ctl)->next.tqe_prev = (&sc->sc_sc.sc_bcdc_rxctlq)->tqh_last; *(&sc ->sc_sc.sc_bcdc_rxctlq)->tqh_last = (ctl); (&sc-> sc_sc.sc_bcdc_rxctlq)->tqh_last = &(ctl)->next.tqe_next ; } while (0); |
857 | |
858 | return 0; |
859 | } |
860 | |
861 | void |
862 | bwfm_usb_txctl_cb(struct usbd_xfer *xfer, void *priv, usbd_status err) |
863 | { |
864 | struct bwfm_usb_softc *sc = priv; |
865 | |
866 | if (usbd_is_dying(xfer->pipe->device)) |
867 | goto err; |
868 | |
869 | if (err == USBD_NORMAL_COMPLETION || err == USBD_SHORT_XFER) { |
870 | sc->sc_sc.sc_proto_ops->proto_rxctl(&sc->sc_sc, |
871 | KERNADDR(&xfer->dmabuf, 0)((void *)((char *)((&xfer->dmabuf)->block->kaddr + (&xfer->dmabuf)->offs) + (0))), xfer->actlen); |
872 | } |
873 | |
874 | err: |
875 | usbd_free_xfer(xfer); |
876 | } |