Line data Source code
1 : /* $OpenBSD: if_wi_usb.c,v 1.68 2015/11/24 17:11:40 mpi Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2003 Dale Rahn. All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : * 1. Redistributions of source code must retain the above copyright
10 : * notice, this list of conditions and the following disclaimer.
11 : * 2. Redistributions in binary form must reproduce the above copyright
12 : * notice, this list of conditions and the following disclaimer in the
13 : * documentation and/or other materials provided with the distribution.
14 : *
15 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 : *
26 : * Effort sponsored in part by the Defense Advanced Research Projects
27 : * Agency (DARPA) and Air Force Research Laboratory, Air Force
28 : * Materiel Command, USAF, under agreement number F30602-01-2-0537.
29 : */
30 : #include "bpfilter.h"
31 :
32 : #include <sys/param.h>
33 : #include <sys/systm.h>
34 : #include <sys/sockio.h>
35 : #include <sys/mbuf.h>
36 : #include <sys/malloc.h>
37 : #include <sys/kernel.h>
38 : #include <sys/socket.h>
39 : #include <sys/device.h>
40 : #include <sys/timeout.h>
41 : #include <sys/kthread.h>
42 : #include <sys/tree.h>
43 :
44 : #include <net/if.h>
45 : #include <net/if_media.h>
46 :
47 : #include <netinet/in.h>
48 : #include <netinet/if_ether.h>
49 :
50 : #include <dev/usb/usb.h>
51 : #include <dev/usb/usbdi.h>
52 : #include <dev/usb/usbdi_util.h>
53 : #include <dev/usb/usbdevs.h>
54 :
55 : #define ROUNDUP64(x) (((x)+63) & ~63)
56 :
57 : #include <net80211/ieee80211_var.h>
58 : #include <net80211/ieee80211_ioctl.h>
59 :
60 : #if NBPFILTER > 0
61 : #include <net/bpf.h>
62 : #endif
63 :
64 : #include <machine/bus.h>
65 :
66 : #include <dev/ic/if_wireg.h>
67 : #include <dev/ic/if_wi_ieee.h>
68 : #include <dev/ic/if_wivar.h>
69 :
70 : #include <dev/usb/if_wi_usb.h>
71 :
72 : int wi_usb_do_transmit_sync(struct wi_usb_softc *wsc, struct wi_usb_chain *c,
73 : void *ident);
74 : void wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
75 : usbd_status status);
76 : void wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
77 : usbd_status status);
78 : void wi_usb_rxeof(struct usbd_xfer *xfer, void *priv,
79 : usbd_status status);
80 : void wi_usb_intr(struct usbd_xfer *xfer, void *priv,
81 : usbd_status status);
82 : void wi_usb_stop(struct wi_usb_softc *usc);
83 : int wi_usb_tx_list_init(struct wi_usb_softc *usc);
84 : int wi_usb_rx_list_init(struct wi_usb_softc *usc);
85 : int wi_usb_open_pipes(struct wi_usb_softc *usc);
86 : void wi_usb_cmdresp(struct wi_usb_chain *c);
87 : void wi_usb_rridresp(struct wi_usb_chain *c);
88 : void wi_usb_wridresp(struct wi_usb_chain *c);
89 : void wi_usb_infofrm(struct wi_usb_chain *c, int len);
90 : int wi_send_packet(struct wi_usb_softc *sc, int id);
91 : void wi_usb_rxfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
92 : void wi_usb_txfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
93 : void wi_usb_start_thread(void *);
94 :
95 : int wi_usb_tx_lock_try(struct wi_usb_softc *sc);
96 : void wi_usb_tx_lock(struct wi_usb_softc *usc);
97 : void wi_usb_tx_unlock(struct wi_usb_softc *usc);
98 : void wi_usb_ctl_lock(struct wi_usb_softc *usc);
99 : void wi_usb_ctl_unlock(struct wi_usb_softc *usc);
100 :
101 : void wi_dump_data(void *buffer, int len);
102 :
103 : void wi_usb_thread(void *arg);
104 :
105 : #ifdef WI_USB_DEBUG
106 : #define DPRINTF(x) do { if (wi_usbdebug) printf x; } while (0)
107 : #define DPRINTFN(n,x) do { if (wi_usbdebug >= (n)) printf x; } while (0)
108 : int wi_usbdebug = 1;
109 : #else
110 : #define DPRINTF(x)
111 : #define DPRINTFN(n,x)
112 : #endif
113 :
114 : struct wi_usb_thread_info {
115 : int status;
116 : int dying;
117 : int idle;
118 : };
119 :
120 : /* thread status flags */
121 : #define WI_START 0x01
122 : #define WI_DYING 0x02
123 : #define WI_INQUIRE 0x04
124 : #define WI_WATCHDOG 0x08
125 :
126 :
127 : struct wi_usb_softc {
128 : struct wi_softc sc_wi;
129 : #define wi_usb_dev sc_wi.sc_dev
130 :
131 : struct timeout wi_usb_stat_ch;
132 :
133 : struct usbd_device *wi_usb_udev;
134 : struct usbd_interface *wi_usb_iface;
135 : u_int16_t wi_usb_vendor;
136 : u_int16_t wi_usb_product;
137 : int wi_usb_ed[WI_USB_ENDPT_MAX];
138 : struct usbd_pipe *wi_usb_ep[WI_USB_ENDPT_MAX];
139 :
140 : struct wi_usb_chain wi_usb_tx_chain[WI_USB_TX_LIST_CNT];
141 : struct wi_usb_chain wi_usb_rx_chain[WI_USB_RX_LIST_CNT];
142 :
143 : int wi_usb_refcnt;
144 : char wi_usb_attached;
145 : int wi_usb_intr_errs;
146 : struct timeval wi_usb_rx_notice;
147 :
148 : int wi_usb_pollpending;
149 :
150 : wi_usb_usbin wi_usb_ibuf;
151 : int wi_usb_tx_prod;
152 : int wi_usb_tx_cons;
153 : int wi_usb_tx_cnt;
154 : int wi_usb_rx_prod;
155 :
156 : struct wi_ltv_gen *ridltv;
157 : int ridresperr;
158 :
159 : int cmdresp;
160 : int cmdresperr;
161 : int txresp;
162 : int txresperr;
163 :
164 : /* nummem (tx/mgmt) */
165 : int wi_usb_nummem;
166 : #define MAX_WI_NMEM 3
167 : void *wi_usb_txmem[MAX_WI_NMEM];
168 : int wi_usb_txmemsize[MAX_WI_NMEM];
169 : void *wi_usb_rxmem;
170 : int wi_usb_rxmemsize;
171 :
172 : void *wi_info;
173 : void *wi_rxframe;
174 :
175 : /* prevent multiple outstanding USB requests */
176 : int wi_lock;
177 : int wi_lockwait;
178 :
179 : /* prevent multiple command requests */
180 : int wi_ctllock;
181 : int wi_ctllockwait;
182 : struct proc *wi_curproc;
183 :
184 : /* kthread */
185 : struct wi_usb_thread_info *wi_thread_info;
186 : int wi_resetonce;
187 : };
188 :
189 : struct wi_funcs wi_func_usb = {
190 : wi_cmd_usb,
191 : wi_read_record_usb,
192 : wi_write_record_usb,
193 : wi_alloc_nicmem_usb,
194 : wi_read_data_usb,
195 : wi_write_data_usb,
196 : wi_get_fid_usb,
197 : wi_init_usb,
198 :
199 : wi_start_usb,
200 : wi_ioctl_usb,
201 : wi_watchdog_usb,
202 : wi_inquire_usb,
203 : };
204 :
205 : /*
206 : * Various supported device vendors/products.
207 : */
208 : const struct wi_usb_type {
209 : struct usb_devno wi_usb_device;
210 : u_int16_t wi_usb_flags;
211 : /* XXX */
212 : } wi_usb_devs[] = {
213 : {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_111 }, 0 },
214 : {{ USB_VENDOR_ACERW, USB_PRODUCT_ACERW_WARPLINK }, 0 },
215 : {{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_FREELAN }, 0 },
216 : {{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_PRISM_25 }, 0 },
217 : {{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_PRISM_25A }, 0 },
218 : {{ USB_VENDOR_ADAPTEC, USB_PRODUCT_ADAPTEC_AWN8020 }, 0 },
219 : {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_WLAN }, 0 },
220 : {{ USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUSTEK_WL140 }, 0 },
221 : {{ USB_VENDOR_AVERATEC, USB_PRODUCT_AVERATEC_USBWLAN }, 0 },
222 : {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_W100 }, 0 },
223 : {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_W200 }, 0 },
224 : {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLANUSB }, 0 },
225 : {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_KEY }, 0 },
226 : {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_TM1180 }, 0 },
227 : {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120F }, 0 },
228 : {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL122 }, 0 },
229 : {{ USB_VENDOR_INTEL, USB_PRODUCT_INTEL_I2011B }, 0 },
230 : {{ USB_VENDOR_INTERSIL, USB_PRODUCT_INTERSIL_PRISM_2X }, 0 },
231 : {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11 }, 0 },
232 : {{ USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_XP7250_WL }, 0 },
233 : {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11_25 }, 0 },
234 : {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB12_11 }, 0 },
235 : {{ USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V30 }, 0 },
236 : {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KB11 }, 0 },
237 : {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KS11G }, 0 },
238 : {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_S11 }, 0 },
239 : {{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN510 }, 0 },
240 : {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_MA111NA }, 0 },
241 : {{ USB_VENDOR_PHEENET, USB_PRODUCT_PHEENET_WL503IA }, 0 },
242 : {{ USB_VENDOR_PHEENET, USB_PRODUCT_PHEENET_WM168B }, 0 },
243 : {{ USB_VENDOR_PLANEX, USB_PRODUCT_PLANEX_GW_US11H }, 0 },
244 : {{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM22 }, 0 },
245 : {{ USB_VENDOR_SITECOM2, USB_PRODUCT_SITECOM2_WL022 }, 0 },
246 : {{ USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_0193 }, 0 },
247 : {{ USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZYAIR_B200 }, 0 },
248 : {{ USB_VENDOR_USR, USB_PRODUCT_USR_USR1120 }, 0 },
249 : {{ USB_VENDOR_VIEWSONIC, USB_PRODUCT_VIEWSONIC_AIRSYNC }, 0 },
250 : {{ USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_XI725 }, 0 },
251 : {{ USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_XI735 }, 0 }
252 : };
253 : #define wi_usb_lookup(v, p) ((struct wi_usb_type *)usb_lookup(wi_usb_devs, v, p))
254 :
255 : int wi_usb_match(struct device *, void *, void *);
256 : void wi_usb_attach(struct device *, struct device *, void *);
257 : int wi_usb_detach(struct device *, int);
258 :
259 : struct cfdriver wi_usb_cd = {
260 : NULL, "wi_usb", DV_IFNET
261 : };
262 :
263 : const struct cfattach wi_usb_ca = {
264 : sizeof(struct wi_usb_softc), wi_usb_match, wi_usb_attach, wi_usb_detach
265 : };
266 :
267 : int
268 0 : wi_usb_match(struct device *parent, void *match, void *aux)
269 : {
270 0 : struct usb_attach_arg *uaa = aux;
271 :
272 0 : if (uaa->iface == NULL || uaa->configno != 1)
273 0 : return (UMATCH_NONE);
274 :
275 0 : return (wi_usb_lookup(uaa->vendor, uaa->product) != NULL ?
276 : UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
277 0 : }
278 :
279 :
280 : /*
281 : * Attach the interface. Allocate softc structures, do ifmedia
282 : * setup and ethernet/BPF attach.
283 : */
284 : void
285 0 : wi_usb_attach(struct device *parent, struct device *self, void *aux)
286 : {
287 0 : struct wi_usb_softc *sc = (struct wi_usb_softc *)self;
288 0 : struct usb_attach_arg *uaa = aux;
289 : /* int s; */
290 0 : struct usbd_device *dev = uaa->device;
291 0 : struct usbd_interface *iface = uaa->iface;
292 : usb_interface_descriptor_t *id;
293 : usb_endpoint_descriptor_t *ed;
294 : int i;
295 :
296 : DPRINTFN(5,(" : wi_usb_attach: sc=%p", sc));
297 :
298 : /* XXX - any tasks? */
299 :
300 : /* XXX - flags? */
301 :
302 0 : sc->wi_usb_udev = dev;
303 0 : sc->wi_usb_iface = iface;
304 0 : sc->wi_usb_product = uaa->product;
305 0 : sc->wi_usb_vendor = uaa->vendor;
306 :
307 0 : sc->sc_wi.wi_usb_cdata = sc;
308 0 : sc->sc_wi.wi_flags |= WI_FLAGS_BUS_USB;
309 :
310 0 : sc->wi_lock = 0;
311 0 : sc->wi_lockwait = 0;
312 0 : sc->wi_resetonce = 0;
313 :
314 0 : id = usbd_get_interface_descriptor(iface);
315 :
316 : /* Find endpoints. */
317 0 : for (i = 0; i < id->bNumEndpoints; i++) {
318 0 : ed = usbd_interface2endpoint_descriptor(iface, i);
319 0 : if (ed == NULL) {
320 0 : printf("%s: couldn't get endpoint descriptor %d\n",
321 0 : sc->wi_usb_dev.dv_xname, i);
322 0 : return;
323 : }
324 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
325 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
326 0 : sc->wi_usb_ed[WI_USB_ENDPT_RX] = ed->bEndpointAddress;
327 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
328 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
329 0 : sc->wi_usb_ed[WI_USB_ENDPT_TX] = ed->bEndpointAddress;
330 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
331 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
332 0 : sc->wi_usb_ed[WI_USB_ENDPT_INTR] = ed->bEndpointAddress;
333 0 : }
334 : }
335 :
336 0 : sc->wi_usb_nummem = 0;
337 :
338 : /* attach wi device */
339 :
340 0 : if (wi_usb_rx_list_init(sc)) {
341 0 : printf("%s: rx list init failed\n",
342 0 : sc->wi_usb_dev.dv_xname);
343 0 : return;
344 : }
345 0 : if (wi_usb_tx_list_init(sc)) {
346 0 : printf("%s: tx list init failed\n",
347 0 : sc->wi_usb_dev.dv_xname);
348 0 : return;
349 : }
350 :
351 0 : if (wi_usb_open_pipes(sc)){
352 0 : printf("%s: open pipes failed\n",
353 0 : sc->wi_usb_dev.dv_xname);
354 0 : return;
355 : }
356 :
357 0 : sc->wi_usb_attached = 1;
358 :
359 0 : kthread_create_deferred(wi_usb_start_thread, sc);
360 0 : }
361 :
362 : int
363 0 : wi_usb_detach(struct device *self, int flags)
364 : {
365 0 : struct wi_usb_softc *sc = (struct wi_usb_softc *)self;
366 0 : struct ifnet *ifp = WI_GET_IFP(sc);
367 : struct wi_softc *wsc = &sc->sc_wi;
368 : int s;
369 : int err;
370 :
371 : /* Detached before attach finished, so just bail out. */
372 0 : if (!sc->wi_usb_attached)
373 0 : return (0);
374 :
375 0 : if (sc->wi_thread_info != NULL) {
376 0 : sc->wi_thread_info->dying = 1;
377 :
378 0 : sc->wi_thread_info->status |= WI_DYING;
379 0 : if (sc->wi_thread_info->idle)
380 0 : wakeup(sc->wi_thread_info);
381 : }
382 :
383 : /* tasks? */
384 :
385 0 : s = splusb();
386 : /* detach wi */
387 :
388 0 : if (!(wsc->wi_flags & WI_FLAGS_ATTACHED)) {
389 0 : printf("%s: already detached\n", sc->wi_usb_dev.dv_xname);
390 0 : splx(s);
391 0 : return (0);
392 : }
393 :
394 0 : wi_detach(&sc->sc_wi);
395 :
396 0 : wsc->wi_flags = 0;
397 :
398 0 : if (ifp->if_softc != NULL) {
399 0 : ether_ifdetach(ifp);
400 0 : if_detach(ifp);
401 0 : }
402 :
403 0 : sc->wi_usb_attached = 0;
404 :
405 0 : if (--sc->wi_usb_refcnt >= 0) {
406 : /* Wait for processes to go away. */
407 0 : usb_detach_wait(&sc->wi_usb_dev);
408 0 : }
409 :
410 0 : while (sc->wi_usb_nummem) {
411 0 : sc->wi_usb_nummem--;
412 0 : if (sc->wi_usb_txmem[sc->wi_usb_nummem] != NULL)
413 0 : free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_DEVBUF, 0);
414 0 : sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
415 : }
416 :
417 0 : if (sc->wi_usb_ep[WI_USB_ENDPT_INTR] != NULL) {
418 0 : usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]);
419 0 : err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]);
420 0 : if (err) {
421 0 : printf("%s: close intr pipe failed: %s\n",
422 0 : sc->wi_usb_dev.dv_xname, usbd_errstr(err));
423 0 : }
424 0 : sc->wi_usb_ep[WI_USB_ENDPT_INTR] = NULL;
425 0 : }
426 0 : if (sc->wi_usb_ep[WI_USB_ENDPT_TX] != NULL) {
427 0 : usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]);
428 0 : err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]);
429 0 : if (err) {
430 0 : printf("%s: close tx pipe failed: %s\n",
431 0 : sc->wi_usb_dev.dv_xname, usbd_errstr(err));
432 0 : }
433 0 : sc->wi_usb_ep[WI_USB_ENDPT_TX] = NULL;
434 0 : }
435 0 : if (sc->wi_usb_ep[WI_USB_ENDPT_RX] != NULL) {
436 0 : usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]);
437 0 : err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]);
438 0 : if (err) {
439 0 : printf("%s: close rx pipe failed: %s\n",
440 0 : sc->wi_usb_dev.dv_xname, usbd_errstr(err));
441 0 : }
442 0 : sc->wi_usb_ep[WI_USB_ENDPT_RX] = NULL;
443 0 : }
444 :
445 0 : splx(s);
446 :
447 0 : return (0);
448 0 : }
449 :
450 : int
451 0 : wi_send_packet(struct wi_usb_softc *sc, int id)
452 : {
453 : struct wi_usb_chain *c;
454 : struct wi_frame *wibuf;
455 : int total_len, rnd_len;
456 : int err;
457 :
458 0 : c = &sc->wi_usb_tx_chain[0];
459 :
460 : DPRINTFN(10,("%s: %s: id=%x\n",
461 : sc->wi_usb_dev.dv_xname, __func__, id));
462 :
463 : /* assemble packet from write_data buffer */
464 0 : if (id == 0 || id == 1) {
465 : /* tx_lock acquired before wi_start() */
466 0 : wibuf = sc->wi_usb_txmem[id];
467 :
468 0 : total_len = sizeof (struct wi_frame) +
469 0 : letoh16(wibuf->wi_dat_len);
470 0 : rnd_len = ROUNDUP64(total_len);
471 0 : if ((total_len > sc->wi_usb_txmemsize[id]) ||
472 0 : (rnd_len > WI_USB_BUFSZ )){
473 0 : printf("invalid packet len: %x memsz %x max %x\n",
474 : total_len, sc->wi_usb_txmemsize[id], WI_USB_BUFSZ);
475 :
476 : err = EIO;
477 0 : goto err_ret;
478 : }
479 :
480 0 : sc->txresp = WI_CMD_TX;
481 0 : sc->txresperr = 0;
482 :
483 0 : bcopy(wibuf, c->wi_usb_buf, total_len);
484 :
485 0 : bzero(((char *)c->wi_usb_buf)+total_len,
486 : rnd_len - total_len);
487 :
488 : /* zero old packet for next TX */
489 0 : bzero(wibuf, total_len);
490 :
491 : total_len = rnd_len;
492 :
493 : DPRINTFN(5,("%s: %s: id=%x len=%x\n",
494 : sc->wi_usb_dev.dv_xname, __func__, id, total_len));
495 :
496 0 : usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
497 0 : c, c->wi_usb_buf, rnd_len,
498 : USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
499 : WI_USB_TX_TIMEOUT, wi_usb_txeof_frm);
500 :
501 0 : err = usbd_transfer(c->wi_usb_xfer);
502 0 : if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
503 0 : printf("%s: %s: error=%s\n",
504 0 : sc->wi_usb_dev.dv_xname, __func__,
505 0 : usbd_errstr(err));
506 : /* Stop the interface from process context. */
507 0 : wi_usb_stop(sc);
508 : err = EIO;
509 0 : } else {
510 : err = 0;
511 : }
512 :
513 : DPRINTFN(5,("%s: %s: exit err=%x\n",
514 : sc->wi_usb_dev.dv_xname, __func__, err));
515 : err_ret:
516 0 : return err;
517 : }
518 0 : printf("%s:%s: invalid packet id sent %x\n",
519 0 : sc->wi_usb_dev.dv_xname, __func__, id);
520 0 : return 0;
521 0 : }
522 :
523 : int
524 0 : wi_cmd_usb(struct wi_softc *wsc, int cmd, int val0, int val1, int val2)
525 : {
526 : struct wi_usb_chain *c;
527 0 : struct wi_usb_softc *sc = wsc->wi_usb_cdata;
528 : struct wi_cmdreq *pcmd;
529 : int total_len, rnd_len;
530 : int err;
531 :
532 : DPRINTFN(5,("%s: %s: enter cmd=%x %x %x %x\n",
533 : sc->wi_usb_dev.dv_xname, __func__, cmd, val0, val1, val2));
534 :
535 0 : if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_TX) {
536 0 : return wi_send_packet(sc, val0);
537 : }
538 :
539 :
540 0 : if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_INI) {
541 : /* free alloc_nicmem regions */
542 0 : while (sc->wi_usb_nummem) {
543 0 : sc->wi_usb_nummem--;
544 0 : free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_DEVBUF, 0);
545 0 : sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
546 : }
547 :
548 : #if 0
549 : /* if this is the first time, init, otherwise do not?? */
550 : if (sc->wi_resetonce) {
551 : return 0;
552 : } else
553 : sc->wi_resetonce = 1;
554 : #endif
555 : }
556 :
557 0 : wi_usb_ctl_lock(sc);
558 :
559 0 : wi_usb_tx_lock(sc);
560 :
561 0 : c = &sc->wi_usb_tx_chain[0];
562 0 : pcmd = c->wi_usb_buf;
563 :
564 :
565 : total_len = sizeof (struct wi_cmdreq);
566 : rnd_len = ROUNDUP64(total_len);
567 0 : if (rnd_len > WI_USB_BUFSZ) {
568 0 : printf("read_record buf size err %x %x\n",
569 : rnd_len, WI_USB_BUFSZ);
570 : err = EIO;
571 0 : goto err_ret;
572 : }
573 :
574 0 : sc->cmdresp = cmd;
575 0 : sc->cmdresperr = 0;
576 :
577 0 : pcmd->type = htole16(WI_USB_CMDREQ);
578 0 : pcmd->cmd = htole16(cmd);
579 0 : pcmd->param0 = htole16(val0);
580 0 : pcmd->param1 = htole16(val1);
581 0 : pcmd->param2 = htole16(val2);
582 :
583 0 : bzero(((char*)pcmd)+total_len, rnd_len - total_len);
584 :
585 0 : usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
586 0 : c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
587 : WI_USB_TX_TIMEOUT, wi_usb_txeof);
588 :
589 0 : err = wi_usb_do_transmit_sync(sc, c, &sc->cmdresperr);
590 :
591 0 : if (err == 0)
592 0 : err = sc->cmdresperr;
593 :
594 0 : sc->cmdresperr = 0;
595 :
596 : err_ret:
597 0 : wi_usb_tx_unlock(sc);
598 :
599 0 : wi_usb_ctl_unlock(sc);
600 :
601 : DPRINTFN(5,("%s: %s: exit err=%x\n",
602 : sc->wi_usb_dev.dv_xname, __func__, err));
603 0 : return err;
604 0 : }
605 :
606 :
607 : int
608 0 : wi_read_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
609 : {
610 : struct wi_usb_chain *c;
611 0 : struct wi_usb_softc *sc = wsc->wi_usb_cdata;
612 : struct wi_rridreq *prid;
613 : int total_len, rnd_len;
614 : int err;
615 0 : struct wi_ltv_gen *oltv = NULL, p2ltv;
616 :
617 : DPRINTFN(5,("%s: %s: enter rid=%x\n",
618 : sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type));
619 :
620 : /* Do we need to deal with these here, as in _io version?
621 : * WI_RID_ENCRYPTION -> WI_RID_P2_ENCRYPTION
622 : * WI_RID_TX_CRYPT_KEY -> WI_RID_P2_TX_CRYPT_KEY
623 : */
624 0 : if (wsc->sc_firmware_type != WI_LUCENT) {
625 : oltv = ltv;
626 0 : switch (ltv->wi_type) {
627 : case WI_RID_ENCRYPTION:
628 0 : p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
629 0 : p2ltv.wi_len = 2;
630 : ltv = &p2ltv;
631 0 : break;
632 : case WI_RID_TX_CRYPT_KEY:
633 0 : if (ltv->wi_val > WI_NLTV_KEYS)
634 0 : return (EINVAL);
635 0 : p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
636 0 : p2ltv.wi_len = 2;
637 : ltv = &p2ltv;
638 0 : break;
639 : }
640 : }
641 :
642 0 : wi_usb_tx_lock(sc);
643 :
644 0 : c = &sc->wi_usb_tx_chain[0];
645 0 : prid = c->wi_usb_buf;
646 :
647 : total_len = sizeof(struct wi_rridreq);
648 : rnd_len = ROUNDUP64(total_len);
649 :
650 0 : if (rnd_len > WI_USB_BUFSZ) {
651 0 : printf("read_record buf size err %x %x\n",
652 : rnd_len, WI_USB_BUFSZ);
653 0 : wi_usb_tx_unlock(sc);
654 0 : return EIO;
655 : }
656 :
657 0 : sc->ridltv = ltv;
658 0 : sc->ridresperr = 0;
659 :
660 0 : prid->type = htole16(WI_USB_RRIDREQ);
661 0 : prid->frmlen = htole16(2); /* variable size? */
662 0 : prid->rid = htole16(ltv->wi_type);
663 :
664 0 : bzero(((char*)prid)+total_len, rnd_len - total_len);
665 :
666 0 : usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
667 0 : c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
668 : WI_USB_TX_TIMEOUT, wi_usb_txeof);
669 :
670 : DPRINTFN(10,("%s: %s: total_len=%x, wilen %d\n",
671 : sc->wi_usb_dev.dv_xname, __func__, total_len, ltv->wi_len));
672 :
673 0 : err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
674 :
675 : /* Do we need to deal with these here, as in _io version?
676 : *
677 : * WI_RID_TX_RATE
678 : * WI_RID_CUR_TX_RATE
679 : * WI_RID_ENCRYPTION
680 : * WI_RID_TX_CRYPT_KEY
681 : * WI_RID_CNFAUTHMODE
682 : */
683 0 : if (ltv->wi_type == WI_RID_PORTTYPE && wsc->wi_ptype == WI_PORTTYPE_IBSS
684 0 : && ltv->wi_val == wsc->wi_ibss_port) {
685 : /*
686 : * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
687 : * Since Lucent uses port type 1 for BSS *and* IBSS we
688 : * have to rely on wi_ptype to distinguish this for us.
689 : */
690 0 : ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
691 0 : } else if (wsc->sc_firmware_type != WI_LUCENT) {
692 : int v;
693 :
694 0 : switch (oltv->wi_type) {
695 : case WI_RID_TX_RATE:
696 : case WI_RID_CUR_TX_RATE:
697 0 : switch (letoh16(ltv->wi_val)) {
698 0 : case 1: v = 1; break;
699 0 : case 2: v = 2; break;
700 0 : case 3: v = 6; break;
701 0 : case 4: v = 5; break;
702 0 : case 7: v = 7; break;
703 0 : case 8: v = 11; break;
704 0 : case 15: v = 3; break;
705 0 : default: v = 0x100 + letoh16(ltv->wi_val); break;
706 : }
707 0 : oltv->wi_val = htole16(v);
708 0 : break;
709 : case WI_RID_ENCRYPTION:
710 0 : oltv->wi_len = 2;
711 0 : if (ltv->wi_val & htole16(0x01))
712 0 : oltv->wi_val = htole16(1);
713 : else
714 0 : oltv->wi_val = htole16(0);
715 : break;
716 : case WI_RID_TX_CRYPT_KEY:
717 : case WI_RID_CNFAUTHMODE:
718 0 : oltv->wi_len = 2;
719 0 : oltv->wi_val = ltv->wi_val;
720 0 : break;
721 : }
722 0 : }
723 :
724 0 : if (err == 0)
725 0 : err = sc->ridresperr;
726 :
727 0 : sc->ridresperr = 0;
728 :
729 0 : wi_usb_tx_unlock(sc);
730 :
731 : DPRINTFN(5,("%s: %s: exit err=%x\n",
732 : sc->wi_usb_dev.dv_xname, __func__, err));
733 0 : return err;
734 0 : }
735 :
736 : int
737 0 : wi_write_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
738 : {
739 : struct wi_usb_chain *c;
740 0 : struct wi_usb_softc *sc = wsc->wi_usb_cdata;
741 : struct wi_wridreq *prid;
742 : int total_len, rnd_len;
743 : int err;
744 0 : struct wi_ltv_gen p2ltv;
745 : u_int16_t val = 0;
746 : int i;
747 :
748 : DPRINTFN(5,("%s: %s: enter rid=%x wi_len %d copying %x\n",
749 : sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type, ltv->wi_len,
750 : (ltv->wi_len-1)*2 ));
751 :
752 : /* Do we need to deal with these here, as in _io version?
753 : * WI_PORTTYPE_IBSS -> WI_RID_PORTTYPE
754 : * RID_TX_RATE munging
755 : * RID_ENCRYPTION
756 : * WI_RID_TX_CRYPT_KEY
757 : * WI_RID_DEFLT_CRYPT_KEYS
758 : */
759 0 : if (ltv->wi_type == WI_RID_PORTTYPE &&
760 0 : letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
761 : /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
762 0 : p2ltv.wi_type = WI_RID_PORTTYPE;
763 0 : p2ltv.wi_len = 2;
764 0 : p2ltv.wi_val = wsc->wi_ibss_port;
765 : ltv = &p2ltv;
766 0 : } else if (wsc->sc_firmware_type != WI_LUCENT) {
767 : int v;
768 :
769 0 : switch (ltv->wi_type) {
770 : case WI_RID_TX_RATE:
771 0 : p2ltv.wi_type = WI_RID_TX_RATE;
772 0 : p2ltv.wi_len = 2;
773 0 : switch (letoh16(ltv->wi_val)) {
774 0 : case 1: v = 1; break;
775 0 : case 2: v = 2; break;
776 0 : case 3: v = 15; break;
777 0 : case 5: v = 4; break;
778 0 : case 6: v = 3; break;
779 0 : case 7: v = 7; break;
780 0 : case 11: v = 8; break;
781 0 : default: return EINVAL;
782 : }
783 0 : p2ltv.wi_val = htole16(v);
784 : ltv = &p2ltv;
785 0 : break;
786 : case WI_RID_ENCRYPTION:
787 0 : p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
788 0 : p2ltv.wi_len = 2;
789 0 : if (ltv->wi_val & htole16(0x01)) {
790 : val = PRIVACY_INVOKED;
791 : /*
792 : * If using shared key WEP we must set the
793 : * EXCLUDE_UNENCRYPTED bit. Symbol cards
794 : * need this bit set even when not using
795 : * shared key. We can't just test for
796 : * IEEE80211_AUTH_SHARED since Symbol cards
797 : * have 2 shared key modes.
798 : */
799 0 : if (wsc->wi_authtype != IEEE80211_AUTH_OPEN ||
800 0 : wsc->sc_firmware_type == WI_SYMBOL)
801 0 : val |= EXCLUDE_UNENCRYPTED;
802 :
803 0 : switch (wsc->wi_crypto_algorithm) {
804 : case WI_CRYPTO_FIRMWARE_WEP:
805 : /*
806 : * TX encryption is broken in
807 : * Host AP mode.
808 : */
809 0 : if (wsc->wi_ptype == WI_PORTTYPE_HOSTAP)
810 0 : val |= HOST_ENCRYPT;
811 : break;
812 : case WI_CRYPTO_SOFTWARE_WEP:
813 0 : val |= HOST_ENCRYPT|HOST_DECRYPT;
814 0 : break;
815 : }
816 0 : p2ltv.wi_val = htole16(val);
817 0 : } else
818 0 : p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
819 : ltv = &p2ltv;
820 0 : break;
821 : case WI_RID_TX_CRYPT_KEY:
822 0 : if (ltv->wi_val > WI_NLTV_KEYS)
823 0 : return (EINVAL);
824 0 : p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
825 0 : p2ltv.wi_len = 2;
826 0 : p2ltv.wi_val = ltv->wi_val;
827 : ltv = &p2ltv;
828 0 : break;
829 : case WI_RID_DEFLT_CRYPT_KEYS: {
830 : int error;
831 : int keylen;
832 0 : struct wi_ltv_str ws;
833 : struct wi_ltv_keys *wk;
834 :
835 0 : wk = (struct wi_ltv_keys *)ltv;
836 0 : keylen = wk->wi_keys[wsc->wi_tx_key].wi_keylen;
837 : keylen = letoh16(keylen);
838 :
839 0 : for (i = 0; i < 4; i++) {
840 0 : bzero(&ws, sizeof(ws));
841 0 : ws.wi_len = (keylen > 5) ? 8 : 4;
842 0 : ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
843 0 : bcopy(&wk->wi_keys[i].wi_keydat,
844 0 : ws.wi_str, keylen);
845 0 : error = wi_write_record_usb(wsc,
846 0 : (struct wi_ltv_gen *)&ws);
847 0 : if (error)
848 0 : return (error);
849 : }
850 0 : }
851 0 : return (0);
852 : }
853 0 : }
854 :
855 0 : wi_usb_tx_lock(sc);
856 :
857 0 : c = &sc->wi_usb_tx_chain[0];
858 :
859 0 : prid = c->wi_usb_buf;
860 :
861 0 : total_len = sizeof(prid->type) + sizeof(prid->frmlen) +
862 0 : sizeof(prid->rid) + (ltv->wi_len-1)*2;
863 0 : rnd_len = ROUNDUP64(total_len);
864 0 : if (rnd_len > WI_USB_BUFSZ) {
865 0 : printf("write_record buf size err %x %x\n",
866 : rnd_len, WI_USB_BUFSZ);
867 0 : wi_usb_tx_unlock(sc);
868 0 : return EIO;
869 : }
870 :
871 0 : prid->type = htole16(WI_USB_WRIDREQ);
872 0 : prid->frmlen = htole16(ltv->wi_len);
873 0 : prid->rid = htole16(ltv->wi_type);
874 0 : if (ltv->wi_len > 1)
875 0 : bcopy(<v->wi_val, &prid->data[0], (ltv->wi_len-1)*2);
876 :
877 0 : bzero(((char*)prid)+total_len, rnd_len - total_len);
878 :
879 0 : usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
880 0 : c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
881 : WI_USB_TX_TIMEOUT, wi_usb_txeof);
882 :
883 0 : err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
884 :
885 0 : if (err == 0)
886 0 : err = sc->ridresperr;
887 :
888 0 : sc->ridresperr = 0;
889 :
890 0 : wi_usb_tx_unlock(sc);
891 :
892 : DPRINTFN(5,("%s: %s: exit err=%x\n",
893 : sc->wi_usb_dev.dv_xname, __func__, err));
894 0 : return err;
895 0 : }
896 :
897 : /*
898 : * This is an ugly compat portion to emulate the I/O which writes
899 : * a packet or management information
900 : * The data is copied into local memory for the requested
901 : * 'id' then on the wi_cmd WI_CMD_TX, the id argument
902 : * will identify which buffer to use
903 : */
904 : int
905 0 : wi_alloc_nicmem_usb(struct wi_softc *wsc, int len, int *id)
906 : {
907 : int nmem;
908 0 : struct wi_usb_softc *sc = wsc->wi_usb_cdata;
909 :
910 : DPRINTFN(10,("%s: %s: enter len=%x\n",
911 : sc->wi_usb_dev.dv_xname, __func__, len));
912 :
913 : /*
914 : * NOTE THIS IS A USB DEVICE WHICH WILL LIKELY HAVE MANY
915 : * CONNECTS/DISCONNECTS, FREE THIS MEMORY XXX XXX XXX !!! !!!
916 : */
917 0 : nmem = sc->wi_usb_nummem++;
918 :
919 0 : if (nmem >= MAX_WI_NMEM) {
920 0 : sc->wi_usb_nummem--;
921 0 : return ENOMEM;
922 : }
923 :
924 0 : sc->wi_usb_txmem[nmem] = malloc(len, M_DEVBUF, M_WAITOK | M_CANFAIL);
925 0 : if (sc->wi_usb_txmem[nmem] == NULL) {
926 0 : sc->wi_usb_nummem--;
927 0 : return ENOMEM;
928 : }
929 0 : sc->wi_usb_txmemsize[nmem] = len;
930 :
931 0 : *id = nmem;
932 0 : return 0;
933 0 : }
934 :
935 : /*
936 : * this is crazy, we skip the first 16 bits of the buf so that it
937 : * can be used as the 'type' of the usb transfer.
938 : */
939 :
940 :
941 : int
942 0 : wi_write_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
943 : {
944 : u_int8_t *ptr;
945 0 : struct wi_usb_softc *sc = wsc->wi_usb_cdata;
946 :
947 : DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
948 : sc->wi_usb_dev.dv_xname, __func__, id, off, len));
949 :
950 0 : if (id < 0 && id >= sc->wi_usb_nummem)
951 0 : return EIO;
952 :
953 0 : ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
954 :
955 0 : if (len + off > sc->wi_usb_txmemsize[id])
956 0 : return EIO;
957 : DPRINTFN(10,("%s: %s: completed \n",
958 : sc->wi_usb_dev.dv_xname, __func__));
959 :
960 0 : bcopy(buf, ptr, len);
961 0 : return 0;
962 0 : }
963 :
964 : /*
965 : * On the prism I/O, this read_data points to the hardware buffer
966 : * which contains the
967 : */
968 : int
969 0 : wi_read_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
970 : {
971 : u_int8_t *ptr;
972 0 : struct wi_usb_softc *sc = wsc->wi_usb_cdata;
973 :
974 : DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
975 : sc->wi_usb_dev.dv_xname, __func__, id, off, len));
976 :
977 0 : if (id == 0x1001 && sc->wi_info != NULL)
978 0 : ptr = (u_int8_t *)sc->wi_info + off;
979 0 : else if (id == 0x1000 && sc->wi_rxframe != NULL)
980 0 : ptr = (u_int8_t *)sc->wi_rxframe + off;
981 0 : else if (id >= 0 && id < sc->wi_usb_nummem) {
982 :
983 0 : if (sc->wi_usb_txmem[id] == NULL)
984 0 : return EIO;
985 0 : if (len + off > sc->wi_usb_txmemsize[id])
986 0 : return EIO;
987 :
988 0 : ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
989 : } else
990 0 : return EIO;
991 :
992 0 : if (id < sc->wi_usb_nummem) {
993 0 : ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
994 :
995 0 : if (len + off > sc->wi_usb_txmemsize[id])
996 0 : return EIO;
997 : }
998 :
999 0 : bcopy(ptr, buf, len);
1000 0 : return 0;
1001 0 : }
1002 :
1003 : void
1004 0 : wi_usb_stop(struct wi_usb_softc *sc)
1005 : {
1006 : DPRINTFN(1,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
1007 : /* XXX */
1008 :
1009 : /* Stop transfers */
1010 0 : }
1011 :
1012 : int
1013 0 : wi_usb_do_transmit_sync(struct wi_usb_softc *sc, struct wi_usb_chain *c,
1014 : void *ident)
1015 : {
1016 : usbd_status err;
1017 :
1018 : DPRINTFN(10,("%s: %s:\n",
1019 : sc->wi_usb_dev.dv_xname, __func__));
1020 :
1021 0 : sc->wi_usb_refcnt++;
1022 0 : err = usbd_transfer(c->wi_usb_xfer);
1023 0 : if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
1024 0 : printf("%s: %s error=%s\n",
1025 0 : sc->wi_usb_dev.dv_xname, __func__,
1026 0 : usbd_errstr(err));
1027 : /* Stop the interface from process context. */
1028 0 : wi_usb_stop(sc);
1029 : err = EIO;
1030 0 : goto done;
1031 : }
1032 0 : err = tsleep(ident, PRIBIO, "wiTXsync", hz*1);
1033 0 : if (err) {
1034 : DPRINTFN(1,("%s: %s: err %x\n",
1035 : sc->wi_usb_dev.dv_xname, __func__, err));
1036 : err = ETIMEDOUT;
1037 : }
1038 : done:
1039 0 : if (--sc->wi_usb_refcnt < 0)
1040 0 : usb_detach_wakeup(&sc->wi_usb_dev);
1041 0 : return err;
1042 : }
1043 :
1044 :
1045 : /*
1046 : * A command/rrid/wrid was sent to the chip. It's safe for us to clean up
1047 : * the list buffers.
1048 : */
1049 :
1050 : void
1051 0 : wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
1052 : usbd_status status)
1053 : {
1054 0 : struct wi_usb_chain *c = priv;
1055 0 : struct wi_usb_softc *sc = c->wi_usb_sc;
1056 :
1057 : int s;
1058 :
1059 0 : if (usbd_is_dying(sc->wi_usb_udev))
1060 0 : return;
1061 :
1062 0 : s = splnet();
1063 :
1064 : DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1065 : __func__, status));
1066 :
1067 0 : if (status != USBD_NORMAL_COMPLETION) {
1068 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1069 0 : splx(s);
1070 0 : return;
1071 : }
1072 0 : printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
1073 0 : usbd_errstr(status));
1074 0 : if (status == USBD_STALLED) {
1075 0 : sc->wi_usb_refcnt++;
1076 0 : usbd_clear_endpoint_stall_async(
1077 0 : sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1078 0 : if (--sc->wi_usb_refcnt < 0)
1079 0 : usb_detach_wakeup(&sc->wi_usb_dev);
1080 : }
1081 0 : splx(s);
1082 0 : return;
1083 : }
1084 :
1085 0 : splx(s);
1086 0 : }
1087 :
1088 : /*
1089 : * A packet was sent to the chip. It's safe for us to clean up
1090 : * the list buffers.
1091 : */
1092 :
1093 : void
1094 0 : wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
1095 : usbd_status status)
1096 : {
1097 0 : struct wi_usb_chain *c = priv;
1098 0 : struct wi_usb_softc *sc = c->wi_usb_sc;
1099 0 : struct wi_softc *wsc = &sc->sc_wi;
1100 0 : struct ifnet *ifp = &wsc->sc_ic.ic_if;
1101 :
1102 : int s;
1103 : int err = 0;
1104 :
1105 0 : if (usbd_is_dying(sc->wi_usb_udev))
1106 0 : return;
1107 :
1108 0 : s = splnet();
1109 :
1110 : DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1111 : __func__, status));
1112 :
1113 0 : if (status != USBD_NORMAL_COMPLETION) {
1114 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1115 0 : splx(s);
1116 0 : return;
1117 : }
1118 0 : printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
1119 0 : usbd_errstr(status));
1120 0 : if (status == USBD_STALLED) {
1121 0 : sc->wi_usb_refcnt++;
1122 0 : usbd_clear_endpoint_stall_async(
1123 0 : sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1124 0 : if (--sc->wi_usb_refcnt < 0)
1125 0 : usb_detach_wakeup(&sc->wi_usb_dev);
1126 : }
1127 0 : splx(s);
1128 0 : return;
1129 : }
1130 :
1131 0 : if (status)
1132 0 : err = WI_EV_TX_EXC;
1133 :
1134 0 : wi_txeof(wsc, err);
1135 :
1136 0 : wi_usb_tx_unlock(sc);
1137 :
1138 0 : if (!IFQ_IS_EMPTY(&ifp->if_snd))
1139 0 : wi_start_usb(ifp);
1140 :
1141 0 : splx(s);
1142 0 : }
1143 :
1144 : int
1145 0 : wi_usb_rx_list_init(struct wi_usb_softc *sc)
1146 : {
1147 : struct wi_usb_chain *c;
1148 : int i;
1149 :
1150 : DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1151 :
1152 0 : for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
1153 0 : c = &sc->wi_usb_rx_chain[i];
1154 0 : c->wi_usb_sc = sc;
1155 0 : c->wi_usb_idx = i;
1156 0 : if (c->wi_usb_xfer != NULL) {
1157 0 : printf("UGH RX\n");
1158 0 : }
1159 0 : if (c->wi_usb_xfer == NULL) {
1160 0 : c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
1161 0 : if (c->wi_usb_xfer == NULL)
1162 0 : return (ENOBUFS);
1163 0 : c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
1164 : WI_USB_BUFSZ);
1165 0 : if (c->wi_usb_buf == NULL)
1166 0 : return (ENOBUFS); /* XXX free xfer */
1167 : }
1168 : }
1169 :
1170 0 : return (0);
1171 0 : }
1172 :
1173 : int
1174 0 : wi_usb_tx_list_init(struct wi_usb_softc *sc)
1175 : {
1176 : struct wi_usb_chain *c;
1177 : int i;
1178 :
1179 : DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1180 :
1181 0 : for (i = 0; i < WI_USB_TX_LIST_CNT; i++) {
1182 0 : c = &sc->wi_usb_tx_chain[i];
1183 0 : c->wi_usb_sc = sc;
1184 0 : c->wi_usb_idx = i;
1185 0 : c->wi_usb_mbuf = NULL;
1186 0 : if (c->wi_usb_xfer != NULL) {
1187 0 : printf("UGH TX\n");
1188 0 : }
1189 0 : if (c->wi_usb_xfer == NULL) {
1190 0 : c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
1191 0 : if (c->wi_usb_xfer == NULL)
1192 0 : return (ENOBUFS);
1193 0 : c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
1194 : WI_USB_BUFSZ);
1195 0 : if (c->wi_usb_buf == NULL)
1196 0 : return (ENOBUFS);
1197 : }
1198 : }
1199 :
1200 0 : return (0);
1201 0 : }
1202 :
1203 : int
1204 0 : wi_usb_open_pipes(struct wi_usb_softc *sc)
1205 : {
1206 : usbd_status err;
1207 : int error = 0;
1208 : struct wi_usb_chain *c;
1209 : int i;
1210 :
1211 : DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
1212 :
1213 0 : sc->wi_usb_refcnt++;
1214 :
1215 : /* Open RX and TX pipes. */
1216 0 : err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_RX],
1217 0 : USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1218 0 : if (err) {
1219 0 : printf("%s: open rx pipe failed: %s\n",
1220 0 : sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1221 : error = EIO;
1222 0 : goto done;
1223 : }
1224 :
1225 0 : err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_TX],
1226 0 : USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1227 0 : if (err) {
1228 0 : printf("%s: open tx pipe failed: %s\n",
1229 0 : sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1230 : error = EIO;
1231 0 : goto done;
1232 : }
1233 :
1234 : /* is this used? */
1235 0 : err = usbd_open_pipe_intr(sc->wi_usb_iface,
1236 0 : sc->wi_usb_ed[WI_USB_ENDPT_INTR], USBD_EXCLUSIVE_USE,
1237 0 : &sc->wi_usb_ep[WI_USB_ENDPT_INTR], sc, &sc->wi_usb_ibuf,
1238 : WI_USB_INTR_PKTLEN, wi_usb_intr, WI_USB_INTR_INTERVAL);
1239 0 : if (err) {
1240 0 : printf("%s: open intr pipe failed: %s\n",
1241 0 : sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1242 : error = EIO;
1243 0 : goto done;
1244 : }
1245 :
1246 : /* Start up the receive pipe. */
1247 0 : for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
1248 0 : c = &sc->wi_usb_rx_chain[i];
1249 0 : usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
1250 0 : c, c->wi_usb_buf, WI_USB_BUFSZ,
1251 : USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1252 : wi_usb_rxeof);
1253 : DPRINTFN(10,("%s: %s: start read\n", sc->wi_usb_dev.dv_xname,
1254 : __func__));
1255 0 : usbd_transfer(c->wi_usb_xfer);
1256 : }
1257 :
1258 : done:
1259 0 : if (--sc->wi_usb_refcnt < 0)
1260 0 : usb_detach_wakeup(&sc->wi_usb_dev);
1261 :
1262 0 : return (error);
1263 : }
1264 :
1265 : /*
1266 : * This is a bit of a kludge, however wi_rxeof and wi_update_stats
1267 : * call wi_get_fid to determine where the data associated with
1268 : * the transaction is located, the returned id is then used to
1269 : * wi_read_data the information out.
1270 : *
1271 : * This code returns which 'fid' should be used. The results are only valid
1272 : * during a wi_usb_rxeof because the data is received packet is 'held'
1273 : * an a variable for reading by wi_read_data_usb for that period.
1274 : *
1275 : * for magic numbers this uses 0x1000, 0x1001 for rx/info
1276 : */
1277 :
1278 : int
1279 0 : wi_get_fid_usb(struct wi_softc *sc, int fid)
1280 : {
1281 0 : switch (fid) {
1282 : case WI_RX_FID:
1283 0 : return 0x1000;
1284 : case WI_INFO_FID:
1285 0 : return 0x1001;
1286 : default:
1287 0 : return 0x1111;
1288 : }
1289 :
1290 0 : }
1291 :
1292 : #if 0
1293 : void
1294 : wi_dump_data(void *buffer, int len)
1295 : {
1296 : int i;
1297 : for (i = 0; i < len; i++) {
1298 : if (((i) % 16) == 0)
1299 : printf("\n %02x:", i);
1300 : printf(" %02x",
1301 : ((uint8_t *)(buffer))[i]);
1302 :
1303 : }
1304 : printf("\n");
1305 :
1306 : }
1307 : #endif
1308 :
1309 : /*
1310 : * A frame has been received.
1311 : */
1312 : void
1313 0 : wi_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
1314 : {
1315 0 : struct wi_usb_chain *c = priv;
1316 0 : struct wi_usb_softc *sc = c->wi_usb_sc;
1317 : wi_usb_usbin *uin;
1318 0 : int total_len = 0;
1319 : u_int16_t rtype;
1320 :
1321 0 : if (usbd_is_dying(sc->wi_usb_udev))
1322 0 : return;
1323 :
1324 : DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1325 : __func__, status));
1326 :
1327 :
1328 0 : if (status != USBD_NORMAL_COMPLETION) {
1329 0 : if (status == USBD_NOT_STARTED || status == USBD_IOERROR
1330 0 : || status == USBD_CANCELLED) {
1331 0 : printf("%s: %u usb errors on rx: %s\n",
1332 0 : sc->wi_usb_dev.dv_xname, 1,
1333 : /* sc->wi_usb_rx_errs, */
1334 0 : usbd_errstr(status));
1335 0 : return;
1336 : }
1337 : #if 0
1338 : sc->wi_usb_rx_errs++;
1339 : if (usbd_ratecheck(&sc->wi_usb_rx_notice)) {
1340 : printf("%s: %u usb errors on rx: %s\n",
1341 : sc->wi_usb_dev.dv_xname, sc->wi_usb_rx_errs,
1342 : usbd_errstr(status));
1343 : sc->wi_usb_rx_errs = 0;
1344 : }
1345 : #endif
1346 0 : if (status == USBD_STALLED) {
1347 0 : sc->wi_usb_refcnt++;
1348 0 : usbd_clear_endpoint_stall_async(
1349 0 : sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1350 0 : if (--sc->wi_usb_refcnt < 0)
1351 0 : usb_detach_wakeup(&sc->wi_usb_dev);
1352 : }
1353 : goto done;
1354 : }
1355 :
1356 0 : usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
1357 :
1358 0 : if (total_len < 6) /* short XXX */
1359 : goto done;
1360 :
1361 0 : uin = (wi_usb_usbin *)(c->wi_usb_buf);
1362 :
1363 0 : rtype = letoh16(uin->type);
1364 :
1365 :
1366 : #if 0
1367 : wi_dump_data(c->wi_usb_buf, total_len);
1368 : #endif
1369 :
1370 0 : if (WI_USB_ISRXFRM(rtype)) {
1371 0 : wi_usb_rxfrm(sc, uin, total_len);
1372 0 : goto done;
1373 : }
1374 0 : if (WI_USB_ISTXFRM(rtype)) {
1375 : DPRINTFN(2,("%s: %s: txfrm type %x\n",
1376 : sc->wi_usb_dev.dv_xname, __func__, rtype));
1377 0 : wi_usb_txfrm(sc, uin, total_len);
1378 0 : goto done;
1379 : }
1380 :
1381 0 : switch (rtype) {
1382 : case WI_USB_INFOFRM:
1383 : /* info packet, INFO_FID hmm */
1384 : DPRINTFN(10,("%s: %s: infofrm type %x\n",
1385 : sc->wi_usb_dev.dv_xname, __func__, rtype));
1386 0 : wi_usb_infofrm(c, total_len);
1387 0 : break;
1388 : case WI_USB_CMDRESP:
1389 0 : wi_usb_cmdresp(c);
1390 0 : break;
1391 : case WI_USB_WRIDRESP:
1392 0 : wi_usb_wridresp(c);
1393 0 : break;
1394 : case WI_USB_RRIDRESP:
1395 0 : wi_usb_rridresp(c);
1396 0 : break;
1397 : case WI_USB_WMEMRESP:
1398 : /* Not currently used */
1399 : DPRINTFN(2,("%s: %s: wmemresp type %x\n",
1400 : sc->wi_usb_dev.dv_xname, __func__, rtype));
1401 : break;
1402 : case WI_USB_RMEMRESP:
1403 : /* Not currently used */
1404 : DPRINTFN(2,("%s: %s: rmemresp type %x\n",
1405 : sc->wi_usb_dev.dv_xname, __func__, rtype));
1406 : break;
1407 : case WI_USB_BUFAVAIL:
1408 0 : printf("wi_usb: received USB_BUFAVAIL packet\n"); /* XXX */
1409 0 : break;
1410 : case WI_USB_ERROR:
1411 0 : printf("wi_usb: received USB_ERROR packet\n"); /* XXX */
1412 0 : break;
1413 : #if 0
1414 : default:
1415 : printf("wi_usb: received Unknown packet 0x%x len %x\n",
1416 : rtype, total_len);
1417 : wi_dump_data(c->wi_usb_buf, total_len);
1418 : #endif
1419 : }
1420 :
1421 : done:
1422 : /* Setup new transfer. */
1423 0 : usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
1424 0 : c, c->wi_usb_buf, WI_USB_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
1425 : USBD_NO_TIMEOUT, wi_usb_rxeof);
1426 0 : sc->wi_usb_refcnt++;
1427 0 : usbd_transfer(c->wi_usb_xfer);
1428 0 : if (--sc->wi_usb_refcnt < 0)
1429 0 : usb_detach_wakeup(&sc->wi_usb_dev);
1430 :
1431 : DPRINTFN(10,("%s: %s: start rx\n", sc->wi_usb_dev.dv_xname,
1432 : __func__));
1433 0 : }
1434 :
1435 : void
1436 0 : wi_usb_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
1437 : {
1438 0 : struct wi_usb_softc *sc = priv;
1439 :
1440 : DPRINTFN(2,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1441 :
1442 0 : if (usbd_is_dying(sc->wi_usb_udev))
1443 0 : return;
1444 :
1445 0 : if (status != USBD_NORMAL_COMPLETION) {
1446 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1447 0 : return;
1448 :
1449 0 : if (status == USBD_STALLED) {
1450 0 : sc->wi_usb_refcnt++;
1451 0 : usbd_clear_endpoint_stall_async(
1452 0 : sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1453 0 : if (--sc->wi_usb_refcnt < 0)
1454 0 : usb_detach_wakeup(&sc->wi_usb_dev);
1455 : }
1456 0 : return;
1457 : }
1458 : /* XXX oerrors or collisions? */
1459 0 : }
1460 : void
1461 0 : wi_usb_cmdresp(struct wi_usb_chain *c)
1462 : {
1463 0 : struct wi_cmdresp *presp = (struct wi_cmdresp *)(c->wi_usb_buf);
1464 0 : u_int16_t status = letoh16(presp->status);
1465 0 : struct wi_usb_softc *sc = c->wi_usb_sc;
1466 : uint16_t type;
1467 : uint16_t cmdresperr;
1468 :
1469 0 : type = htole16(presp->type);
1470 0 : cmdresperr = letoh16(presp->resp0);
1471 : DPRINTFN(10,("%s: %s: enter type=%x, status=%x, cmdresp=%x, "
1472 : "resp=%x,%x,%x\n",
1473 : sc->wi_usb_dev.dv_xname, __func__, type, status, sc->cmdresp,
1474 : cmdresperr, letoh16(presp->resp1),
1475 : letoh16(presp->resp2)));
1476 :
1477 : /* XXX */
1478 0 : if (sc->cmdresp != (status & WI_STAT_CMD_CODE)) {
1479 : DPRINTFN(1,("%s: cmd ty %x st %x cmd %x failed %x\n",
1480 : sc->wi_usb_dev.dv_xname,
1481 : type, status, sc->cmdresp, cmdresperr));
1482 0 : return;
1483 : }
1484 :
1485 0 : sc->cmdresperr = (status & WI_STAT_CMD_RESULT) >> 8;
1486 :
1487 0 : sc->cmdresp = 0; /* good value for idle == INI ?? XXX */
1488 :
1489 0 : wakeup(&sc->cmdresperr);
1490 0 : }
1491 : void
1492 0 : wi_usb_rridresp(struct wi_usb_chain *c)
1493 : {
1494 0 : struct wi_rridresp *presp = (struct wi_rridresp *)(c->wi_usb_buf);
1495 0 : u_int16_t frmlen = letoh16(presp->frmlen);
1496 0 : struct wi_usb_softc *sc = c->wi_usb_sc;
1497 : struct wi_ltv_gen *ltv;
1498 : uint16_t rid;
1499 :
1500 0 : rid = letoh16(presp->rid);
1501 0 : ltv = sc->ridltv;
1502 :
1503 0 : if (ltv == 0) {
1504 : DPRINTFN(5,("%s: %s: enter ltv = 0 rid=%x len %d\n",
1505 : sc->wi_usb_dev.dv_xname, __func__, rid,
1506 : frmlen));
1507 0 : return;
1508 : }
1509 :
1510 : DPRINTFN(5,("%s: %s: enter rid=%x expecting %x len %d exptlen %d\n",
1511 : sc->wi_usb_dev.dv_xname, __func__, rid, ltv->wi_type,
1512 : frmlen, ltv->wi_len));
1513 :
1514 0 : rid = letoh16(presp->rid);
1515 :
1516 0 : if (rid != ltv->wi_type) {
1517 0 : sc->ridresperr = EIO;
1518 0 : return;
1519 : }
1520 :
1521 0 : if (frmlen > ltv->wi_len) {
1522 0 : sc->ridresperr = ENOSPC;
1523 0 : sc->ridltv = 0;
1524 0 : wakeup(&sc->ridresperr);
1525 0 : return;
1526 : }
1527 :
1528 0 : ltv->wi_len = frmlen;
1529 :
1530 : DPRINTFN(10,("%s: %s: copying %d frmlen %d\n",
1531 : sc->wi_usb_dev.dv_xname, __func__, (ltv->wi_len-1)*2,
1532 : frmlen));
1533 :
1534 0 : if (ltv->wi_len > 1)
1535 0 : bcopy(&presp->data[0], <v->wi_val,
1536 0 : (ltv->wi_len-1)*2);
1537 :
1538 0 : sc->ridresperr = 0;
1539 0 : sc->ridltv = 0;
1540 0 : wakeup(&sc->ridresperr);
1541 :
1542 0 : }
1543 :
1544 : void
1545 0 : wi_usb_wridresp(struct wi_usb_chain *c)
1546 : {
1547 0 : struct wi_wridresp *presp = (struct wi_wridresp *)(c->wi_usb_buf);
1548 0 : struct wi_usb_softc *sc = c->wi_usb_sc;
1549 : uint16_t status;
1550 :
1551 0 : status = letoh16(presp->status);
1552 :
1553 : DPRINTFN(10,("%s: %s: enter status=%x\n",
1554 : sc->wi_usb_dev.dv_xname, __func__, status));
1555 :
1556 0 : sc->ridresperr = (status & WI_STAT_CMD_RESULT) >> 8;
1557 0 : sc->ridltv = 0;
1558 0 : wakeup(&sc->ridresperr);
1559 0 : }
1560 :
1561 : void
1562 0 : wi_usb_infofrm(struct wi_usb_chain *c, int len)
1563 : {
1564 0 : struct wi_usb_softc *sc = c->wi_usb_sc;
1565 :
1566 : DPRINTFN(10,("%s: %s: enter\n",
1567 : sc->wi_usb_dev.dv_xname, __func__));
1568 :
1569 0 : sc->wi_info = ((char *)c->wi_usb_buf) + 2;
1570 0 : wi_update_stats(&sc->sc_wi);
1571 0 : sc->wi_info = NULL;
1572 0 : }
1573 :
1574 : void
1575 0 : wi_usb_txfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
1576 : {
1577 : u_int16_t status;
1578 : int s;
1579 0 : struct wi_softc *wsc = &sc->sc_wi;
1580 0 : struct ifnet *ifp = &wsc->sc_ic.ic_if;
1581 :
1582 0 : s = splnet();
1583 0 : status = letoh16(uin->type); /* XXX -- type == status */
1584 :
1585 :
1586 : DPRINTFN(2,("%s: %s: enter status=%d\n",
1587 : sc->wi_usb_dev.dv_xname, __func__, status));
1588 :
1589 0 : if (sc->txresp == WI_CMD_TX) {
1590 0 : sc->txresperr=status;
1591 0 : sc->txresp = 0;
1592 0 : wakeup(&sc->txresperr);
1593 0 : } else {
1594 0 : if (status != 0) /* XXX */
1595 0 : wi_watchdog_usb(ifp);
1596 : DPRINTFN(1,("%s: %s: txresp not expected status=%d \n",
1597 : sc->wi_usb_dev.dv_xname, __func__, status));
1598 : }
1599 :
1600 0 : splx(s);
1601 0 : }
1602 : void
1603 0 : wi_usb_rxfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
1604 : {
1605 : int s;
1606 :
1607 : DPRINTFN(5,("%s: %s: enter len=%d\n",
1608 : sc->wi_usb_dev.dv_xname, __func__, total_len));
1609 :
1610 0 : s = splnet();
1611 :
1612 0 : sc->wi_rxframe = (void *)uin;
1613 :
1614 0 : wi_rxeof(&sc->sc_wi);
1615 :
1616 0 : sc->wi_rxframe = NULL;
1617 :
1618 0 : splx(s);
1619 :
1620 0 : }
1621 :
1622 :
1623 : void
1624 0 : wi_usb_start_thread(void *arg)
1625 : {
1626 0 : struct wi_usb_softc *sc = arg;
1627 0 : kthread_create (wi_usb_thread, arg, NULL, sc->wi_usb_dev.dv_xname);
1628 0 : }
1629 :
1630 : void
1631 0 : wi_start_usb(struct ifnet *ifp)
1632 : {
1633 : struct wi_softc *wsc;
1634 : struct wi_usb_softc *sc;
1635 : int s;
1636 :
1637 0 : wsc = ifp->if_softc;
1638 0 : sc = wsc->wi_usb_cdata;
1639 :
1640 0 : s = splnet();
1641 :
1642 : DPRINTFN(5,("%s: %s:\n",
1643 : sc->wi_usb_dev.dv_xname, __func__));
1644 :
1645 0 : if (wi_usb_tx_lock_try(sc)) {
1646 : /* lock acquired do start now */
1647 0 : wi_func_io.f_start(ifp);
1648 0 : } else {
1649 0 : sc->wi_thread_info->status |= WI_START;
1650 0 : if (sc->wi_thread_info->idle)
1651 0 : wakeup(sc->wi_thread_info);
1652 : }
1653 :
1654 0 : splx(s);
1655 0 : }
1656 :
1657 : /*
1658 : * inquire is called from interrupt context (timeout)
1659 : * It is not possible to sleep in interrupt context so it is necessary
1660 : * to signal the kernel thread to perform the action.
1661 : */
1662 : void
1663 0 : wi_init_usb(struct wi_softc *wsc)
1664 : {
1665 : DPRINTFN(5,("%s: %s:\n", WI_PRT_ARG(wsc), __func__));
1666 :
1667 0 : wi_usb_ctl_lock(wsc->wi_usb_cdata);
1668 0 : wi_func_io.f_init(wsc);
1669 0 : wi_usb_ctl_unlock(wsc->wi_usb_cdata);
1670 0 : }
1671 :
1672 :
1673 : /*
1674 : * inquire is called from interrupt context (timeout)
1675 : * It is not possible to sleep in interrupt context so it is necessary
1676 : * to signal the kernel thread to perform the action.
1677 : */
1678 : void
1679 0 : wi_inquire_usb(void *xsc)
1680 : {
1681 0 : struct wi_softc *wsc = xsc;
1682 0 : struct wi_usb_softc *sc = wsc->wi_usb_cdata;
1683 : int s;
1684 :
1685 :
1686 0 : s = splnet();
1687 :
1688 : DPRINTFN(2,("%s: %s:\n",
1689 : sc->wi_usb_dev.dv_xname, __func__));
1690 :
1691 0 : sc->wi_thread_info->status |= WI_INQUIRE;
1692 :
1693 0 : if (sc->wi_thread_info->idle)
1694 0 : wakeup(sc->wi_thread_info);
1695 0 : splx(s);
1696 0 : }
1697 :
1698 : /*
1699 : * Watchdog is normally called from interrupt context (timeout)
1700 : * It is not possible to sleep in interrupt context so it is necessary
1701 : * to signal the kernel thread to perform the action.
1702 : */
1703 : void
1704 0 : wi_watchdog_usb(struct ifnet *ifp)
1705 : {
1706 : struct wi_softc *wsc;
1707 : struct wi_usb_softc *sc;
1708 : int s;
1709 :
1710 0 : wsc = ifp->if_softc;
1711 0 : sc = wsc->wi_usb_cdata;
1712 :
1713 0 : s = splnet();
1714 :
1715 : DPRINTFN(5,("%s: %s: ifp %x\n",
1716 : sc->wi_usb_dev.dv_xname, __func__, ifp));
1717 :
1718 0 : sc->wi_thread_info->status |= WI_WATCHDOG;
1719 :
1720 0 : if (sc->wi_thread_info->idle)
1721 0 : wakeup(sc->wi_thread_info);
1722 0 : splx(s);
1723 0 : }
1724 :
1725 : /*
1726 : * ioctl will always be called from a user context,
1727 : * therefore it is possible to sleep in the calling context
1728 : * acquire the lock and call the real ioctl function directly
1729 : */
1730 : int
1731 0 : wi_ioctl_usb(struct ifnet *ifp, u_long command, caddr_t data)
1732 : {
1733 : struct wi_softc *wsc;
1734 : int err;
1735 :
1736 0 : wsc = ifp->if_softc;
1737 :
1738 0 : wi_usb_ctl_lock(wsc->wi_usb_cdata);
1739 0 : err = wi_func_io.f_ioctl(ifp, command, data);
1740 0 : wi_usb_ctl_unlock(wsc->wi_usb_cdata);
1741 0 : return err;
1742 : }
1743 :
1744 : void
1745 0 : wi_usb_thread(void *arg)
1746 : {
1747 0 : struct wi_usb_softc *sc = arg;
1748 : struct wi_usb_thread_info *wi_thread_info;
1749 : int s;
1750 :
1751 0 : wi_thread_info = malloc(sizeof(*wi_thread_info), M_DEVBUF, M_WAITOK);
1752 :
1753 : /*
1754 : * is there a remote possibility that the device could
1755 : * be removed before the kernel thread starts up?
1756 : */
1757 :
1758 0 : sc->wi_usb_refcnt++;
1759 :
1760 0 : sc->wi_thread_info = wi_thread_info;
1761 0 : wi_thread_info->dying = 0;
1762 0 : wi_thread_info->status = 0;
1763 :
1764 0 : wi_usb_ctl_lock(sc);
1765 :
1766 0 : wi_attach(&sc->sc_wi, &wi_func_usb);
1767 :
1768 0 : wi_usb_ctl_unlock(sc);
1769 :
1770 0 : for(;;) {
1771 0 : if (wi_thread_info->dying) {
1772 0 : if (--sc->wi_usb_refcnt < 0)
1773 0 : usb_detach_wakeup(&sc->wi_usb_dev);
1774 0 : kthread_exit(0);
1775 : }
1776 :
1777 : DPRINTFN(5,("%s: %s: dying %x status %x\n",
1778 : sc->wi_usb_dev.dv_xname, __func__,
1779 : wi_thread_info->dying, wi_thread_info->status));
1780 :
1781 0 : wi_usb_ctl_lock(sc);
1782 :
1783 : DPRINTFN(5,("%s: %s: starting %x\n",
1784 : sc->wi_usb_dev.dv_xname, __func__,
1785 : wi_thread_info->status));
1786 :
1787 0 : s = splusb();
1788 0 : if (wi_thread_info->status & WI_START) {
1789 0 : wi_thread_info->status &= ~WI_START;
1790 0 : wi_usb_tx_lock(sc);
1791 0 : wi_func_io.f_start(&sc->sc_wi.sc_ic.ic_if);
1792 : /*
1793 : * tx_unlock is explicitly missing here
1794 : * it is done in txeof_frm
1795 : */
1796 0 : } else if (wi_thread_info->status & WI_INQUIRE) {
1797 0 : wi_thread_info->status &= ~WI_INQUIRE;
1798 0 : wi_func_io.f_inquire(&sc->sc_wi);
1799 0 : } else if (wi_thread_info->status & WI_WATCHDOG) {
1800 0 : wi_thread_info->status &= ~WI_WATCHDOG;
1801 0 : wi_func_io.f_watchdog( &sc->sc_wi.sc_ic.ic_if);
1802 0 : }
1803 0 : splx(s);
1804 :
1805 : DPRINTFN(5,("%s: %s: ending %x\n",
1806 : sc->wi_usb_dev.dv_xname, __func__,
1807 : wi_thread_info->status));
1808 0 : wi_usb_ctl_unlock(sc);
1809 :
1810 0 : if (wi_thread_info->status == 0) {
1811 0 : s = splnet();
1812 0 : wi_thread_info->idle = 1;
1813 0 : tsleep(wi_thread_info, PRIBIO, "wiIDL", 0);
1814 0 : wi_thread_info->idle = 0;
1815 0 : splx(s);
1816 0 : }
1817 : }
1818 : }
1819 :
1820 : int
1821 0 : wi_usb_tx_lock_try(struct wi_usb_softc *sc)
1822 : {
1823 : int s;
1824 :
1825 0 : s = splnet();
1826 :
1827 : DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1828 :
1829 0 : if (sc->wi_lock != 0) {
1830 0 : splx(s);
1831 0 : return 0; /* failed to aquire lock */
1832 : }
1833 :
1834 0 : sc->wi_lock = 1;
1835 :
1836 0 : splx(s);
1837 :
1838 0 : return 1;
1839 0 : }
1840 : void
1841 0 : wi_usb_tx_lock(struct wi_usb_softc *sc)
1842 : {
1843 : int s;
1844 :
1845 0 : s = splnet();
1846 :
1847 : again:
1848 : DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1849 :
1850 0 : if (sc->wi_lock != 0) {
1851 0 : sc->wi_lockwait++;
1852 : DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
1853 : __func__, sc->wi_lockwait ));
1854 0 : tsleep(&sc->wi_lock, PRIBIO, "witxl", 0);
1855 0 : }
1856 :
1857 0 : if (sc->wi_lock != 0)
1858 0 : goto again;
1859 0 : sc->wi_lock = 1;
1860 :
1861 0 : splx(s);
1862 :
1863 : return;
1864 :
1865 0 : }
1866 :
1867 : void
1868 0 : wi_usb_tx_unlock(struct wi_usb_softc *sc)
1869 : {
1870 : int s;
1871 0 : s = splnet();
1872 :
1873 0 : sc->wi_lock = 0;
1874 :
1875 : DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1876 :
1877 0 : if (sc->wi_lockwait) {
1878 : DPRINTFN(10,("%s: %s: waking\n",
1879 : sc->wi_usb_dev.dv_xname, __func__));
1880 0 : sc->wi_lockwait = 0;
1881 0 : wakeup(&sc->wi_lock);
1882 0 : }
1883 :
1884 0 : splx(s);
1885 0 : }
1886 :
1887 : void
1888 0 : wi_usb_ctl_lock(struct wi_usb_softc *sc)
1889 : {
1890 : int s;
1891 :
1892 0 : s = splnet();
1893 :
1894 : again:
1895 : DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,
1896 : __func__));
1897 :
1898 0 : if (sc->wi_ctllock != 0) {
1899 0 : if (curproc == sc->wi_curproc) {
1900 : /* allow recursion */
1901 0 : sc->wi_ctllock++;
1902 0 : splx(s);
1903 0 : return;
1904 : }
1905 0 : sc->wi_ctllockwait++;
1906 : DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
1907 : __func__, sc->wi_ctllockwait ));
1908 0 : tsleep(&sc->wi_ctllock, PRIBIO, "wiusbthr", 0);
1909 0 : }
1910 :
1911 0 : if (sc->wi_ctllock != 0)
1912 0 : goto again;
1913 0 : sc->wi_ctllock++;
1914 0 : sc->wi_curproc = curproc;
1915 :
1916 0 : splx(s);
1917 :
1918 0 : return;
1919 :
1920 0 : }
1921 :
1922 : void
1923 0 : wi_usb_ctl_unlock(struct wi_usb_softc *sc)
1924 : {
1925 : int s;
1926 :
1927 0 : s = splnet();
1928 :
1929 0 : sc->wi_ctllock--;
1930 :
1931 : DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1932 :
1933 0 : if (sc->wi_ctllock == 0 && sc->wi_ctllockwait) {
1934 : DPRINTFN(10,("%s: %s: waking\n",
1935 : sc->wi_usb_dev.dv_xname, __func__));
1936 0 : sc->wi_ctllockwait = 0;
1937 0 : sc->wi_curproc = 0;
1938 0 : wakeup(&sc->wi_ctllock);
1939 0 : }
1940 :
1941 0 : splx(s);
1942 0 : }
|