Annotation of sys/dev/usb/if_url.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_url.c,v 1.48 2007/06/14 10:11:15 mbalmer Exp $ */
2: /* $NetBSD: if_url.c,v 1.6 2002/09/29 10:19:21 martin Exp $ */
3: /*
4: * Copyright (c) 2001, 2002
5: * Shingo WATANABE <nabe@nabechan.org>. 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. Neither the name of the author nor the names of any co-contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: *
31: */
32:
33: /*
34: * The RTL8150L(Realtek USB to fast ethernet controller) spec can be found at
35: * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/8150v14.pdf
36: * ftp://152.104.125.40/lancard/data_sheet/8150/8150v14.pdf
37: */
38:
39: /*
40: * TODO:
41: * Interrupt Endpoint support
42: * External PHYs
43: * powerhook() support?
44: */
45:
46: #include "bpfilter.h"
47:
48: #include <sys/param.h>
49: #include <sys/systm.h>
50: #include <sys/rwlock.h>
51: #include <sys/mbuf.h>
52: #include <sys/kernel.h>
53: #include <sys/proc.h>
54: #include <sys/socket.h>
55:
56: #include <sys/device.h>
57:
58: #include <net/if.h>
59: #include <net/if_arp.h>
60: #include <net/if_dl.h>
61: #include <net/if_media.h>
62:
63: #if NBPFILTER > 0
64: #include <net/bpf.h>
65: #endif
66:
67: #ifdef INET
68: #include <netinet/in.h>
69: #include <netinet/in_systm.h>
70: #include <netinet/in_var.h>
71: #include <netinet/ip.h>
72: #include <netinet/if_ether.h>
73: #endif
74:
75: #include <dev/mii/mii.h>
76: #include <dev/mii/miivar.h>
77: #include <dev/mii/urlphyreg.h>
78:
79: #include <dev/usb/usb.h>
80: #include <dev/usb/usbdi.h>
81: #include <dev/usb/usbdi_util.h>
82: #include <dev/usb/usbdevs.h>
83:
84: #include <dev/usb/if_urlreg.h>
85:
86:
87: /* Function declarations */
88: int url_match(struct device *, void *, void *);
89: void url_attach(struct device *, struct device *, void *);
90: int url_detach(struct device *, int);
91: int url_activate(struct device *, enum devact);
92:
93: struct cfdriver url_cd = {
94: NULL, "url", DV_IFNET
95: };
96:
97: const struct cfattach url_ca = {
98: sizeof(struct url_softc),
99: url_match,
100: url_attach,
101: url_detach,
102: url_activate,
103: };
104:
105: int url_openpipes(struct url_softc *);
106: int url_rx_list_init(struct url_softc *);
107: int url_tx_list_init(struct url_softc *);
108: int url_newbuf(struct url_softc *, struct url_chain *, struct mbuf *);
109: void url_start(struct ifnet *);
110: int url_send(struct url_softc *, struct mbuf *, int);
111: void url_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
112: void url_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
113: void url_tick(void *);
114: void url_tick_task(void *);
115: int url_ioctl(struct ifnet *, u_long, caddr_t);
116: void url_stop_task(struct url_softc *);
117: void url_stop(struct ifnet *, int);
118: void url_watchdog(struct ifnet *);
119: int url_ifmedia_change(struct ifnet *);
120: void url_ifmedia_status(struct ifnet *, struct ifmediareq *);
121: void url_lock_mii(struct url_softc *);
122: void url_unlock_mii(struct url_softc *);
123: int url_int_miibus_readreg(struct device *, int, int);
124: void url_int_miibus_writereg(struct device *, int, int, int);
125: void url_miibus_statchg(struct device *);
126: int url_init(struct ifnet *);
127: void url_setmulti(struct url_softc *);
128: void url_reset(struct url_softc *);
129:
130: int url_csr_read_1(struct url_softc *, int);
131: int url_csr_read_2(struct url_softc *, int);
132: int url_csr_write_1(struct url_softc *, int, int);
133: int url_csr_write_2(struct url_softc *, int, int);
134: int url_csr_write_4(struct url_softc *, int, int);
135: int url_mem(struct url_softc *, int, int, void *, int);
136:
137: /* Macros */
138: #ifdef URL_DEBUG
139: #define DPRINTF(x) do { if (urldebug) printf x; } while (0)
140: #define DPRINTFN(n,x) do { if (urldebug >= (n)) printf x; } while (0)
141: int urldebug = 0;
142: #else
143: #define DPRINTF(x)
144: #define DPRINTFN(n,x)
145: #endif
146:
147: #define URL_SETBIT(sc, reg, x) \
148: url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) | (x))
149:
150: #define URL_SETBIT2(sc, reg, x) \
151: url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) | (x))
152:
153: #define URL_CLRBIT(sc, reg, x) \
154: url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) & ~(x))
155:
156: #define URL_CLRBIT2(sc, reg, x) \
157: url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) & ~(x))
158:
159: static const struct url_type {
160: struct usb_devno url_dev;
161: u_int16_t url_flags;
162: #define URL_EXT_PHY 0x0001
163: } url_devs [] = {
164: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_LCS8138TX}, 0},
165: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RTL8151}, 0},
166: {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0},
167: {{ USB_VENDOR_MICRONET, USB_PRODUCT_MICRONET_SP128AR}, 0},
168: {{ USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01}, 0},
169: {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8150}, 0},
170: {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8151}, 0},
171: {{ USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_PRESTIGE}, 0}
172: };
173: #define url_lookup(v, p) ((struct url_type *)usb_lookup(url_devs, v, p))
174:
175:
176: /* Probe */
177: int
178: url_match(struct device *parent, void *match, void *aux)
179: {
180: struct usb_attach_arg *uaa = aux;
181:
182: if (uaa->iface != NULL)
183: return (UMATCH_NONE);
184:
185: return (url_lookup(uaa->vendor, uaa->product) != NULL ?
186: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
187: }
188: /* Attach */
189: void
190: url_attach(struct device *parent, struct device *self, void *aux)
191: {
192: struct url_softc *sc = (struct url_softc *)self;
193: struct usb_attach_arg *uaa = aux;
194: usbd_device_handle dev = uaa->device;
195: usbd_interface_handle iface;
196: usbd_status err;
197: usb_interface_descriptor_t *id;
198: usb_endpoint_descriptor_t *ed;
199: char *devinfop;
200: char *devname = sc->sc_dev.dv_xname;
201: struct ifnet *ifp;
202: struct mii_data *mii;
203: u_char eaddr[ETHER_ADDR_LEN];
204: int i, s;
205:
206: devinfop = usbd_devinfo_alloc(dev, 0);
207: printf("\n%s: %s\n", devname, devinfop);
208: usbd_devinfo_free(devinfop);
209:
210: /* Move the device into the configured state. */
211: err = usbd_set_config_no(dev, URL_CONFIG_NO, 1);
212: if (err) {
213: printf("%s: setting config no failed\n", devname);
214: goto bad;
215: }
216:
217: usb_init_task(&sc->sc_tick_task, url_tick_task, sc);
218: rw_init(&sc->sc_mii_lock, "urlmii");
219: usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc);
220:
221: /* get control interface */
222: err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface);
223: if (err) {
224: printf("%s: failed to get interface, err=%s\n", devname,
225: usbd_errstr(err));
226: goto bad;
227: }
228:
229: sc->sc_udev = dev;
230: sc->sc_ctl_iface = iface;
231: sc->sc_flags = url_lookup(uaa->vendor, uaa->product)->url_flags;
232:
233: /* get interface descriptor */
234: id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
235:
236: /* find endpoints */
237: sc->sc_bulkin_no = sc->sc_bulkout_no = sc->sc_intrin_no = -1;
238: for (i = 0; i < id->bNumEndpoints; i++) {
239: ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
240: if (ed == NULL) {
241: printf("%s: couldn't get endpoint %d\n", devname, i);
242: goto bad;
243: }
244: if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
245: UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
246: sc->sc_bulkin_no = ed->bEndpointAddress; /* RX */
247: else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
248: UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
249: sc->sc_bulkout_no = ed->bEndpointAddress; /* TX */
250: else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT &&
251: UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
252: sc->sc_intrin_no = ed->bEndpointAddress; /* Status */
253: }
254:
255: if (sc->sc_bulkin_no == -1 || sc->sc_bulkout_no == -1 ||
256: sc->sc_intrin_no == -1) {
257: printf("%s: missing endpoint\n", devname);
258: goto bad;
259: }
260:
261: s = splnet();
262:
263: /* reset the adapter */
264: url_reset(sc);
265:
266: /* Get Ethernet Address */
267: err = url_mem(sc, URL_CMD_READMEM, URL_IDR0, (void *)eaddr,
268: ETHER_ADDR_LEN);
269: if (err) {
270: printf("%s: read MAC address failed\n", devname);
271: splx(s);
272: goto bad;
273: }
274:
275: /* Print Ethernet Address */
276: printf("%s: address %s\n", devname, ether_sprintf(eaddr));
277:
278: bcopy(eaddr, (char *)&sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
279: /* initialize interface information */
280: ifp = GET_IFP(sc);
281: ifp->if_softc = sc;
282: strlcpy(ifp->if_xname, devname, IFNAMSIZ);
283: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
284: ifp->if_start = url_start;
285: ifp->if_ioctl = url_ioctl;
286: ifp->if_watchdog = url_watchdog;
287:
288: IFQ_SET_READY(&ifp->if_snd);
289:
290: /*
291: * Do ifmedia setup.
292: */
293: mii = &sc->sc_mii;
294: mii->mii_ifp = ifp;
295: mii->mii_readreg = url_int_miibus_readreg;
296: mii->mii_writereg = url_int_miibus_writereg;
297: #if 0
298: if (sc->sc_flags & URL_EXT_PHY) {
299: mii->mii_readreg = url_ext_miibus_readreg;
300: mii->mii_writereg = url_ext_miibus_writereg;
301: }
302: #endif
303: mii->mii_statchg = url_miibus_statchg;
304: mii->mii_flags = MIIF_AUTOTSLEEP;
305: ifmedia_init(&mii->mii_media, 0,
306: url_ifmedia_change, url_ifmedia_status);
307: mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
308: if (LIST_FIRST(&mii->mii_phys) == NULL) {
309: ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
310: ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
311: } else
312: ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
313:
314: /* attach the interface */
315: if_attach(ifp);
316: ether_ifattach(ifp);
317:
318: timeout_set(&sc->sc_stat_ch, NULL, NULL);
319: sc->sc_attached = 1;
320: splx(s);
321:
322: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, &sc->sc_dev);
323:
324: return;
325:
326: bad:
327: sc->sc_dying = 1;
328: }
329:
330: /* detach */
331: int
332: url_detach(struct device *self, int flags)
333: {
334: struct url_softc *sc = (struct url_softc *)self;
335: struct ifnet *ifp = GET_IFP(sc);
336: int s;
337:
338: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
339:
340: /* Detached before attached finished */
341: if (!sc->sc_attached)
342: return (0);
343:
344: timeout_del(&sc->sc_stat_ch);
345:
346: /* Remove any pending tasks */
347: usb_rem_task(sc->sc_udev, &sc->sc_tick_task);
348: usb_rem_task(sc->sc_udev, &sc->sc_stop_task);
349:
350: s = splusb();
351:
352: if (--sc->sc_refcnt >= 0) {
353: /* Wait for processes to go away */
354: usb_detach_wait(&sc->sc_dev);
355: }
356:
357: if (ifp->if_flags & IFF_RUNNING)
358: url_stop(GET_IFP(sc), 1);
359:
360: mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
361: ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
362: ether_ifdetach(ifp);
363: if_detach(ifp);
364:
365: #ifdef DIAGNOSTIC
366: if (sc->sc_pipe_tx != NULL)
367: printf("%s: detach has active tx endpoint.\n",
368: sc->sc_dev.dv_xname);
369: if (sc->sc_pipe_rx != NULL)
370: printf("%s: detach has active rx endpoint.\n",
371: sc->sc_dev.dv_xname);
372: if (sc->sc_pipe_intr != NULL)
373: printf("%s: detach has active intr endpoint.\n",
374: sc->sc_dev.dv_xname);
375: #endif
376:
377: sc->sc_attached = 0;
378:
379: splx(s);
380:
381: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
382: &sc->sc_dev);
383:
384: return (0);
385: }
386:
387: /* read/write memory */
388: int
389: url_mem(struct url_softc *sc, int cmd, int offset, void *buf, int len)
390: {
391: usb_device_request_t req;
392: usbd_status err;
393:
394: if (sc == NULL)
395: return (0);
396:
397: DPRINTFN(0x200,
398: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
399:
400: if (sc->sc_dying)
401: return (0);
402:
403: if (cmd == URL_CMD_READMEM)
404: req.bmRequestType = UT_READ_VENDOR_DEVICE;
405: else
406: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
407: req.bRequest = URL_REQ_MEM;
408: USETW(req.wValue, offset);
409: USETW(req.wIndex, 0x0000);
410: USETW(req.wLength, len);
411:
412: sc->sc_refcnt++;
413: err = usbd_do_request(sc->sc_udev, &req, buf);
414: if (--sc->sc_refcnt < 0)
415: usb_detach_wakeup(&sc->sc_dev);
416: if (err) {
417: DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n",
418: sc->sc_dev.dv_xname,
419: cmd == URL_CMD_READMEM ? "read" : "write",
420: offset, err));
421: }
422:
423: return (err);
424: }
425:
426: /* read 1byte from register */
427: int
428: url_csr_read_1(struct url_softc *sc, int reg)
429: {
430: u_int8_t val = 0;
431:
432: DPRINTFN(0x100,
433: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
434:
435: if (sc->sc_dying)
436: return (0);
437:
438: return (url_mem(sc, URL_CMD_READMEM, reg, &val, 1) ? 0 : val);
439: }
440:
441: /* read 2bytes from register */
442: int
443: url_csr_read_2(struct url_softc *sc, int reg)
444: {
445: uWord val;
446:
447: DPRINTFN(0x100,
448: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
449:
450: if (sc->sc_dying)
451: return (0);
452:
453: USETW(val, 0);
454: return (url_mem(sc, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val));
455: }
456:
457: /* write 1byte to register */
458: int
459: url_csr_write_1(struct url_softc *sc, int reg, int aval)
460: {
461: u_int8_t val = aval;
462:
463: DPRINTFN(0x100,
464: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
465:
466: if (sc->sc_dying)
467: return (0);
468:
469: return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0);
470: }
471:
472: /* write 2bytes to register */
473: int
474: url_csr_write_2(struct url_softc *sc, int reg, int aval)
475: {
476: uWord val;
477:
478: DPRINTFN(0x100,
479: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
480:
481: USETW(val, aval);
482:
483: if (sc->sc_dying)
484: return (0);
485:
486: return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0);
487: }
488:
489: /* write 4bytes to register */
490: int
491: url_csr_write_4(struct url_softc *sc, int reg, int aval)
492: {
493: uDWord val;
494:
495: DPRINTFN(0x100,
496: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
497:
498: USETDW(val, aval);
499:
500: if (sc->sc_dying)
501: return (0);
502:
503: return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0);
504: }
505:
506: int
507: url_init(struct ifnet *ifp)
508: {
509: struct url_softc *sc = ifp->if_softc;
510: struct mii_data *mii = GET_MII(sc);
511: u_char *eaddr;
512: int i, s;
513:
514: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
515:
516: if (sc->sc_dying)
517: return (EIO);
518:
519: s = splnet();
520:
521: /* Cancel pending I/O and free all TX/RX buffers */
522: url_stop(ifp, 1);
523:
524: eaddr = sc->sc_ac.ac_enaddr;
525: for (i = 0; i < ETHER_ADDR_LEN; i++)
526: url_csr_write_1(sc, URL_IDR0 + i, eaddr[i]);
527:
528: /* Init transmission control register */
529: URL_CLRBIT(sc, URL_TCR,
530: URL_TCR_TXRR1 | URL_TCR_TXRR0 |
531: URL_TCR_IFG1 | URL_TCR_IFG0 |
532: URL_TCR_NOCRC);
533:
534: /* Init receive control register */
535: URL_SETBIT2(sc, URL_RCR, URL_RCR_TAIL | URL_RCR_AD);
536: if (ifp->if_flags & IFF_BROADCAST)
537: URL_SETBIT2(sc, URL_RCR, URL_RCR_AB);
538: else
539: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AB);
540:
541: /* If we want promiscuous mode, accept all physical frames. */
542: if (ifp->if_flags & IFF_PROMISC)
543: URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
544: else
545: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
546:
547:
548: /* Initialize transmit ring */
549: if (url_tx_list_init(sc) == ENOBUFS) {
550: printf("%s: tx list init failed\n", sc->sc_dev.dv_xname);
551: splx(s);
552: return (EIO);
553: }
554:
555: /* Initialize receive ring */
556: if (url_rx_list_init(sc) == ENOBUFS) {
557: printf("%s: rx list init failed\n", sc->sc_dev.dv_xname);
558: splx(s);
559: return (EIO);
560: }
561:
562: /* Load the multicast filter */
563: url_setmulti(sc);
564:
565: /* Enable RX and TX */
566: URL_SETBIT(sc, URL_CR, URL_CR_TE | URL_CR_RE);
567:
568: mii_mediachg(mii);
569:
570: if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) {
571: if (url_openpipes(sc)) {
572: splx(s);
573: return (EIO);
574: }
575: }
576:
577: ifp->if_flags |= IFF_RUNNING;
578: ifp->if_flags &= ~IFF_OACTIVE;
579:
580: splx(s);
581:
582: timeout_del(&sc->sc_stat_ch);
583: timeout_set(&sc->sc_stat_ch, url_tick, sc);
584: timeout_add(&sc->sc_stat_ch, hz);
585:
586: return (0);
587: }
588:
589: void
590: url_reset(struct url_softc *sc)
591: {
592: int i;
593:
594: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
595:
596: if (sc->sc_dying)
597: return;
598:
599: URL_SETBIT(sc, URL_CR, URL_CR_SOFT_RST);
600:
601: for (i = 0; i < URL_TX_TIMEOUT; i++) {
602: if (!(url_csr_read_1(sc, URL_CR) & URL_CR_SOFT_RST))
603: break;
604: delay(10); /* XXX */
605: }
606:
607: delay(10000); /* XXX */
608: }
609:
610: int
611: url_activate(struct device *self, enum devact act)
612: {
613: struct url_softc *sc = (struct url_softc *)self;
614:
615: DPRINTF(("%s: %s: enter, act=%d\n", sc->sc_dev.dv_xname,
616: __func__, act));
617:
618: switch (act) {
619: case DVACT_ACTIVATE:
620: break;
621:
622: case DVACT_DEACTIVATE:
623: sc->sc_dying = 1;
624: break;
625: }
626:
627: return (0);
628: }
629:
630: #define url_calchash(addr) (ether_crc32_be((addr), ETHER_ADDR_LEN) >> 26)
631:
632:
633: void
634: url_setmulti(struct url_softc *sc)
635: {
636: struct ifnet *ifp;
637: struct ether_multi *enm;
638: struct ether_multistep step;
639: u_int32_t hashes[2] = { 0, 0 };
640: int h = 0;
641: int mcnt = 0;
642:
643: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
644:
645: if (sc->sc_dying)
646: return;
647:
648: ifp = GET_IFP(sc);
649:
650: if (ifp->if_flags & IFF_PROMISC) {
651: URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
652: return;
653: } else if (ifp->if_flags & IFF_ALLMULTI) {
654: allmulti:
655: ifp->if_flags |= IFF_ALLMULTI;
656: URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM);
657: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAP);
658: return;
659: }
660:
661: /* first, zot all the existing hash bits */
662: url_csr_write_4(sc, URL_MAR0, 0);
663: url_csr_write_4(sc, URL_MAR4, 0);
664:
665: /* now program new ones */
666: ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
667: while (enm != NULL) {
668: if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
669: ETHER_ADDR_LEN) != 0)
670: goto allmulti;
671:
672: h = url_calchash(enm->enm_addrlo);
673: if (h < 32)
674: hashes[0] |= (1 << h);
675: else
676: hashes[1] |= (1 << (h -32));
677: mcnt++;
678: ETHER_NEXT_MULTI(step, enm);
679: }
680:
681: ifp->if_flags &= ~IFF_ALLMULTI;
682:
683: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
684:
685: if (mcnt){
686: URL_SETBIT2(sc, URL_RCR, URL_RCR_AM);
687: } else {
688: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AM);
689: }
690: url_csr_write_4(sc, URL_MAR0, hashes[0]);
691: url_csr_write_4(sc, URL_MAR4, hashes[1]);
692: }
693:
694: int
695: url_openpipes(struct url_softc *sc)
696: {
697: struct url_chain *c;
698: usbd_status err;
699: int i;
700: int error = 0;
701:
702: if (sc->sc_dying)
703: return (EIO);
704:
705: sc->sc_refcnt++;
706:
707: /* Open RX pipe */
708: err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkin_no,
709: USBD_EXCLUSIVE_USE, &sc->sc_pipe_rx);
710: if (err) {
711: printf("%s: open rx pipe failed: %s\n",
712: sc->sc_dev.dv_xname, usbd_errstr(err));
713: error = EIO;
714: goto done;
715: }
716:
717: /* Open TX pipe */
718: err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkout_no,
719: USBD_EXCLUSIVE_USE, &sc->sc_pipe_tx);
720: if (err) {
721: printf("%s: open tx pipe failed: %s\n",
722: sc->sc_dev.dv_xname, usbd_errstr(err));
723: error = EIO;
724: goto done;
725: }
726:
727: #if 0
728: /* XXX: interrupt endpoint is not yet supported */
729: /* Open Interrupt pipe */
730: err = usbd_open_pipe_intr(sc->sc_ctl_iface, sc->sc_intrin_no,
731: USBD_EXCLUSIVE_USE, &sc->sc_pipe_intr, sc,
732: &sc->sc_cdata.url_ibuf, URL_INTR_PKGLEN,
733: url_intr, URL_INTR_INTERVAL);
734: if (err) {
735: printf("%s: open intr pipe failed: %s\n",
736: sc->sc_dev.dv_xname, usbd_errstr(err));
737: error = EIO;
738: goto done;
739: }
740: #endif
741:
742:
743: /* Start up the receive pipe. */
744: for (i = 0; i < URL_RX_LIST_CNT; i++) {
745: c = &sc->sc_cdata.url_rx_chain[i];
746: usbd_setup_xfer(c->url_xfer, sc->sc_pipe_rx,
747: c, c->url_buf, URL_BUFSZ,
748: USBD_SHORT_XFER_OK | USBD_NO_COPY,
749: USBD_NO_TIMEOUT, url_rxeof);
750: (void)usbd_transfer(c->url_xfer);
751: DPRINTF(("%s: %s: start read\n", sc->sc_dev.dv_xname,
752: __func__));
753: }
754:
755: done:
756: if (--sc->sc_refcnt < 0)
757: usb_detach_wakeup(&sc->sc_dev);
758:
759: return (error);
760: }
761:
762: int
763: url_newbuf(struct url_softc *sc, struct url_chain *c, struct mbuf *m)
764: {
765: struct mbuf *m_new = NULL;
766:
767: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
768:
769: if (m == NULL) {
770: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
771: if (m_new == NULL) {
772: printf("%s: no memory for rx list "
773: "-- packet dropped!\n", sc->sc_dev.dv_xname);
774: return (ENOBUFS);
775: }
776: MCLGET(m_new, M_DONTWAIT);
777: if (!(m_new->m_flags & M_EXT)) {
778: printf("%s: no memory for rx list "
779: "-- packet dropped!\n", sc->sc_dev.dv_xname);
780: m_freem(m_new);
781: return (ENOBUFS);
782: }
783: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
784: } else {
785: m_new = m;
786: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
787: m_new->m_data = m_new->m_ext.ext_buf;
788: }
789:
790: m_adj(m_new, ETHER_ALIGN);
791: c->url_mbuf = m_new;
792:
793: return (0);
794: }
795:
796:
797: int
798: url_rx_list_init(struct url_softc *sc)
799: {
800: struct url_cdata *cd;
801: struct url_chain *c;
802: int i;
803:
804: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
805:
806: cd = &sc->sc_cdata;
807: for (i = 0; i < URL_RX_LIST_CNT; i++) {
808: c = &cd->url_rx_chain[i];
809: c->url_sc = sc;
810: c->url_idx = i;
811: if (url_newbuf(sc, c, NULL) == ENOBUFS)
812: return (ENOBUFS);
813: if (c->url_xfer == NULL) {
814: c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
815: if (c->url_xfer == NULL)
816: return (ENOBUFS);
817: c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
818: if (c->url_buf == NULL) {
819: usbd_free_xfer(c->url_xfer);
820: return (ENOBUFS);
821: }
822: }
823: }
824:
825: return (0);
826: }
827:
828: int
829: url_tx_list_init(struct url_softc *sc)
830: {
831: struct url_cdata *cd;
832: struct url_chain *c;
833: int i;
834:
835: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
836:
837: cd = &sc->sc_cdata;
838: for (i = 0; i < URL_TX_LIST_CNT; i++) {
839: c = &cd->url_tx_chain[i];
840: c->url_sc = sc;
841: c->url_idx = i;
842: c->url_mbuf = NULL;
843: if (c->url_xfer == NULL) {
844: c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
845: if (c->url_xfer == NULL)
846: return (ENOBUFS);
847: c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
848: if (c->url_buf == NULL) {
849: usbd_free_xfer(c->url_xfer);
850: return (ENOBUFS);
851: }
852: }
853: }
854:
855: return (0);
856: }
857:
858: void
859: url_start(struct ifnet *ifp)
860: {
861: struct url_softc *sc = ifp->if_softc;
862: struct mbuf *m_head = NULL;
863:
864: DPRINTF(("%s: %s: enter, link=%d\n", sc->sc_dev.dv_xname,
865: __func__, sc->sc_link));
866:
867: if (sc->sc_dying)
868: return;
869:
870: if (!sc->sc_link)
871: return;
872:
873: if (ifp->if_flags & IFF_OACTIVE)
874: return;
875:
876: IFQ_POLL(&ifp->if_snd, m_head);
877: if (m_head == NULL)
878: return;
879:
880: if (url_send(sc, m_head, 0)) {
881: ifp->if_flags |= IFF_OACTIVE;
882: return;
883: }
884:
885: IFQ_DEQUEUE(&ifp->if_snd, m_head);
886:
887: #if NBPFILTER > 0
888: if (ifp->if_bpf)
889: bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
890: #endif
891:
892: ifp->if_flags |= IFF_OACTIVE;
893:
894: /* Set a timeout in case the chip goes out to lunch. */
895: ifp->if_timer = 5;
896: }
897:
898: int
899: url_send(struct url_softc *sc, struct mbuf *m, int idx)
900: {
901: int total_len;
902: struct url_chain *c;
903: usbd_status err;
904:
905: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
906:
907: c = &sc->sc_cdata.url_tx_chain[idx];
908:
909: /* Copy the mbuf data into a contiguous buffer */
910: m_copydata(m, 0, m->m_pkthdr.len, c->url_buf);
911: c->url_mbuf = m;
912: total_len = m->m_pkthdr.len;
913:
914: if (total_len < URL_MIN_FRAME_LEN) {
915: bzero(c->url_buf + total_len, URL_MIN_FRAME_LEN - total_len);
916: total_len = URL_MIN_FRAME_LEN;
917: }
918: usbd_setup_xfer(c->url_xfer, sc->sc_pipe_tx, c, c->url_buf, total_len,
919: USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
920: URL_TX_TIMEOUT, url_txeof);
921:
922: /* Transmit */
923: sc->sc_refcnt++;
924: err = usbd_transfer(c->url_xfer);
925: if (--sc->sc_refcnt < 0)
926: usb_detach_wakeup(&sc->sc_dev);
927: if (err != USBD_IN_PROGRESS) {
928: printf("%s: url_send error=%s\n", sc->sc_dev.dv_xname,
929: usbd_errstr(err));
930: /* Stop the interface */
931: usb_add_task(sc->sc_udev, &sc->sc_stop_task);
932: return (EIO);
933: }
934:
935: DPRINTF(("%s: %s: send %d bytes\n", sc->sc_dev.dv_xname,
936: __func__, total_len));
937:
938: sc->sc_cdata.url_tx_cnt++;
939:
940: return (0);
941: }
942:
943: void
944: url_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
945: {
946: struct url_chain *c = priv;
947: struct url_softc *sc = c->url_sc;
948: struct ifnet *ifp = GET_IFP(sc);
949: int s;
950:
951: if (sc->sc_dying)
952: return;
953:
954: s = splnet();
955:
956: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
957:
958: ifp->if_timer = 0;
959: ifp->if_flags &= ~IFF_OACTIVE;
960:
961: if (status != USBD_NORMAL_COMPLETION) {
962: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
963: splx(s);
964: return;
965: }
966: ifp->if_oerrors++;
967: printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname,
968: usbd_errstr(status));
969: if (status == USBD_STALLED) {
970: sc->sc_refcnt++;
971: usbd_clear_endpoint_stall_async(sc->sc_pipe_tx);
972: if (--sc->sc_refcnt < 0)
973: usb_detach_wakeup(&sc->sc_dev);
974: }
975: splx(s);
976: return;
977: }
978:
979: ifp->if_opackets++;
980:
981: m_freem(c->url_mbuf);
982: c->url_mbuf = NULL;
983:
984: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
985: url_start(ifp);
986:
987: splx(s);
988: }
989:
990: void
991: url_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
992: {
993: struct url_chain *c = priv;
994: struct url_softc *sc = c->url_sc;
995: struct ifnet *ifp = GET_IFP(sc);
996: struct mbuf *m;
997: u_int32_t total_len;
998: url_rxhdr_t rxhdr;
999: int s;
1000:
1001: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
1002:
1003: if (sc->sc_dying)
1004: return;
1005:
1006: if (status != USBD_NORMAL_COMPLETION) {
1007: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1008: return;
1009: sc->sc_rx_errs++;
1010: if (usbd_ratecheck(&sc->sc_rx_notice)) {
1011: printf("%s: %u usb errors on rx: %s\n",
1012: sc->sc_dev.dv_xname, sc->sc_rx_errs,
1013: usbd_errstr(status));
1014: sc->sc_rx_errs = 0;
1015: }
1016: if (status == USBD_STALLED) {
1017: sc->sc_refcnt++;
1018: usbd_clear_endpoint_stall_async(sc->sc_pipe_rx);
1019: if (--sc->sc_refcnt < 0)
1020: usb_detach_wakeup(&sc->sc_dev);
1021: }
1022: goto done;
1023: }
1024:
1025: usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
1026:
1027: memcpy(mtod(c->url_mbuf, char *), c->url_buf, total_len);
1028:
1029: if (total_len <= ETHER_CRC_LEN) {
1030: ifp->if_ierrors++;
1031: goto done;
1032: }
1033:
1034: memcpy(&rxhdr, c->url_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr));
1035:
1036: DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n",
1037: sc->sc_dev.dv_xname,
1038: UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK,
1039: UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "",
1040: UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "",
1041: UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "",
1042: UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : ""));
1043:
1044: if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) {
1045: ifp->if_ierrors++;
1046: goto done;
1047: }
1048:
1049: ifp->if_ipackets++;
1050: total_len -= ETHER_CRC_LEN;
1051:
1052: m = c->url_mbuf;
1053: m->m_pkthdr.len = m->m_len = total_len;
1054: m->m_pkthdr.rcvif = ifp;
1055:
1056: s = splnet();
1057:
1058: if (url_newbuf(sc, c, NULL) == ENOBUFS) {
1059: ifp->if_ierrors++;
1060: goto done1;
1061: }
1062:
1063: #if NBPFILTER > 0
1064: if (ifp->if_bpf)
1065: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
1066: #endif
1067:
1068: DPRINTF(("%s: %s: deliver %d\n", sc->sc_dev.dv_xname,
1069: __func__, m->m_len));
1070: ether_input_mbuf(ifp, m);
1071:
1072: done1:
1073: splx(s);
1074:
1075: done:
1076: /* Setup new transfer */
1077: usbd_setup_xfer(xfer, sc->sc_pipe_rx, c, c->url_buf, URL_BUFSZ,
1078: USBD_SHORT_XFER_OK | USBD_NO_COPY,
1079: USBD_NO_TIMEOUT, url_rxeof);
1080: sc->sc_refcnt++;
1081: usbd_transfer(xfer);
1082: if (--sc->sc_refcnt < 0)
1083: usb_detach_wakeup(&sc->sc_dev);
1084:
1085: DPRINTF(("%s: %s: start rx\n", sc->sc_dev.dv_xname, __func__));
1086: }
1087:
1088: #if 0
1089: void url_intr()
1090: {
1091: }
1092: #endif
1093:
1094: int
1095: url_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1096: {
1097: struct url_softc *sc = ifp->if_softc;
1098: struct ifaddr *ifa = (struct ifaddr *)data;
1099: struct ifreq *ifr = (struct ifreq *)data;
1100: struct mii_data *mii;
1101: int s, error = 0;
1102:
1103: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1104:
1105: if (sc->sc_dying)
1106: return (EIO);
1107:
1108: s = splnet();
1109:
1110: switch (cmd) {
1111: case SIOCSIFADDR:
1112: ifp->if_flags |= IFF_UP;
1113: url_init(ifp);
1114:
1115: switch (ifa->ifa_addr->sa_family) {
1116: #ifdef INET
1117: case AF_INET:
1118: arp_ifinit(&sc->sc_ac, ifa);
1119: break;
1120: #endif /* INET */
1121: }
1122: break;
1123:
1124: case SIOCSIFMTU:
1125: if (ifr->ifr_mtu > ETHERMTU)
1126: error = EINVAL;
1127: else
1128: ifp->if_mtu = ifr->ifr_mtu;
1129: break;
1130:
1131: case SIOCSIFFLAGS:
1132: if (ifp->if_flags & IFF_UP) {
1133: if (ifp->if_flags & IFF_RUNNING &&
1134: ifp->if_flags & IFF_PROMISC) {
1135: URL_SETBIT2(sc, URL_RCR,
1136: URL_RCR_AAM|URL_RCR_AAP);
1137: } else if (ifp->if_flags & IFF_RUNNING &&
1138: !(ifp->if_flags & IFF_PROMISC)) {
1139: URL_CLRBIT2(sc, URL_RCR,
1140: URL_RCR_AAM|URL_RCR_AAP);
1141: } else if (!(ifp->if_flags & IFF_RUNNING))
1142: url_init(ifp);
1143: } else {
1144: if (ifp->if_flags & IFF_RUNNING)
1145: url_stop(ifp, 1);
1146: }
1147: error = 0;
1148: break;
1149: case SIOCADDMULTI:
1150: case SIOCDELMULTI:
1151: error = (cmd == SIOCADDMULTI) ?
1152: ether_addmulti(ifr, &sc->sc_ac) :
1153: ether_delmulti(ifr, &sc->sc_ac);
1154:
1155: if (error == ENETRESET) {
1156: if (ifp->if_flags & IFF_RUNNING)
1157: url_setmulti(sc);
1158: error = 0;
1159: }
1160: break;
1161: case SIOCGIFMEDIA:
1162: case SIOCSIFMEDIA:
1163: mii = GET_MII(sc);
1164: error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1165: break;
1166: default:
1167: error = EINVAL;
1168: break;
1169: }
1170:
1171: splx(s);
1172:
1173: return (error);
1174: }
1175:
1176: void
1177: url_watchdog(struct ifnet *ifp)
1178: {
1179: struct url_softc *sc = ifp->if_softc;
1180: struct url_chain *c;
1181: usbd_status stat;
1182: int s;
1183:
1184: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1185:
1186: ifp->if_oerrors++;
1187: printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
1188:
1189: s = splusb();
1190: c = &sc->sc_cdata.url_tx_chain[0];
1191: usbd_get_xfer_status(c->url_xfer, NULL, NULL, NULL, &stat);
1192: url_txeof(c->url_xfer, c, stat);
1193:
1194: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1195: url_start(ifp);
1196: splx(s);
1197: }
1198:
1199: void
1200: url_stop_task(struct url_softc *sc)
1201: {
1202: url_stop(GET_IFP(sc), 1);
1203: }
1204:
1205: /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
1206: void
1207: url_stop(struct ifnet *ifp, int disable)
1208: {
1209: struct url_softc *sc = ifp->if_softc;
1210: usbd_status err;
1211: int i;
1212:
1213: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1214:
1215: ifp->if_timer = 0;
1216: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1217:
1218: url_reset(sc);
1219:
1220: timeout_del(&sc->sc_stat_ch);
1221:
1222: /* Stop transfers */
1223: /* RX endpoint */
1224: if (sc->sc_pipe_rx != NULL) {
1225: err = usbd_abort_pipe(sc->sc_pipe_rx);
1226: if (err)
1227: printf("%s: abort rx pipe failed: %s\n",
1228: sc->sc_dev.dv_xname, usbd_errstr(err));
1229: err = usbd_close_pipe(sc->sc_pipe_rx);
1230: if (err)
1231: printf("%s: close rx pipe failed: %s\n",
1232: sc->sc_dev.dv_xname, usbd_errstr(err));
1233: sc->sc_pipe_rx = NULL;
1234: }
1235:
1236: /* TX endpoint */
1237: if (sc->sc_pipe_tx != NULL) {
1238: err = usbd_abort_pipe(sc->sc_pipe_tx);
1239: if (err)
1240: printf("%s: abort tx pipe failed: %s\n",
1241: sc->sc_dev.dv_xname, usbd_errstr(err));
1242: err = usbd_close_pipe(sc->sc_pipe_tx);
1243: if (err)
1244: printf("%s: close tx pipe failed: %s\n",
1245: sc->sc_dev.dv_xname, usbd_errstr(err));
1246: sc->sc_pipe_tx = NULL;
1247: }
1248:
1249: #if 0
1250: /* XXX: Interrupt endpoint is not yet supported!! */
1251: /* Interrupt endpoint */
1252: if (sc->sc_pipe_intr != NULL) {
1253: err = usbd_abort_pipe(sc->sc_pipe_intr);
1254: if (err)
1255: printf("%s: abort intr pipe failed: %s\n",
1256: sc->sc_dev.dv_xname, usbd_errstr(err));
1257: err = usbd_close_pipe(sc->sc_pipe_intr);
1258: if (err)
1259: printf("%s: close intr pipe failed: %s\n",
1260: sc->sc_dev.dv_xname, usbd_errstr(err));
1261: sc->sc_pipe_intr = NULL;
1262: }
1263: #endif
1264:
1265: /* Free RX resources. */
1266: for (i = 0; i < URL_RX_LIST_CNT; i++) {
1267: if (sc->sc_cdata.url_rx_chain[i].url_mbuf != NULL) {
1268: m_freem(sc->sc_cdata.url_rx_chain[i].url_mbuf);
1269: sc->sc_cdata.url_rx_chain[i].url_mbuf = NULL;
1270: }
1271: if (sc->sc_cdata.url_rx_chain[i].url_xfer != NULL) {
1272: usbd_free_xfer(sc->sc_cdata.url_rx_chain[i].url_xfer);
1273: sc->sc_cdata.url_rx_chain[i].url_xfer = NULL;
1274: }
1275: }
1276:
1277: /* Free TX resources. */
1278: for (i = 0; i < URL_TX_LIST_CNT; i++) {
1279: if (sc->sc_cdata.url_tx_chain[i].url_mbuf != NULL) {
1280: m_freem(sc->sc_cdata.url_tx_chain[i].url_mbuf);
1281: sc->sc_cdata.url_tx_chain[i].url_mbuf = NULL;
1282: }
1283: if (sc->sc_cdata.url_tx_chain[i].url_xfer != NULL) {
1284: usbd_free_xfer(sc->sc_cdata.url_tx_chain[i].url_xfer);
1285: sc->sc_cdata.url_tx_chain[i].url_xfer = NULL;
1286: }
1287: }
1288:
1289: sc->sc_link = 0;
1290: }
1291:
1292: /* Set media options */
1293: int
1294: url_ifmedia_change(struct ifnet *ifp)
1295: {
1296: struct url_softc *sc = ifp->if_softc;
1297: struct mii_data *mii = GET_MII(sc);
1298:
1299: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1300:
1301: if (sc->sc_dying)
1302: return (0);
1303:
1304: sc->sc_link = 0;
1305: if (mii->mii_instance) {
1306: struct mii_softc *miisc;
1307: for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
1308: miisc = LIST_NEXT(miisc, mii_list))
1309: mii_phy_reset(miisc);
1310: }
1311:
1312: return (mii_mediachg(mii));
1313: }
1314:
1315: /* Report current media status. */
1316: void
1317: url_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1318: {
1319: struct url_softc *sc = ifp->if_softc;
1320: struct mii_data *mii = GET_MII(sc);
1321:
1322: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1323:
1324: if (sc->sc_dying)
1325: return;
1326:
1327: if ((ifp->if_flags & IFF_RUNNING) == 0) {
1328: ifmr->ifm_active = IFM_ETHER | IFM_NONE;
1329: ifmr->ifm_status = 0;
1330: return;
1331: }
1332:
1333: mii_pollstat(mii);
1334: ifmr->ifm_active = mii->mii_media_active;
1335: ifmr->ifm_status = mii->mii_media_status;
1336: }
1337:
1338: void
1339: url_tick(void *xsc)
1340: {
1341: struct url_softc *sc = xsc;
1342:
1343: if (sc == NULL)
1344: return;
1345:
1346: DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
1347: __func__));
1348:
1349: if (sc->sc_dying)
1350: return;
1351:
1352: /* Perform periodic stuff in process context */
1353: usb_add_task(sc->sc_udev, &sc->sc_tick_task);
1354: }
1355:
1356: void
1357: url_tick_task(void *xsc)
1358: {
1359: struct url_softc *sc = xsc;
1360: struct ifnet *ifp;
1361: struct mii_data *mii;
1362: int s;
1363:
1364: if (sc == NULL)
1365: return;
1366:
1367: DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
1368: __func__));
1369:
1370: if (sc->sc_dying)
1371: return;
1372:
1373: ifp = GET_IFP(sc);
1374: mii = GET_MII(sc);
1375:
1376: if (mii == NULL)
1377: return;
1378:
1379: s = splnet();
1380:
1381: mii_tick(mii);
1382: if (!sc->sc_link && mii->mii_media_status & IFM_ACTIVE &&
1383: IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
1384: DPRINTF(("%s: %s: got link\n",
1385: sc->sc_dev.dv_xname, __func__));
1386: sc->sc_link++;
1387: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1388: url_start(ifp);
1389: }
1390:
1391: timeout_del(&sc->sc_stat_ch);
1392: timeout_set(&sc->sc_stat_ch, url_tick, sc);
1393: timeout_add(&sc->sc_stat_ch, hz);
1394:
1395: splx(s);
1396: }
1397:
1398: /* Get exclusive access to the MII registers */
1399: void
1400: url_lock_mii(struct url_softc *sc)
1401: {
1402: DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
1403: __func__));
1404:
1405: sc->sc_refcnt++;
1406: rw_enter_write(&sc->sc_mii_lock);
1407: }
1408:
1409: void
1410: url_unlock_mii(struct url_softc *sc)
1411: {
1412: DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
1413: __func__));
1414:
1415: rw_exit_write(&sc->sc_mii_lock);
1416: if (--sc->sc_refcnt < 0)
1417: usb_detach_wakeup(&sc->sc_dev);
1418: }
1419:
1420: int
1421: url_int_miibus_readreg(struct device *dev, int phy, int reg)
1422: {
1423: struct url_softc *sc;
1424: u_int16_t val;
1425:
1426: if (dev == NULL)
1427: return (0);
1428:
1429: sc = (void *)dev;
1430:
1431: DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n",
1432: sc->sc_dev.dv_xname, __func__, phy, reg));
1433:
1434: if (sc->sc_dying) {
1435: #ifdef DIAGNOSTIC
1436: printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
1437: __func__);
1438: #endif
1439: return (0);
1440: }
1441:
1442: /* XXX: one PHY only for the RTL8150 internal PHY */
1443: if (phy != 0) {
1444: DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
1445: sc->sc_dev.dv_xname, __func__, phy));
1446: return (0);
1447: }
1448:
1449: url_lock_mii(sc);
1450:
1451: switch (reg) {
1452: case MII_BMCR: /* Control Register */
1453: reg = URL_BMCR;
1454: break;
1455: case MII_BMSR: /* Status Register */
1456: reg = URL_BMSR;
1457: break;
1458: case MII_PHYIDR1:
1459: case MII_PHYIDR2:
1460: val = 0;
1461: goto R_DONE;
1462: break;
1463: case MII_ANAR: /* Autonegotiation advertisement */
1464: reg = URL_ANAR;
1465: break;
1466: case MII_ANLPAR: /* Autonegotiation link partner abilities */
1467: reg = URL_ANLP;
1468: break;
1469: case URLPHY_MSR: /* Media Status Register */
1470: reg = URL_MSR;
1471: break;
1472: default:
1473: printf("%s: %s: bad register %04x\n",
1474: sc->sc_dev.dv_xname, __func__, reg);
1475: val = 0;
1476: goto R_DONE;
1477: break;
1478: }
1479:
1480: if (reg == URL_MSR)
1481: val = url_csr_read_1(sc, reg);
1482: else
1483: val = url_csr_read_2(sc, reg);
1484:
1485: R_DONE:
1486: DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
1487: sc->sc_dev.dv_xname, __func__, phy, reg, val));
1488:
1489: url_unlock_mii(sc);
1490: return (val);
1491: }
1492:
1493: void
1494: url_int_miibus_writereg(struct device *dev, int phy, int reg, int data)
1495: {
1496: struct url_softc *sc;
1497:
1498: if (dev == NULL)
1499: return;
1500:
1501: sc = (void *)dev;
1502:
1503: DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
1504: sc->sc_dev.dv_xname, __func__, phy, reg, data));
1505:
1506: if (sc->sc_dying) {
1507: #ifdef DIAGNOSTIC
1508: printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
1509: __func__);
1510: #endif
1511: return;
1512: }
1513:
1514: /* XXX: one PHY only for the RTL8150 internal PHY */
1515: if (phy != 0) {
1516: DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
1517: sc->sc_dev.dv_xname, __func__, phy));
1518: return;
1519: }
1520:
1521: url_lock_mii(sc);
1522:
1523: switch (reg) {
1524: case MII_BMCR: /* Control Register */
1525: reg = URL_BMCR;
1526: break;
1527: case MII_BMSR: /* Status Register */
1528: reg = URL_BMSR;
1529: break;
1530: case MII_PHYIDR1:
1531: case MII_PHYIDR2:
1532: goto W_DONE;
1533: break;
1534: case MII_ANAR: /* Autonegotiation advertisement */
1535: reg = URL_ANAR;
1536: break;
1537: case MII_ANLPAR: /* Autonegotiation link partner abilities */
1538: reg = URL_ANLP;
1539: break;
1540: case URLPHY_MSR: /* Media Status Register */
1541: reg = URL_MSR;
1542: break;
1543: default:
1544: printf("%s: %s: bad register %04x\n",
1545: sc->sc_dev.dv_xname, __func__, reg);
1546: goto W_DONE;
1547: break;
1548: }
1549:
1550: if (reg == URL_MSR)
1551: url_csr_write_1(sc, reg, data);
1552: else
1553: url_csr_write_2(sc, reg, data);
1554: W_DONE:
1555:
1556: url_unlock_mii(sc);
1557: return;
1558: }
1559:
1560: void
1561: url_miibus_statchg(struct device *dev)
1562: {
1563: #ifdef URL_DEBUG
1564: struct url_softc *sc;
1565:
1566: if (dev == NULL)
1567: return;
1568:
1569: sc = (void *)dev;
1570: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1571: #endif
1572: /* Nothing to do */
1573: }
1574:
1575: #if 0
1576: /*
1577: * external PHYs support, but not test.
1578: */
1579: int
1580: url_ext_miibus_redreg(struct device *dev, int phy, int reg)
1581: {
1582: struct url_softc *sc = (void *)dev;
1583: u_int16_t val;
1584:
1585: DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n",
1586: sc->sc_dev.dv_xname, __func__, phy, reg));
1587:
1588: if (sc->sc_dying) {
1589: #ifdef DIAGNOSTIC
1590: printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
1591: __func__);
1592: #endif
1593: return (0);
1594: }
1595:
1596: url_lock_mii(sc);
1597:
1598: url_csr_write_1(sc, URL_PHYADD, phy & URL_PHYADD_MASK);
1599: /*
1600: * RTL8150L will initiate a MII management data transaction
1601: * if PHYCNT_OWN bit is set 1 by software. After transaction,
1602: * this bit is auto cleared by TRL8150L.
1603: */
1604: url_csr_write_1(sc, URL_PHYCNT,
1605: (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR);
1606: for (i = 0; i < URL_TIMEOUT; i++) {
1607: if ((url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0)
1608: break;
1609: }
1610: if (i == URL_TIMEOUT) {
1611: printf("%s: MII read timed out\n", sc->sc_dev.dv_xname);
1612: }
1613:
1614: val = url_csr_read_2(sc, URL_PHYDAT);
1615:
1616: DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
1617: sc->sc_dev.dv_xname, __func__, phy, reg, val));
1618:
1619: url_unlock_mii(sc);
1620: return (val);
1621: }
1622:
1623: void
1624: url_ext_miibus_writereg(struct device *dev, int phy, int reg, int data)
1625: {
1626: struct url_softc *sc = (void *)dev;
1627:
1628: DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
1629: sc->sc_dev.dv_xname, __func__, phy, reg, data));
1630:
1631: if (sc->sc_dying) {
1632: #ifdef DIAGNOSTIC
1633: printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
1634: __func__);
1635: #endif
1636: return;
1637: }
1638:
1639: url_lock_mii(sc);
1640:
1641: url_csr_write_2(sc, URL_PHYDAT, data);
1642: url_csr_write_1(sc, URL_PHYADD, phy);
1643: url_csr_write_1(sc, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */
1644:
1645: for (i=0; i < URL_TIMEOUT; i++) {
1646: if (url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN)
1647: break;
1648: }
1649:
1650: if (i == URL_TIMEOUT) {
1651: printf("%s: MII write timed out\n",
1652: sc->sc_dev.dv_xname);
1653: }
1654:
1655: url_unlock_mii(sc);
1656: return;
1657: }
1658: #endif
1659:
CVSweb