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