1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (c) 1997, 1998, 1999, 2000 |
---|
5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. |
---|
6 | * |
---|
7 | * Redistribution and use in source and binary forms, with or without |
---|
8 | * modification, are permitted provided that the following conditions |
---|
9 | * are met: |
---|
10 | * 1. Redistributions of source code must retain the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer. |
---|
12 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer in the |
---|
14 | * documentation and/or other materials provided with the distribution. |
---|
15 | * 3. All advertising materials mentioning features or use of this software |
---|
16 | * must display the following acknowledgement: |
---|
17 | * This product includes software developed by Bill Paul. |
---|
18 | * 4. Neither the name of the author nor the names of any co-contributors |
---|
19 | * may be used to endorse or promote products derived from this software |
---|
20 | * without specific prior written permission. |
---|
21 | * |
---|
22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND |
---|
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD |
---|
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
---|
32 | * THE POSSIBILITY OF SUCH DAMAGE. |
---|
33 | */ |
---|
34 | |
---|
35 | #include <sys/cdefs.h> |
---|
36 | __FBSDID("$FreeBSD$"); |
---|
37 | |
---|
38 | /* |
---|
39 | * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate |
---|
40 | * adapters and others. |
---|
41 | * |
---|
42 | * Written by Bill Paul <wpaul@ee.columbia.edu> |
---|
43 | * Electrical Engineering Department |
---|
44 | * Columbia University, New York City |
---|
45 | */ |
---|
46 | |
---|
47 | /* |
---|
48 | * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The |
---|
49 | * RX filter uses a 512-bit multicast hash table, single perfect entry |
---|
50 | * for the station address, and promiscuous mode. Unlike the ADMtek |
---|
51 | * and KLSI chips, the CATC ASIC supports read and write combining |
---|
52 | * mode where multiple packets can be transferred using a single bulk |
---|
53 | * transaction, which helps performance a great deal. |
---|
54 | */ |
---|
55 | |
---|
56 | #include <sys/stdint.h> |
---|
57 | #include <sys/stddef.h> |
---|
58 | #include <rtems/bsd/sys/param.h> |
---|
59 | #include <sys/queue.h> |
---|
60 | #include <sys/types.h> |
---|
61 | #include <sys/systm.h> |
---|
62 | #include <sys/socket.h> |
---|
63 | #include <sys/kernel.h> |
---|
64 | #include <sys/bus.h> |
---|
65 | #include <sys/module.h> |
---|
66 | #include <rtems/bsd/sys/lock.h> |
---|
67 | #include <sys/mutex.h> |
---|
68 | #include <sys/condvar.h> |
---|
69 | #include <sys/sysctl.h> |
---|
70 | #include <sys/sx.h> |
---|
71 | #include <rtems/bsd/sys/unistd.h> |
---|
72 | #include <sys/callout.h> |
---|
73 | #include <sys/malloc.h> |
---|
74 | #include <sys/priv.h> |
---|
75 | |
---|
76 | #include <net/if.h> |
---|
77 | #include <net/if_var.h> |
---|
78 | |
---|
79 | #include <dev/usb/usb.h> |
---|
80 | #include <dev/usb/usbdi.h> |
---|
81 | #include <dev/usb/usbdi_util.h> |
---|
82 | #include <rtems/bsd/local/usbdevs.h> |
---|
83 | |
---|
84 | #define USB_DEBUG_VAR cue_debug |
---|
85 | #include <dev/usb/usb_debug.h> |
---|
86 | #include <dev/usb/usb_process.h> |
---|
87 | |
---|
88 | #include <dev/usb/net/usb_ethernet.h> |
---|
89 | #include <dev/usb/net/if_cuereg.h> |
---|
90 | |
---|
91 | /* |
---|
92 | * Various supported device vendors/products. |
---|
93 | */ |
---|
94 | |
---|
95 | /* Belkin F5U111 adapter covered by NETMATE entry */ |
---|
96 | |
---|
97 | static const STRUCT_USB_HOST_ID cue_devs[] = { |
---|
98 | #define CUE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } |
---|
99 | CUE_DEV(CATC, NETMATE), |
---|
100 | CUE_DEV(CATC, NETMATE2), |
---|
101 | CUE_DEV(SMARTBRIDGES, SMARTLINK), |
---|
102 | #undef CUE_DEV |
---|
103 | }; |
---|
104 | |
---|
105 | /* prototypes */ |
---|
106 | |
---|
107 | static device_probe_t cue_probe; |
---|
108 | static device_attach_t cue_attach; |
---|
109 | static device_detach_t cue_detach; |
---|
110 | |
---|
111 | static usb_callback_t cue_bulk_read_callback; |
---|
112 | static usb_callback_t cue_bulk_write_callback; |
---|
113 | |
---|
114 | static uether_fn_t cue_attach_post; |
---|
115 | static uether_fn_t cue_init; |
---|
116 | static uether_fn_t cue_stop; |
---|
117 | static uether_fn_t cue_start; |
---|
118 | static uether_fn_t cue_tick; |
---|
119 | static uether_fn_t cue_setmulti; |
---|
120 | static uether_fn_t cue_setpromisc; |
---|
121 | |
---|
122 | static uint8_t cue_csr_read_1(struct cue_softc *, uint16_t); |
---|
123 | static uint16_t cue_csr_read_2(struct cue_softc *, uint8_t); |
---|
124 | static int cue_csr_write_1(struct cue_softc *, uint16_t, uint16_t); |
---|
125 | static int cue_mem(struct cue_softc *, uint8_t, uint16_t, void *, int); |
---|
126 | static int cue_getmac(struct cue_softc *, void *); |
---|
127 | static uint32_t cue_mchash(const uint8_t *); |
---|
128 | static void cue_reset(struct cue_softc *); |
---|
129 | |
---|
130 | #ifdef USB_DEBUG |
---|
131 | static int cue_debug = 0; |
---|
132 | |
---|
133 | static SYSCTL_NODE(_hw_usb, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue"); |
---|
134 | SYSCTL_INT(_hw_usb_cue, OID_AUTO, debug, CTLFLAG_RWTUN, &cue_debug, 0, |
---|
135 | "Debug level"); |
---|
136 | #endif |
---|
137 | |
---|
138 | static const struct usb_config cue_config[CUE_N_TRANSFER] = { |
---|
139 | |
---|
140 | [CUE_BULK_DT_WR] = { |
---|
141 | .type = UE_BULK, |
---|
142 | .endpoint = UE_ADDR_ANY, |
---|
143 | .direction = UE_DIR_OUT, |
---|
144 | .bufsize = (MCLBYTES + 2), |
---|
145 | .flags = {.pipe_bof = 1,}, |
---|
146 | .callback = cue_bulk_write_callback, |
---|
147 | .timeout = 10000, /* 10 seconds */ |
---|
148 | }, |
---|
149 | |
---|
150 | [CUE_BULK_DT_RD] = { |
---|
151 | .type = UE_BULK, |
---|
152 | .endpoint = UE_ADDR_ANY, |
---|
153 | .direction = UE_DIR_IN, |
---|
154 | .bufsize = (MCLBYTES + 2), |
---|
155 | .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, |
---|
156 | .callback = cue_bulk_read_callback, |
---|
157 | }, |
---|
158 | }; |
---|
159 | |
---|
160 | static device_method_t cue_methods[] = { |
---|
161 | /* Device interface */ |
---|
162 | DEVMETHOD(device_probe, cue_probe), |
---|
163 | DEVMETHOD(device_attach, cue_attach), |
---|
164 | DEVMETHOD(device_detach, cue_detach), |
---|
165 | |
---|
166 | DEVMETHOD_END |
---|
167 | }; |
---|
168 | |
---|
169 | static driver_t cue_driver = { |
---|
170 | .name = "cue", |
---|
171 | .methods = cue_methods, |
---|
172 | .size = sizeof(struct cue_softc), |
---|
173 | }; |
---|
174 | |
---|
175 | static devclass_t cue_devclass; |
---|
176 | |
---|
177 | DRIVER_MODULE(cue, uhub, cue_driver, cue_devclass, NULL, 0); |
---|
178 | MODULE_DEPEND(cue, uether, 1, 1, 1); |
---|
179 | MODULE_DEPEND(cue, usb, 1, 1, 1); |
---|
180 | MODULE_DEPEND(cue, ether, 1, 1, 1); |
---|
181 | MODULE_VERSION(cue, 1); |
---|
182 | USB_PNP_HOST_INFO(cue_devs); |
---|
183 | |
---|
184 | static const struct usb_ether_methods cue_ue_methods = { |
---|
185 | .ue_attach_post = cue_attach_post, |
---|
186 | .ue_start = cue_start, |
---|
187 | .ue_init = cue_init, |
---|
188 | .ue_stop = cue_stop, |
---|
189 | .ue_tick = cue_tick, |
---|
190 | .ue_setmulti = cue_setmulti, |
---|
191 | .ue_setpromisc = cue_setpromisc, |
---|
192 | }; |
---|
193 | |
---|
194 | #define CUE_SETBIT(sc, reg, x) \ |
---|
195 | cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x)) |
---|
196 | |
---|
197 | #define CUE_CLRBIT(sc, reg, x) \ |
---|
198 | cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x)) |
---|
199 | |
---|
200 | static uint8_t |
---|
201 | cue_csr_read_1(struct cue_softc *sc, uint16_t reg) |
---|
202 | { |
---|
203 | struct usb_device_request req; |
---|
204 | uint8_t val; |
---|
205 | |
---|
206 | req.bmRequestType = UT_READ_VENDOR_DEVICE; |
---|
207 | req.bRequest = CUE_CMD_READREG; |
---|
208 | USETW(req.wValue, 0); |
---|
209 | USETW(req.wIndex, reg); |
---|
210 | USETW(req.wLength, 1); |
---|
211 | |
---|
212 | if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) { |
---|
213 | /* ignore any errors */ |
---|
214 | } |
---|
215 | return (val); |
---|
216 | } |
---|
217 | |
---|
218 | static uint16_t |
---|
219 | cue_csr_read_2(struct cue_softc *sc, uint8_t reg) |
---|
220 | { |
---|
221 | struct usb_device_request req; |
---|
222 | uint16_t val; |
---|
223 | |
---|
224 | req.bmRequestType = UT_READ_VENDOR_DEVICE; |
---|
225 | req.bRequest = CUE_CMD_READREG; |
---|
226 | USETW(req.wValue, 0); |
---|
227 | USETW(req.wIndex, reg); |
---|
228 | USETW(req.wLength, 2); |
---|
229 | |
---|
230 | (void)uether_do_request(&sc->sc_ue, &req, &val, 1000); |
---|
231 | return (le16toh(val)); |
---|
232 | } |
---|
233 | |
---|
234 | static int |
---|
235 | cue_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val) |
---|
236 | { |
---|
237 | struct usb_device_request req; |
---|
238 | |
---|
239 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; |
---|
240 | req.bRequest = CUE_CMD_WRITEREG; |
---|
241 | USETW(req.wValue, val); |
---|
242 | USETW(req.wIndex, reg); |
---|
243 | USETW(req.wLength, 0); |
---|
244 | |
---|
245 | return (uether_do_request(&sc->sc_ue, &req, NULL, 1000)); |
---|
246 | } |
---|
247 | |
---|
248 | static int |
---|
249 | cue_mem(struct cue_softc *sc, uint8_t cmd, uint16_t addr, void *buf, int len) |
---|
250 | { |
---|
251 | struct usb_device_request req; |
---|
252 | |
---|
253 | if (cmd == CUE_CMD_READSRAM) |
---|
254 | req.bmRequestType = UT_READ_VENDOR_DEVICE; |
---|
255 | else |
---|
256 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; |
---|
257 | req.bRequest = cmd; |
---|
258 | USETW(req.wValue, 0); |
---|
259 | USETW(req.wIndex, addr); |
---|
260 | USETW(req.wLength, len); |
---|
261 | |
---|
262 | return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); |
---|
263 | } |
---|
264 | |
---|
265 | static int |
---|
266 | cue_getmac(struct cue_softc *sc, void *buf) |
---|
267 | { |
---|
268 | struct usb_device_request req; |
---|
269 | |
---|
270 | req.bmRequestType = UT_READ_VENDOR_DEVICE; |
---|
271 | req.bRequest = CUE_CMD_GET_MACADDR; |
---|
272 | USETW(req.wValue, 0); |
---|
273 | USETW(req.wIndex, 0); |
---|
274 | USETW(req.wLength, ETHER_ADDR_LEN); |
---|
275 | |
---|
276 | return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); |
---|
277 | } |
---|
278 | |
---|
279 | #define CUE_BITS 9 |
---|
280 | |
---|
281 | static uint32_t |
---|
282 | cue_mchash(const uint8_t *addr) |
---|
283 | { |
---|
284 | uint32_t crc; |
---|
285 | |
---|
286 | /* Compute CRC for the address value. */ |
---|
287 | crc = ether_crc32_le(addr, ETHER_ADDR_LEN); |
---|
288 | |
---|
289 | return (crc & ((1 << CUE_BITS) - 1)); |
---|
290 | } |
---|
291 | |
---|
292 | static void |
---|
293 | cue_setpromisc(struct usb_ether *ue) |
---|
294 | { |
---|
295 | struct cue_softc *sc = uether_getsc(ue); |
---|
296 | struct ifnet *ifp = uether_getifp(ue); |
---|
297 | |
---|
298 | CUE_LOCK_ASSERT(sc, MA_OWNED); |
---|
299 | |
---|
300 | /* if we want promiscuous mode, set the allframes bit */ |
---|
301 | if (ifp->if_flags & IFF_PROMISC) |
---|
302 | CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); |
---|
303 | else |
---|
304 | CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); |
---|
305 | |
---|
306 | /* write multicast hash-bits */ |
---|
307 | cue_setmulti(ue); |
---|
308 | } |
---|
309 | |
---|
310 | static void |
---|
311 | cue_setmulti(struct usb_ether *ue) |
---|
312 | { |
---|
313 | struct cue_softc *sc = uether_getsc(ue); |
---|
314 | struct ifnet *ifp = uether_getifp(ue); |
---|
315 | struct ifmultiaddr *ifma; |
---|
316 | uint32_t h = 0, i; |
---|
317 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
---|
318 | |
---|
319 | CUE_LOCK_ASSERT(sc, MA_OWNED); |
---|
320 | |
---|
321 | if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { |
---|
322 | for (i = 0; i < 8; i++) |
---|
323 | hashtbl[i] = 0xff; |
---|
324 | cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, |
---|
325 | &hashtbl, 8); |
---|
326 | return; |
---|
327 | } |
---|
328 | |
---|
329 | /* now program new ones */ |
---|
330 | if_maddr_rlock(ifp); |
---|
331 | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) |
---|
332 | { |
---|
333 | if (ifma->ifma_addr->sa_family != AF_LINK) |
---|
334 | continue; |
---|
335 | h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); |
---|
336 | hashtbl[h >> 3] |= 1 << (h & 0x7); |
---|
337 | } |
---|
338 | if_maddr_runlock(ifp); |
---|
339 | |
---|
340 | /* |
---|
341 | * Also include the broadcast address in the filter |
---|
342 | * so we can receive broadcast frames. |
---|
343 | */ |
---|
344 | if (ifp->if_flags & IFF_BROADCAST) { |
---|
345 | h = cue_mchash(ifp->if_broadcastaddr); |
---|
346 | hashtbl[h >> 3] |= 1 << (h & 0x7); |
---|
347 | } |
---|
348 | |
---|
349 | cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, &hashtbl, 8); |
---|
350 | } |
---|
351 | |
---|
352 | static void |
---|
353 | cue_reset(struct cue_softc *sc) |
---|
354 | { |
---|
355 | struct usb_device_request req; |
---|
356 | |
---|
357 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; |
---|
358 | req.bRequest = CUE_CMD_RESET; |
---|
359 | USETW(req.wValue, 0); |
---|
360 | USETW(req.wIndex, 0); |
---|
361 | USETW(req.wLength, 0); |
---|
362 | |
---|
363 | if (uether_do_request(&sc->sc_ue, &req, NULL, 1000)) { |
---|
364 | /* ignore any errors */ |
---|
365 | } |
---|
366 | |
---|
367 | /* |
---|
368 | * wait a little while for the chip to get its brains in order: |
---|
369 | */ |
---|
370 | uether_pause(&sc->sc_ue, hz / 100); |
---|
371 | } |
---|
372 | |
---|
373 | static void |
---|
374 | cue_attach_post(struct usb_ether *ue) |
---|
375 | { |
---|
376 | struct cue_softc *sc = uether_getsc(ue); |
---|
377 | |
---|
378 | cue_getmac(sc, ue->ue_eaddr); |
---|
379 | } |
---|
380 | |
---|
381 | static int |
---|
382 | cue_probe(device_t dev) |
---|
383 | { |
---|
384 | struct usb_attach_arg *uaa = device_get_ivars(dev); |
---|
385 | |
---|
386 | if (uaa->usb_mode != USB_MODE_HOST) |
---|
387 | return (ENXIO); |
---|
388 | if (uaa->info.bConfigIndex != CUE_CONFIG_IDX) |
---|
389 | return (ENXIO); |
---|
390 | if (uaa->info.bIfaceIndex != CUE_IFACE_IDX) |
---|
391 | return (ENXIO); |
---|
392 | |
---|
393 | return (usbd_lookup_id_by_uaa(cue_devs, sizeof(cue_devs), uaa)); |
---|
394 | } |
---|
395 | |
---|
396 | /* |
---|
397 | * Attach the interface. Allocate softc structures, do ifmedia |
---|
398 | * setup and ethernet/BPF attach. |
---|
399 | */ |
---|
400 | static int |
---|
401 | cue_attach(device_t dev) |
---|
402 | { |
---|
403 | struct usb_attach_arg *uaa = device_get_ivars(dev); |
---|
404 | struct cue_softc *sc = device_get_softc(dev); |
---|
405 | struct usb_ether *ue = &sc->sc_ue; |
---|
406 | uint8_t iface_index; |
---|
407 | int error; |
---|
408 | |
---|
409 | device_set_usb_desc(dev); |
---|
410 | mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); |
---|
411 | |
---|
412 | iface_index = CUE_IFACE_IDX; |
---|
413 | error = usbd_transfer_setup(uaa->device, &iface_index, |
---|
414 | sc->sc_xfer, cue_config, CUE_N_TRANSFER, sc, &sc->sc_mtx); |
---|
415 | if (error) { |
---|
416 | device_printf(dev, "allocating USB transfers failed\n"); |
---|
417 | goto detach; |
---|
418 | } |
---|
419 | |
---|
420 | ue->ue_sc = sc; |
---|
421 | ue->ue_dev = dev; |
---|
422 | ue->ue_udev = uaa->device; |
---|
423 | ue->ue_mtx = &sc->sc_mtx; |
---|
424 | ue->ue_methods = &cue_ue_methods; |
---|
425 | |
---|
426 | error = uether_ifattach(ue); |
---|
427 | if (error) { |
---|
428 | device_printf(dev, "could not attach interface\n"); |
---|
429 | goto detach; |
---|
430 | } |
---|
431 | return (0); /* success */ |
---|
432 | |
---|
433 | detach: |
---|
434 | cue_detach(dev); |
---|
435 | return (ENXIO); /* failure */ |
---|
436 | } |
---|
437 | |
---|
438 | static int |
---|
439 | cue_detach(device_t dev) |
---|
440 | { |
---|
441 | struct cue_softc *sc = device_get_softc(dev); |
---|
442 | struct usb_ether *ue = &sc->sc_ue; |
---|
443 | |
---|
444 | usbd_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER); |
---|
445 | uether_ifdetach(ue); |
---|
446 | mtx_destroy(&sc->sc_mtx); |
---|
447 | |
---|
448 | return (0); |
---|
449 | } |
---|
450 | |
---|
451 | static void |
---|
452 | cue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) |
---|
453 | { |
---|
454 | struct cue_softc *sc = usbd_xfer_softc(xfer); |
---|
455 | struct usb_ether *ue = &sc->sc_ue; |
---|
456 | struct ifnet *ifp = uether_getifp(ue); |
---|
457 | struct usb_page_cache *pc; |
---|
458 | uint8_t buf[2]; |
---|
459 | int len; |
---|
460 | int actlen; |
---|
461 | |
---|
462 | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); |
---|
463 | |
---|
464 | switch (USB_GET_STATE(xfer)) { |
---|
465 | case USB_ST_TRANSFERRED: |
---|
466 | |
---|
467 | if (actlen <= (int)(2 + sizeof(struct ether_header))) { |
---|
468 | if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); |
---|
469 | goto tr_setup; |
---|
470 | } |
---|
471 | pc = usbd_xfer_get_frame(xfer, 0); |
---|
472 | usbd_copy_out(pc, 0, buf, 2); |
---|
473 | actlen -= 2; |
---|
474 | len = buf[0] | (buf[1] << 8); |
---|
475 | len = min(actlen, len); |
---|
476 | |
---|
477 | uether_rxbuf(ue, pc, 2, len); |
---|
478 | /* FALLTHROUGH */ |
---|
479 | case USB_ST_SETUP: |
---|
480 | tr_setup: |
---|
481 | usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); |
---|
482 | usbd_transfer_submit(xfer); |
---|
483 | uether_rxflush(ue); |
---|
484 | return; |
---|
485 | |
---|
486 | default: /* Error */ |
---|
487 | DPRINTF("bulk read error, %s\n", |
---|
488 | usbd_errstr(error)); |
---|
489 | |
---|
490 | if (error != USB_ERR_CANCELLED) { |
---|
491 | /* try to clear stall first */ |
---|
492 | usbd_xfer_set_stall(xfer); |
---|
493 | goto tr_setup; |
---|
494 | } |
---|
495 | return; |
---|
496 | |
---|
497 | } |
---|
498 | } |
---|
499 | |
---|
500 | static void |
---|
501 | cue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) |
---|
502 | { |
---|
503 | struct cue_softc *sc = usbd_xfer_softc(xfer); |
---|
504 | struct ifnet *ifp = uether_getifp(&sc->sc_ue); |
---|
505 | struct usb_page_cache *pc; |
---|
506 | struct mbuf *m; |
---|
507 | uint8_t buf[2]; |
---|
508 | |
---|
509 | switch (USB_GET_STATE(xfer)) { |
---|
510 | case USB_ST_TRANSFERRED: |
---|
511 | DPRINTFN(11, "transfer complete\n"); |
---|
512 | if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); |
---|
513 | |
---|
514 | /* FALLTHROUGH */ |
---|
515 | case USB_ST_SETUP: |
---|
516 | tr_setup: |
---|
517 | IFQ_DRV_DEQUEUE(&ifp->if_snd, m); |
---|
518 | |
---|
519 | if (m == NULL) |
---|
520 | return; |
---|
521 | if (m->m_pkthdr.len > MCLBYTES) |
---|
522 | m->m_pkthdr.len = MCLBYTES; |
---|
523 | usbd_xfer_set_frame_len(xfer, 0, (m->m_pkthdr.len + 2)); |
---|
524 | |
---|
525 | /* the first two bytes are the frame length */ |
---|
526 | |
---|
527 | buf[0] = (uint8_t)(m->m_pkthdr.len); |
---|
528 | buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); |
---|
529 | |
---|
530 | pc = usbd_xfer_get_frame(xfer, 0); |
---|
531 | usbd_copy_in(pc, 0, buf, 2); |
---|
532 | usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len); |
---|
533 | |
---|
534 | /* |
---|
535 | * If there's a BPF listener, bounce a copy of this frame |
---|
536 | * to him. |
---|
537 | */ |
---|
538 | BPF_MTAP(ifp, m); |
---|
539 | |
---|
540 | m_freem(m); |
---|
541 | |
---|
542 | usbd_transfer_submit(xfer); |
---|
543 | |
---|
544 | return; |
---|
545 | |
---|
546 | default: /* Error */ |
---|
547 | DPRINTFN(11, "transfer error, %s\n", |
---|
548 | usbd_errstr(error)); |
---|
549 | |
---|
550 | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); |
---|
551 | |
---|
552 | if (error != USB_ERR_CANCELLED) { |
---|
553 | /* try to clear stall first */ |
---|
554 | usbd_xfer_set_stall(xfer); |
---|
555 | goto tr_setup; |
---|
556 | } |
---|
557 | return; |
---|
558 | } |
---|
559 | } |
---|
560 | |
---|
561 | static void |
---|
562 | cue_tick(struct usb_ether *ue) |
---|
563 | { |
---|
564 | struct cue_softc *sc = uether_getsc(ue); |
---|
565 | struct ifnet *ifp = uether_getifp(ue); |
---|
566 | |
---|
567 | CUE_LOCK_ASSERT(sc, MA_OWNED); |
---|
568 | |
---|
569 | if_inc_counter(ifp, IFCOUNTER_COLLISIONS, cue_csr_read_2(sc, CUE_TX_SINGLECOLL)); |
---|
570 | if_inc_counter(ifp, IFCOUNTER_COLLISIONS, cue_csr_read_2(sc, CUE_TX_MULTICOLL)); |
---|
571 | if_inc_counter(ifp, IFCOUNTER_COLLISIONS, cue_csr_read_2(sc, CUE_TX_EXCESSCOLL)); |
---|
572 | |
---|
573 | if (cue_csr_read_2(sc, CUE_RX_FRAMEERR)) |
---|
574 | if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); |
---|
575 | } |
---|
576 | |
---|
577 | static void |
---|
578 | cue_start(struct usb_ether *ue) |
---|
579 | { |
---|
580 | struct cue_softc *sc = uether_getsc(ue); |
---|
581 | |
---|
582 | /* |
---|
583 | * start the USB transfers, if not already started: |
---|
584 | */ |
---|
585 | usbd_transfer_start(sc->sc_xfer[CUE_BULK_DT_RD]); |
---|
586 | usbd_transfer_start(sc->sc_xfer[CUE_BULK_DT_WR]); |
---|
587 | } |
---|
588 | |
---|
589 | static void |
---|
590 | cue_init(struct usb_ether *ue) |
---|
591 | { |
---|
592 | struct cue_softc *sc = uether_getsc(ue); |
---|
593 | struct ifnet *ifp = uether_getifp(ue); |
---|
594 | int i; |
---|
595 | |
---|
596 | CUE_LOCK_ASSERT(sc, MA_OWNED); |
---|
597 | |
---|
598 | /* |
---|
599 | * Cancel pending I/O and free all RX/TX buffers. |
---|
600 | */ |
---|
601 | cue_stop(ue); |
---|
602 | #if 0 |
---|
603 | cue_reset(sc); |
---|
604 | #endif |
---|
605 | /* Set MAC address */ |
---|
606 | for (i = 0; i < ETHER_ADDR_LEN; i++) |
---|
607 | cue_csr_write_1(sc, CUE_PAR0 - i, IF_LLADDR(ifp)[i]); |
---|
608 | |
---|
609 | /* Enable RX logic. */ |
---|
610 | cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON); |
---|
611 | |
---|
612 | /* Load the multicast filter */ |
---|
613 | cue_setpromisc(ue); |
---|
614 | |
---|
615 | /* |
---|
616 | * Set the number of RX and TX buffers that we want |
---|
617 | * to reserve inside the ASIC. |
---|
618 | */ |
---|
619 | cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES); |
---|
620 | cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES); |
---|
621 | |
---|
622 | /* Set advanced operation modes. */ |
---|
623 | cue_csr_write_1(sc, CUE_ADVANCED_OPMODES, |
---|
624 | CUE_AOP_EMBED_RXLEN | 0x01);/* 1 wait state */ |
---|
625 | |
---|
626 | /* Program the LED operation. */ |
---|
627 | cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); |
---|
628 | |
---|
629 | usbd_xfer_set_stall(sc->sc_xfer[CUE_BULK_DT_WR]); |
---|
630 | |
---|
631 | ifp->if_drv_flags |= IFF_DRV_RUNNING; |
---|
632 | cue_start(ue); |
---|
633 | } |
---|
634 | |
---|
635 | /* |
---|
636 | * Stop the adapter and free any mbufs allocated to the |
---|
637 | * RX and TX lists. |
---|
638 | */ |
---|
639 | static void |
---|
640 | cue_stop(struct usb_ether *ue) |
---|
641 | { |
---|
642 | struct cue_softc *sc = uether_getsc(ue); |
---|
643 | struct ifnet *ifp = uether_getifp(ue); |
---|
644 | |
---|
645 | CUE_LOCK_ASSERT(sc, MA_OWNED); |
---|
646 | |
---|
647 | ifp->if_drv_flags &= ~IFF_DRV_RUNNING; |
---|
648 | |
---|
649 | /* |
---|
650 | * stop all the transfers, if not already stopped: |
---|
651 | */ |
---|
652 | usbd_transfer_stop(sc->sc_xfer[CUE_BULK_DT_WR]); |
---|
653 | usbd_transfer_stop(sc->sc_xfer[CUE_BULK_DT_RD]); |
---|
654 | |
---|
655 | cue_csr_write_1(sc, CUE_ETHCTL, 0); |
---|
656 | cue_reset(sc); |
---|
657 | } |
---|