1 /* $OpenBSD: if_mos.c,v 1.44 2024/05/23 03:21:08 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org>
21 *
22 * Permission to use, copy, modify, and distribute this software for any
23 * purpose with or without fee is hereby granted, provided that the above
24 * copyright notice and this permission notice appear in all copies.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
27 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
29 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
30 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
31 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 */
34
35 /*
36 * Copyright (c) 1997, 1998, 1999, 2000-2003
37 * Bill Paul <wpaul@windriver.com>. All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 * must display the following acknowledgement:
49 * This product includes software developed by Bill Paul.
50 * 4. Neither the name of the author nor the names of any co-contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
64 * THE POSSIBILITY OF SUCH DAMAGE.
65 */
66
67 /*
68 * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller
69 * The datasheet is available at the following URL:
70 * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf
71 */
72
73 #include "bpfilter.h"
74
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/sockio.h>
78 #include <sys/rwlock.h>
79 #include <sys/mbuf.h>
80
81 #include <sys/device.h>
82
83 #include <machine/bus.h>
84
85 #include <net/if.h>
86 #include <net/if_media.h>
87
88 #if NBPFILTER > 0
89 #include <net/bpf.h>
90 #endif
91
92 #include <netinet/in.h>
93 #include <netinet/if_ether.h>
94
95 #include <dev/mii/miivar.h>
96
97 #include <dev/usb/usb.h>
98 #include <dev/usb/usbdi.h>
99 #include <dev/usb/usbdi_util.h>
100 #include <dev/usb/usbdevs.h>
101
102 #include <dev/usb/if_mosreg.h>
103
104 #ifdef MOS_DEBUG
105 #define DPRINTF(x) do { if (mosdebug) printf x; } while (0)
106 #define DPRINTFN(n,x) do { if (mosdebug >= (n)) printf x; } while (0)
107 int mosdebug = 0;
108 #else
109 #define DPRINTF(x)
110 #define DPRINTFN(n,x)
111 #endif
112
113 /*
114 * Various supported device vendors/products.
115 */
116 const struct mos_type mos_devs[] = {
117 { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730 }, MCS7730 },
118 { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830 }, MCS7830 },
119 { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832 }, MCS7832 },
120 { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030 }, MCS7830 },
121 };
122 #define mos_lookup(v, p) ((struct mos_type *)usb_lookup(mos_devs, v, p))
123
124 int mos_match(struct device *, void *, void *);
125 void mos_attach(struct device *, struct device *, void *);
126 int mos_detach(struct device *, int);
127
128 struct cfdriver mos_cd = {
129 NULL, "mos", DV_IFNET
130 };
131
132 const struct cfattach mos_ca = {
133 sizeof(struct mos_softc), mos_match, mos_attach, mos_detach
134 };
135
136 int mos_tx_list_init(struct mos_softc *);
137 int mos_rx_list_init(struct mos_softc *);
138 struct mbuf *mos_newbuf(void);
139 int mos_encap(struct mos_softc *, struct mbuf *, int);
140 void mos_rxeof(struct usbd_xfer *, void *, usbd_status);
141 void mos_txeof(struct usbd_xfer *, void *, usbd_status);
142 void mos_tick(void *);
143 void mos_tick_task(void *);
144 void mos_start(struct ifnet *);
145 int mos_ioctl(struct ifnet *, u_long, caddr_t);
146 void mos_init(void *);
147 void mos_chip_init(struct mos_softc *);
148 void mos_stop(struct mos_softc *);
149 void mos_watchdog(struct ifnet *);
150 int mos_miibus_readreg(struct device *, int, int);
151 void mos_miibus_writereg(struct device *, int, int, int);
152 void mos_miibus_statchg(struct device *);
153 int mos_ifmedia_upd(struct ifnet *);
154 void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *);
155 void mos_reset(struct mos_softc *sc);
156
157 int mos_reg_read_1(struct mos_softc *, int);
158 int mos_reg_read_2(struct mos_softc *, int);
159 int mos_reg_write_1(struct mos_softc *, int, int);
160 int mos_reg_write_2(struct mos_softc *, int, int);
161 int mos_readmac(struct mos_softc *, u_char *);
162 int mos_writemac(struct mos_softc *, u_char *);
163 int mos_write_mcast(struct mos_softc *, u_char *);
164
165 void mos_iff(struct mos_softc *);
166 void mos_lock_mii(struct mos_softc *);
167 void mos_unlock_mii(struct mos_softc *);
168
169 /*
170 * Get exclusive access to the MII registers
171 */
172 void
mos_lock_mii(struct mos_softc * sc)173 mos_lock_mii(struct mos_softc *sc)
174 {
175 sc->mos_refcnt++;
176 rw_enter_write(&sc->mos_mii_lock);
177 }
178
179 void
mos_unlock_mii(struct mos_softc * sc)180 mos_unlock_mii(struct mos_softc *sc)
181 {
182 rw_exit_write(&sc->mos_mii_lock);
183 if (--sc->mos_refcnt < 0)
184 usb_detach_wakeup(&sc->mos_dev);
185 }
186
187 int
mos_reg_read_1(struct mos_softc * sc,int reg)188 mos_reg_read_1(struct mos_softc *sc, int reg)
189 {
190 usb_device_request_t req;
191 usbd_status err;
192 uByte val = 0;
193
194 if (usbd_is_dying(sc->mos_udev))
195 return(0);
196
197 req.bmRequestType = UT_READ_VENDOR_DEVICE;
198 req.bRequest = MOS_UR_READREG;
199 USETW(req.wValue, 0);
200 USETW(req.wIndex, reg);
201 USETW(req.wLength, 1);
202
203 err = usbd_do_request(sc->mos_udev, &req, &val);
204
205 if (err) {
206 DPRINTF(("mos_reg_read_1 error, reg: %d\n", reg));
207 return (-1);
208 }
209
210 return (val);
211 }
212
213 int
mos_reg_read_2(struct mos_softc * sc,int reg)214 mos_reg_read_2(struct mos_softc *sc, int reg)
215 {
216 usb_device_request_t req;
217 usbd_status err;
218 uWord val;
219
220 USETW(val,0);
221
222 if (usbd_is_dying(sc->mos_udev))
223 return(0);
224
225 req.bmRequestType = UT_READ_VENDOR_DEVICE;
226 req.bRequest = MOS_UR_READREG;
227 USETW(req.wValue, 0);
228 USETW(req.wIndex, reg);
229 USETW(req.wLength, 2);
230
231 err = usbd_do_request(sc->mos_udev, &req, &val);
232
233 if (err) {
234 DPRINTF(("mos_reg_read_2 error, reg: %d\n", reg));
235 return (-1);
236 }
237
238 return(UGETW(val));
239 }
240
241 int
mos_reg_write_1(struct mos_softc * sc,int reg,int aval)242 mos_reg_write_1(struct mos_softc *sc, int reg, int aval)
243 {
244 usb_device_request_t req;
245 usbd_status err;
246 uByte val;
247
248 val = aval;
249
250 if (usbd_is_dying(sc->mos_udev))
251 return(0);
252
253 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
254 req.bRequest = MOS_UR_WRITEREG;
255 USETW(req.wValue, 0);
256 USETW(req.wIndex, reg);
257 USETW(req.wLength, 1);
258
259 err = usbd_do_request(sc->mos_udev, &req, &val);
260
261 if (err) {
262 DPRINTF(("mos_reg_write_1 error, reg: %d\n", reg));
263 return (-1);
264 }
265
266 return(0);
267 }
268
269 int
mos_reg_write_2(struct mos_softc * sc,int reg,int aval)270 mos_reg_write_2(struct mos_softc *sc, int reg, int aval)
271 {
272 usb_device_request_t req;
273 usbd_status err;
274 uWord val;
275
276 USETW(val, aval);
277
278 if (usbd_is_dying(sc->mos_udev))
279 return (0);
280
281 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
282 req.bRequest = MOS_UR_WRITEREG;
283 USETW(req.wValue, 0);
284 USETW(req.wIndex, reg);
285 USETW(req.wLength, 2);
286
287 err = usbd_do_request(sc->mos_udev, &req, &val);
288
289 if (err) {
290 DPRINTF(("mos_reg_write_2 error, reg: %d\n", reg));
291 return (-1);
292 }
293
294 return (0);
295 }
296
297 int
mos_readmac(struct mos_softc * sc,u_char * mac)298 mos_readmac(struct mos_softc *sc, u_char *mac)
299 {
300 usb_device_request_t req;
301 usbd_status err;
302
303 if (usbd_is_dying(sc->mos_udev))
304 return(0);
305
306 req.bmRequestType = UT_READ_VENDOR_DEVICE;
307 req.bRequest = MOS_UR_READREG;
308 USETW(req.wValue, 0);
309 USETW(req.wIndex, MOS_MAC);
310 USETW(req.wLength, ETHER_ADDR_LEN);
311
312 err = usbd_do_request(sc->mos_udev, &req, mac);
313
314 if (err) {
315 DPRINTF(("mos_readmac error"));
316 return (-1);
317 }
318
319 return (0);
320 }
321
322 int
mos_writemac(struct mos_softc * sc,u_char * mac)323 mos_writemac(struct mos_softc *sc, u_char *mac)
324 {
325 usb_device_request_t req;
326 usbd_status err;
327
328 if (usbd_is_dying(sc->mos_udev))
329 return(0);
330
331 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
332 req.bRequest = MOS_UR_WRITEREG;
333 USETW(req.wValue, 0);
334 USETW(req.wIndex, MOS_MAC);
335 USETW(req.wLength, ETHER_ADDR_LEN);
336
337 err = usbd_do_request(sc->mos_udev, &req, mac);
338
339 if (err) {
340 DPRINTF(("mos_writemac error"));
341 return (-1);
342 }
343
344 return (0);
345 }
346
347 int
mos_write_mcast(struct mos_softc * sc,u_char * hashtbl)348 mos_write_mcast(struct mos_softc *sc, u_char *hashtbl)
349 {
350 usb_device_request_t req;
351 usbd_status err;
352
353 if (usbd_is_dying(sc->mos_udev))
354 return(0);
355
356 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
357 req.bRequest = MOS_UR_WRITEREG;
358 USETW(req.wValue, 0);
359 USETW(req.wIndex, MOS_MCAST_TABLE);
360 USETW(req.wLength, 8);
361
362 err = usbd_do_request(sc->mos_udev, &req, hashtbl);
363
364 if (err) {
365 DPRINTF(("mos_reg_mcast error\n"));
366 return(-1);
367 }
368
369 return(0);
370 }
371
372 int
mos_miibus_readreg(struct device * dev,int phy,int reg)373 mos_miibus_readreg(struct device *dev, int phy, int reg)
374 {
375 struct mos_softc *sc = (void *)dev;
376 int i,res;
377
378 if (usbd_is_dying(sc->mos_udev)) {
379 DPRINTF(("mos: dying\n"));
380 return (0);
381 }
382
383 mos_lock_mii(sc);
384
385 mos_reg_write_2(sc, MOS_PHY_DATA, 0);
386 mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
387 MOS_PHYCTL_READ);
388 mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
389 MOS_PHYSTS_PENDING);
390
391 for (i = 0; i < MOS_TIMEOUT; i++) {
392 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
393 break;
394 }
395 if (i == MOS_TIMEOUT) {
396 printf("%s: MII read timeout\n", sc->mos_dev.dv_xname);
397 }
398
399 res = mos_reg_read_2(sc, MOS_PHY_DATA);
400
401 mos_unlock_mii(sc);
402
403 return (res);
404 }
405
406 void
mos_miibus_writereg(struct device * dev,int phy,int reg,int val)407 mos_miibus_writereg(struct device *dev, int phy, int reg, int val)
408 {
409 struct mos_softc *sc = (void *)dev;
410 int i;
411
412 if (usbd_is_dying(sc->mos_udev))
413 return;
414
415 mos_lock_mii(sc);
416
417 mos_reg_write_2(sc, MOS_PHY_DATA, val);
418 mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
419 MOS_PHYCTL_WRITE);
420 mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
421 MOS_PHYSTS_PENDING);
422
423 for (i = 0; i < MOS_TIMEOUT; i++) {
424 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
425 break;
426 }
427 if (i == MOS_TIMEOUT) {
428 printf("%s: MII write timeout\n", sc->mos_dev.dv_xname);
429 }
430
431 mos_unlock_mii(sc);
432
433 return;
434 }
435
436 void
mos_miibus_statchg(struct device * dev)437 mos_miibus_statchg(struct device *dev)
438 {
439 struct mos_softc *sc = (void *)dev;
440 struct mii_data *mii = GET_MII(sc);
441 int val, err;
442
443 mos_lock_mii(sc);
444
445 /* disable RX, TX prior to changing FDX, SPEEDSEL */
446 val = mos_reg_read_1(sc, MOS_CTL);
447 val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
448 mos_reg_write_1(sc, MOS_CTL, val);
449
450 /* reset register which counts dropped frames */
451 mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
452
453 if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
454 val |= MOS_CTL_FDX_ENB;
455 else
456 val &= ~(MOS_CTL_FDX_ENB);
457
458 switch (IFM_SUBTYPE(mii->mii_media_active)) {
459 case IFM_100_TX:
460 val |= MOS_CTL_SPEEDSEL;
461 break;
462 case IFM_10_T:
463 val &= ~(MOS_CTL_SPEEDSEL);
464 break;
465 }
466
467 /* re-enable TX, RX */
468 val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
469 err = mos_reg_write_1(sc, MOS_CTL, val);
470 mos_unlock_mii(sc);
471
472 if (err) {
473 printf("%s: media change failed\n", sc->mos_dev.dv_xname);
474 return;
475 }
476 }
477
478 /*
479 * Set media options.
480 */
481 int
mos_ifmedia_upd(struct ifnet * ifp)482 mos_ifmedia_upd(struct ifnet *ifp)
483 {
484 struct mos_softc *sc = ifp->if_softc;
485 struct mii_data *mii = GET_MII(sc);
486
487 sc->mos_link = 0;
488 if (mii->mii_instance) {
489 struct mii_softc *miisc;
490 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
491 mii_phy_reset(miisc);
492 }
493 mii_mediachg(mii);
494
495 return (0);
496 }
497
498 /*
499 * Report current media status.
500 */
501 void
mos_ifmedia_sts(struct ifnet * ifp,struct ifmediareq * ifmr)502 mos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
503 {
504 struct mos_softc *sc = ifp->if_softc;
505 struct mii_data *mii = GET_MII(sc);
506
507 mii_pollstat(mii);
508 ifmr->ifm_active = mii->mii_media_active;
509 ifmr->ifm_status = mii->mii_media_status;
510 }
511
512 void
mos_iff(struct mos_softc * sc)513 mos_iff(struct mos_softc *sc)
514 {
515 struct ifnet *ifp = GET_IFP(sc);
516 struct arpcom *ac = &sc->arpcom;
517 struct ether_multi *enm;
518 struct ether_multistep step;
519 u_int32_t h = 0;
520 u_int8_t rxmode, hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
521
522 if (usbd_is_dying(sc->mos_udev))
523 return;
524
525 rxmode = mos_reg_read_1(sc, MOS_CTL);
526 rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC);
527 ifp->if_flags &= ~IFF_ALLMULTI;
528
529 if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
530 ifp->if_flags |= IFF_ALLMULTI;
531 rxmode |= MOS_CTL_ALLMULTI;
532 if (ifp->if_flags & IFF_PROMISC)
533 rxmode |= MOS_CTL_RX_PROMISC;
534 } else {
535 /* now program new ones */
536 ETHER_FIRST_MULTI(step, ac, enm);
537 while (enm != NULL) {
538 h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
539
540 hashtbl[h / 8] |= 1 << (h % 8);
541
542 ETHER_NEXT_MULTI(step, enm);
543 }
544 }
545
546 /*
547 * The datasheet claims broadcast frames were always accepted
548 * regardless of filter settings. But the hardware seems to
549 * filter broadcast frames, so pass them explicitly.
550 */
551 h = ether_crc32_be(etherbroadcastaddr, ETHER_ADDR_LEN) >> 26;
552 hashtbl[h / 8] |= 1 << (h % 8);
553
554 mos_write_mcast(sc, (void *)&hashtbl);
555 mos_reg_write_1(sc, MOS_CTL, rxmode);
556 }
557
558 void
mos_reset(struct mos_softc * sc)559 mos_reset(struct mos_softc *sc)
560 {
561 u_int8_t ctl;
562 if (usbd_is_dying(sc->mos_udev))
563 return;
564
565 ctl = mos_reg_read_1(sc, MOS_CTL);
566 ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB |
567 MOS_CTL_RX_ENB);
568 /* Disable RX, TX, promiscuous and allmulticast mode */
569 mos_reg_write_1(sc, MOS_CTL, ctl);
570
571 /* Reset frame drop counter register to zero */
572 mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
573
574 /* Wait a little while for the chip to get its brains in order. */
575 DELAY(1000);
576 return;
577 }
578
579 void
mos_chip_init(struct mos_softc * sc)580 mos_chip_init(struct mos_softc *sc)
581 {
582 int i;
583
584 /*
585 * Rev.C devices have a pause threshold register which needs to be set
586 * at startup.
587 */
588 if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) {
589 for (i=0;i<MOS_PAUSE_REWRITES;i++)
590 mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0);
591 }
592
593 sc->mos_phyaddrs[0] = 1; sc->mos_phyaddrs[1] = 0xFF;
594 }
595
596 /*
597 * Probe for a MCS7x30 chip.
598 */
599 int
mos_match(struct device * parent,void * match,void * aux)600 mos_match(struct device *parent, void *match, void *aux)
601 {
602 struct usb_attach_arg *uaa = aux;
603
604 if (uaa->iface == NULL || uaa->configno != MOS_CONFIG_NO)
605 return(UMATCH_NONE);
606
607 return (mos_lookup(uaa->vendor, uaa->product) != NULL ?
608 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
609 }
610
611 /*
612 * Attach the interface. Allocate softc structures, do ifmedia
613 * setup and ethernet/BPF attach.
614 */
615 void
mos_attach(struct device * parent,struct device * self,void * aux)616 mos_attach(struct device *parent, struct device *self, void *aux)
617 {
618 struct mos_softc *sc = (struct mos_softc *)self;
619 struct usb_attach_arg *uaa = aux;
620 struct ifnet *ifp;
621 struct usbd_device *dev = uaa->device;
622 usbd_status err;
623 usb_interface_descriptor_t *id;
624 usb_endpoint_descriptor_t *ed;
625 struct mii_data *mii;
626 u_char eaddr[ETHER_ADDR_LEN];
627 int i,s;
628
629 sc->mos_udev = dev;
630 sc->mos_unit = self->dv_unit;
631
632 usb_init_task(&sc->mos_tick_task, mos_tick_task, sc,
633 USB_TASK_TYPE_GENERIC);
634 rw_init(&sc->mos_mii_lock, "mosmii");
635 usb_init_task(&sc->mos_stop_task, (void (*)(void *))mos_stop, sc,
636 USB_TASK_TYPE_GENERIC);
637
638 err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &sc->mos_iface);
639 if (err) {
640 printf("%s: getting interface handle failed\n",
641 sc->mos_dev.dv_xname);
642 return;
643 }
644
645 sc->mos_flags = mos_lookup(uaa->vendor, uaa->product)->mos_flags;
646
647 id = usbd_get_interface_descriptor(sc->mos_iface);
648
649 sc->mos_bufsz = MOS_BUFSZ;
650
651 /* Find endpoints. */
652 for (i = 0; i < id->bNumEndpoints; i++) {
653 ed = usbd_interface2endpoint_descriptor(sc->mos_iface, i);
654 if (!ed) {
655 printf("%s: couldn't get ep %d\n",
656 sc->mos_dev.dv_xname, i);
657 return;
658 }
659 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
660 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
661 sc->mos_ed[MOS_ENDPT_RX] = ed->bEndpointAddress;
662 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
663 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
664 sc->mos_ed[MOS_ENDPT_TX] = ed->bEndpointAddress;
665 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
666 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
667 sc->mos_ed[MOS_ENDPT_INTR] = ed->bEndpointAddress;
668 }
669 }
670
671 s = splnet();
672
673 printf("%s:", sc->mos_dev.dv_xname);
674
675 if (sc->mos_flags & MCS7730)
676 printf(" MCS7730");
677 else if (sc->mos_flags & MCS7830)
678 printf(" MCS7830");
679 else if (sc->mos_flags & MCS7832)
680 printf(" MCS7832");
681
682 mos_chip_init(sc);
683
684 /*
685 * Read MAC address, inform the world.
686 */
687 err = mos_readmac(sc, (void*)&eaddr);
688 if (err) {
689 printf("%s: couldn't get MAC address\n",
690 sc->mos_dev.dv_xname);
691 splx(s);
692 return;
693 }
694 bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
695 printf(", address %s\n", ether_sprintf(eaddr));
696
697 /* Initialize interface info.*/
698 ifp = GET_IFP(sc);
699 ifp->if_softc = sc;
700 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
701 ifp->if_ioctl = mos_ioctl;
702 ifp->if_start = mos_start;
703 ifp->if_watchdog = mos_watchdog;
704 strlcpy(ifp->if_xname, sc->mos_dev.dv_xname, IFNAMSIZ);
705
706 ifp->if_capabilities = IFCAP_VLAN_MTU;
707
708 /* Initialize MII/media info. */
709 mii = GET_MII(sc);
710 mii->mii_ifp = ifp;
711 mii->mii_readreg = mos_miibus_readreg;
712 mii->mii_writereg = mos_miibus_writereg;
713 mii->mii_statchg = mos_miibus_statchg;
714 mii->mii_flags = MIIF_AUTOTSLEEP;
715
716 ifmedia_init(&mii->mii_media, 0, mos_ifmedia_upd, mos_ifmedia_sts);
717 mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
718
719 if (LIST_FIRST(&mii->mii_phys) == NULL) {
720 ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
721 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
722 } else
723 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
724
725 /* Attach the interface. */
726 if_attach(ifp);
727 ether_ifattach(ifp);
728
729 timeout_set(&sc->mos_stat_ch, mos_tick, sc);
730
731 splx(s);
732 }
733
734 int
mos_detach(struct device * self,int flags)735 mos_detach(struct device *self, int flags)
736 {
737 struct mos_softc *sc = (struct mos_softc *)self;
738 struct ifnet *ifp = GET_IFP(sc);
739 int s;
740
741 DPRINTFN(2,("%s: %s: enter\n", sc->mos_dev.dv_xname, __func__));
742
743 if (timeout_initialized(&sc->mos_stat_ch))
744 timeout_del(&sc->mos_stat_ch);
745
746 if (sc->mos_ep[MOS_ENDPT_TX] != NULL)
747 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_TX]);
748 if (sc->mos_ep[MOS_ENDPT_RX] != NULL)
749 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_RX]);
750 if (sc->mos_ep[MOS_ENDPT_INTR] != NULL)
751 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_INTR]);
752
753 /*
754 * Remove any pending tasks. They cannot be executing because they run
755 * in the same thread as detach.
756 */
757 usb_rem_task(sc->mos_udev, &sc->mos_tick_task);
758 usb_rem_task(sc->mos_udev, &sc->mos_stop_task);
759 s = splusb();
760
761 if (--sc->mos_refcnt >= 0) {
762 /* Wait for processes to go away */
763 usb_detach_wait(&sc->mos_dev);
764 }
765
766 if (ifp->if_flags & IFF_RUNNING)
767 mos_stop(sc);
768
769 mii_detach(&sc->mos_mii, MII_PHY_ANY, MII_OFFSET_ANY);
770 ifmedia_delete_instance(&sc->mos_mii.mii_media, IFM_INST_ANY);
771 if (ifp->if_softc != NULL) {
772 ether_ifdetach(ifp);
773 if_detach(ifp);
774 }
775
776 #ifdef DIAGNOSTIC
777 if (sc->mos_ep[MOS_ENDPT_TX] != NULL ||
778 sc->mos_ep[MOS_ENDPT_RX] != NULL ||
779 sc->mos_ep[MOS_ENDPT_INTR] != NULL)
780 printf("%s: detach has active endpoints\n",
781 sc->mos_dev.dv_xname);
782 #endif
783
784 splx(s);
785
786 return (0);
787 }
788
789 struct mbuf *
mos_newbuf(void)790 mos_newbuf(void)
791 {
792 struct mbuf *m;
793
794 MGETHDR(m, M_DONTWAIT, MT_DATA);
795 if (m == NULL)
796 return (NULL);
797
798 MCLGET(m, M_DONTWAIT);
799 if (!(m->m_flags & M_EXT)) {
800 m_freem(m);
801 return (NULL);
802 }
803
804 m->m_len = m->m_pkthdr.len = MCLBYTES;
805 m_adj(m, ETHER_ALIGN);
806
807 return (m);
808 }
809
810 int
mos_rx_list_init(struct mos_softc * sc)811 mos_rx_list_init(struct mos_softc *sc)
812 {
813 struct mos_cdata *cd;
814 struct mos_chain *c;
815 int i;
816
817 DPRINTF(("%s: %s: enter\n", sc->mos_dev.dv_xname, __func__));
818
819 cd = &sc->mos_cdata;
820 for (i = 0; i < MOS_RX_LIST_CNT; i++) {
821 c = &cd->mos_rx_chain[i];
822 c->mos_sc = sc;
823 c->mos_idx = i;
824 c->mos_mbuf = NULL;
825 if (c->mos_xfer == NULL) {
826 c->mos_xfer = usbd_alloc_xfer(sc->mos_udev);
827 if (c->mos_xfer == NULL)
828 return (ENOBUFS);
829 c->mos_buf = usbd_alloc_buffer(c->mos_xfer,
830 sc->mos_bufsz);
831 if (c->mos_buf == NULL) {
832 usbd_free_xfer(c->mos_xfer);
833 return (ENOBUFS);
834 }
835 }
836 }
837
838 return (0);
839 }
840
841 int
mos_tx_list_init(struct mos_softc * sc)842 mos_tx_list_init(struct mos_softc *sc)
843 {
844 struct mos_cdata *cd;
845 struct mos_chain *c;
846 int i;
847
848 DPRINTF(("%s: %s: enter\n", sc->mos_dev.dv_xname, __func__));
849
850 cd = &sc->mos_cdata;
851 for (i = 0; i < MOS_TX_LIST_CNT; i++) {
852 c = &cd->mos_tx_chain[i];
853 c->mos_sc = sc;
854 c->mos_idx = i;
855 c->mos_mbuf = NULL;
856 if (c->mos_xfer == NULL) {
857 c->mos_xfer = usbd_alloc_xfer(sc->mos_udev);
858 if (c->mos_xfer == NULL)
859 return (ENOBUFS);
860 c->mos_buf = usbd_alloc_buffer(c->mos_xfer,
861 sc->mos_bufsz);
862 if (c->mos_buf == NULL) {
863 usbd_free_xfer(c->mos_xfer);
864 return (ENOBUFS);
865 }
866 }
867 }
868
869 return (0);
870 }
871
872 /*
873 * A frame has been uploaded: pass the resulting mbuf chain up to
874 * the higher level protocols.
875 */
876 void
mos_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)877 mos_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
878 {
879 struct mos_chain *c = (struct mos_chain *)priv;
880 struct mos_softc *sc = c->mos_sc;
881 struct ifnet *ifp = GET_IFP(sc);
882 u_char *buf = c->mos_buf;
883 u_int8_t rxstat;
884 u_int32_t total_len;
885 u_int16_t pktlen = 0;
886 struct mbuf_list ml = MBUF_LIST_INITIALIZER();
887 struct mbuf *m;
888 int s;
889
890 DPRINTFN(10,("%s: %s: enter\n", sc->mos_dev.dv_xname,__func__));
891
892 if (usbd_is_dying(sc->mos_udev))
893 return;
894
895 if (!(ifp->if_flags & IFF_RUNNING))
896 return;
897
898 if (status != USBD_NORMAL_COMPLETION) {
899 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
900 return;
901 if (usbd_ratecheck(&sc->mos_rx_notice)) {
902 printf("%s: usb errors on rx: %s\n",
903 sc->mos_dev.dv_xname, usbd_errstr(status));
904 }
905 if (status == USBD_STALLED)
906 usbd_clear_endpoint_stall_async(sc->mos_ep[MOS_ENDPT_RX]);
907 goto done;
908 }
909
910 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
911
912 if (total_len <= 1)
913 goto done;
914
915 /* evaluate status byte at the end */
916 pktlen = total_len - 1;
917 rxstat = buf[pktlen] & MOS_RXSTS_MASK;
918
919 if (rxstat != MOS_RXSTS_VALID) {
920 DPRINTF(("%s: erroneous frame received: ",
921 sc->mos_dev.dv_xname));
922 if (rxstat & MOS_RXSTS_SHORT_FRAME)
923 DPRINTF(("frame size less than 64 bytes\n"));
924 if (rxstat & MOS_RXSTS_LARGE_FRAME)
925 DPRINTF(("frame size larger than 1532 bytes\n"));
926 if (rxstat & MOS_RXSTS_CRC_ERROR)
927 DPRINTF(("CRC error\n"));
928 if (rxstat & MOS_RXSTS_ALIGN_ERROR)
929 DPRINTF(("alignment error\n"));
930 ifp->if_ierrors++;
931 goto done;
932 }
933
934 if ( pktlen < sizeof(struct ether_header) ) {
935 ifp->if_ierrors++;
936 goto done;
937 }
938
939 m = mos_newbuf();
940 if (m == NULL) {
941 ifp->if_ierrors++;
942 goto done;
943 }
944
945 m->m_pkthdr.len = m->m_len = pktlen;
946
947 memcpy(mtod(m, char *), buf, pktlen);
948
949 ml_enqueue(&ml, m);
950
951 s = splnet();
952 if_input(ifp, &ml);
953 splx(s);
954
955 done:
956 memset(c->mos_buf, 0, sc->mos_bufsz);
957
958 /* Setup new transfer. */
959 usbd_setup_xfer(xfer, sc->mos_ep[MOS_ENDPT_RX],
960 c, c->mos_buf, sc->mos_bufsz,
961 USBD_SHORT_XFER_OK | USBD_NO_COPY,
962 USBD_NO_TIMEOUT, mos_rxeof);
963 usbd_transfer(xfer);
964
965 DPRINTFN(10,("%s: %s: start rx\n", sc->mos_dev.dv_xname, __func__));
966
967 return;
968 }
969
970 /*
971 * A frame was downloaded to the chip. It's safe for us to clean up
972 * the list buffers.
973 */
974
975 void
mos_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)976 mos_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
977 {
978 struct mos_softc *sc;
979 struct mos_chain *c;
980 struct ifnet *ifp;
981 int s;
982
983 c = priv;
984 sc = c->mos_sc;
985 ifp = &sc->arpcom.ac_if;
986
987 if (usbd_is_dying(sc->mos_udev))
988 return;
989
990 s = splnet();
991
992 if (status != USBD_NORMAL_COMPLETION) {
993 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
994 splx(s);
995 return;
996 }
997 ifp->if_oerrors++;
998 printf("%s: usb error on tx: %s\n", sc->mos_dev.dv_xname,
999 usbd_errstr(status));
1000 if (status == USBD_STALLED)
1001 usbd_clear_endpoint_stall_async(sc->mos_ep[MOS_ENDPT_TX]);
1002 splx(s);
1003 return;
1004 }
1005
1006 ifp->if_timer = 0;
1007 ifq_clr_oactive(&ifp->if_snd);
1008
1009 m_freem(c->mos_mbuf);
1010 c->mos_mbuf = NULL;
1011
1012 if (ifq_empty(&ifp->if_snd) == 0)
1013 mos_start(ifp);
1014
1015 splx(s);
1016 return;
1017 }
1018
1019 void
mos_tick(void * xsc)1020 mos_tick(void *xsc)
1021 {
1022 struct mos_softc *sc = xsc;
1023
1024 if (sc == NULL)
1025 return;
1026
1027 DPRINTFN(0xff, ("%s: %s: enter\n", sc->mos_dev.dv_xname,
1028 __func__));
1029
1030 if (usbd_is_dying(sc->mos_udev))
1031 return;
1032
1033 /* Perform periodic stuff in process context */
1034 usb_add_task(sc->mos_udev, &sc->mos_tick_task);
1035
1036 }
1037
1038 void
mos_tick_task(void * xsc)1039 mos_tick_task(void *xsc)
1040 {
1041 int s;
1042 struct mos_softc *sc;
1043 struct ifnet *ifp;
1044 struct mii_data *mii;
1045
1046 sc = xsc;
1047
1048 if (sc == NULL)
1049 return;
1050
1051 if (usbd_is_dying(sc->mos_udev))
1052 return;
1053
1054 ifp = GET_IFP(sc);
1055 mii = GET_MII(sc);
1056 if (mii == NULL)
1057 return;
1058
1059 s = splnet();
1060
1061 mii_tick(mii);
1062 if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE &&
1063 IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
1064 DPRINTF(("%s: %s: got link\n",
1065 sc->mos_dev.dv_xname, __func__));
1066 sc->mos_link++;
1067 if (ifq_empty(&ifp->if_snd) == 0)
1068 mos_start(ifp);
1069 }
1070
1071 timeout_add_sec(&sc->mos_stat_ch, 1);
1072
1073 splx(s);
1074 }
1075
1076 int
mos_encap(struct mos_softc * sc,struct mbuf * m,int idx)1077 mos_encap(struct mos_softc *sc, struct mbuf *m, int idx)
1078 {
1079 struct mos_chain *c;
1080 usbd_status err;
1081 int length;
1082
1083 c = &sc->mos_cdata.mos_tx_chain[idx];
1084
1085 m_copydata(m, 0, m->m_pkthdr.len, c->mos_buf);
1086 length = m->m_pkthdr.len;
1087
1088 c->mos_mbuf = m;
1089
1090 usbd_setup_xfer(c->mos_xfer, sc->mos_ep[MOS_ENDPT_TX],
1091 c, c->mos_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
1092 10000, mos_txeof);
1093
1094 /* Transmit */
1095 err = usbd_transfer(c->mos_xfer);
1096 if (err != USBD_IN_PROGRESS) {
1097 c->mos_mbuf = NULL;
1098 mos_stop(sc);
1099 return(EIO);
1100 }
1101
1102 sc->mos_cdata.mos_tx_cnt++;
1103
1104 return(0);
1105 }
1106
1107 void
mos_start(struct ifnet * ifp)1108 mos_start(struct ifnet *ifp)
1109 {
1110 struct mos_softc *sc;
1111 struct mbuf *m_head = NULL;
1112
1113 sc = ifp->if_softc;
1114
1115 if (!sc->mos_link)
1116 return;
1117
1118 if (ifq_is_oactive(&ifp->if_snd))
1119 return;
1120
1121 m_head = ifq_dequeue(&ifp->if_snd);
1122 if (m_head == NULL)
1123 return;
1124
1125 if (mos_encap(sc, m_head, 0)) {
1126 m_freem(m_head);
1127 ifq_set_oactive(&ifp->if_snd);
1128 return;
1129 }
1130
1131 /*
1132 * If there's a BPF listener, bounce a copy of this frame
1133 * to him.
1134 */
1135 #if NBPFILTER > 0
1136 if (ifp->if_bpf)
1137 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
1138 #endif
1139
1140 ifq_set_oactive(&ifp->if_snd);
1141
1142 /*
1143 * Set a timeout in case the chip goes out to lunch.
1144 */
1145 ifp->if_timer = 5;
1146
1147 return;
1148 }
1149
1150 void
mos_init(void * xsc)1151 mos_init(void *xsc)
1152 {
1153 struct mos_softc *sc = xsc;
1154 struct ifnet *ifp = &sc->arpcom.ac_if;
1155 struct mos_chain *c;
1156 usbd_status err;
1157 u_int8_t rxmode;
1158 int i, s;
1159
1160 s = splnet();
1161
1162 /*
1163 * Cancel pending I/O and free all RX/TX buffers.
1164 */
1165 mos_reset(sc);
1166
1167 /*
1168 * Write MAC address
1169 */
1170 mos_writemac(sc, sc->arpcom.ac_enaddr);
1171
1172 /* Init RX ring. */
1173 if (mos_rx_list_init(sc) == ENOBUFS) {
1174 printf("%s: rx list init failed\n", sc->mos_dev.dv_xname);
1175 splx(s);
1176 return;
1177 }
1178
1179 /* Init TX ring. */
1180 if (mos_tx_list_init(sc) == ENOBUFS) {
1181 printf("%s: tx list init failed\n", sc->mos_dev.dv_xname);
1182 splx(s);
1183 return;
1184 }
1185
1186 /* Read and set transmitter IPG values */
1187 sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0);
1188 sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1);
1189 mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]);
1190 mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]);
1191
1192 /* Program promiscuous mode and multicast filters. */
1193 mos_iff(sc);
1194
1195 /* Enable receiver and transmitter, bridge controls speed/duplex mode */
1196 rxmode = mos_reg_read_1(sc, MOS_CTL);
1197 rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB;
1198 rxmode &= ~(MOS_CTL_SLEEP);
1199 mos_reg_write_1(sc, MOS_CTL, rxmode);
1200
1201 mii_mediachg(GET_MII(sc));
1202
1203 /* Open RX and TX pipes. */
1204 err = usbd_open_pipe(sc->mos_iface, sc->mos_ed[MOS_ENDPT_RX],
1205 USBD_EXCLUSIVE_USE, &sc->mos_ep[MOS_ENDPT_RX]);
1206 if (err) {
1207 printf("%s: open rx pipe failed: %s\n",
1208 sc->mos_dev.dv_xname, usbd_errstr(err));
1209 splx(s);
1210 return;
1211 }
1212
1213 err = usbd_open_pipe(sc->mos_iface, sc->mos_ed[MOS_ENDPT_TX],
1214 USBD_EXCLUSIVE_USE, &sc->mos_ep[MOS_ENDPT_TX]);
1215 if (err) {
1216 printf("%s: open tx pipe failed: %s\n",
1217 sc->mos_dev.dv_xname, usbd_errstr(err));
1218 splx(s);
1219 return;
1220 }
1221
1222 /* Start up the receive pipe. */
1223 for (i = 0; i < MOS_RX_LIST_CNT; i++) {
1224 c = &sc->mos_cdata.mos_rx_chain[i];
1225 usbd_setup_xfer(c->mos_xfer, sc->mos_ep[MOS_ENDPT_RX],
1226 c, c->mos_buf, sc->mos_bufsz,
1227 USBD_SHORT_XFER_OK | USBD_NO_COPY,
1228 USBD_NO_TIMEOUT, mos_rxeof);
1229 usbd_transfer(c->mos_xfer);
1230 }
1231
1232 ifp->if_flags |= IFF_RUNNING;
1233 ifq_clr_oactive(&ifp->if_snd);
1234
1235 splx(s);
1236
1237 timeout_add_sec(&sc->mos_stat_ch, 1);
1238 return;
1239 }
1240
1241 int
mos_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)1242 mos_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1243 {
1244 struct mos_softc *sc = ifp->if_softc;
1245 struct ifreq *ifr = (struct ifreq *)data;
1246 int s, error = 0;
1247
1248 s = splnet();
1249
1250 switch(cmd) {
1251 case SIOCSIFADDR:
1252 ifp->if_flags |= IFF_UP;
1253 if (!(ifp->if_flags & IFF_RUNNING))
1254 mos_init(sc);
1255 break;
1256
1257 case SIOCSIFFLAGS:
1258 if (ifp->if_flags & IFF_UP) {
1259 if (ifp->if_flags & IFF_RUNNING)
1260 error = ENETRESET;
1261 else
1262 mos_init(sc);
1263 } else {
1264 if (ifp->if_flags & IFF_RUNNING)
1265 mos_stop(sc);
1266 }
1267 break;
1268
1269 case SIOCGIFMEDIA:
1270 case SIOCSIFMEDIA:
1271 error = ifmedia_ioctl(ifp, ifr, &sc->mos_mii.mii_media, cmd);
1272 break;
1273
1274 default:
1275 error = ether_ioctl(ifp, &sc->arpcom, cmd, data);
1276 }
1277
1278 if (error == ENETRESET) {
1279 if (ifp->if_flags & IFF_RUNNING)
1280 mos_iff(sc);
1281 error = 0;
1282 }
1283
1284 splx(s);
1285 return(error);
1286 }
1287
1288 void
mos_watchdog(struct ifnet * ifp)1289 mos_watchdog(struct ifnet *ifp)
1290 {
1291 struct mos_softc *sc;
1292 struct mos_chain *c;
1293 usbd_status stat;
1294 int s;
1295
1296 sc = ifp->if_softc;
1297
1298 ifp->if_oerrors++;
1299 printf("%s: watchdog timeout\n", sc->mos_dev.dv_xname);
1300
1301 s = splusb();
1302 c = &sc->mos_cdata.mos_tx_chain[0];
1303 usbd_get_xfer_status(c->mos_xfer, NULL, NULL, NULL, &stat);
1304 mos_txeof(c->mos_xfer, c, stat);
1305
1306 if (!ifq_empty(&ifp->if_snd))
1307 mos_start(ifp);
1308 splx(s);
1309 }
1310
1311
1312 /*
1313 * Stop the adapter and free any mbufs allocated to the
1314 * RX and TX lists.
1315 */
1316 void
mos_stop(struct mos_softc * sc)1317 mos_stop(struct mos_softc *sc)
1318 {
1319 usbd_status err;
1320 struct ifnet *ifp;
1321 int i;
1322
1323 mos_reset(sc);
1324
1325 ifp = &sc->arpcom.ac_if;
1326 ifp->if_timer = 0;
1327 ifp->if_flags &= ~IFF_RUNNING;
1328 ifq_clr_oactive(&ifp->if_snd);
1329
1330 timeout_del(&sc->mos_stat_ch);
1331
1332 /* Stop transfers. */
1333 if (sc->mos_ep[MOS_ENDPT_RX] != NULL) {
1334 err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_RX]);
1335 if (err) {
1336 printf("%s: close rx pipe failed: %s\n",
1337 sc->mos_dev.dv_xname, usbd_errstr(err));
1338 }
1339 sc->mos_ep[MOS_ENDPT_RX] = NULL;
1340 }
1341
1342 if (sc->mos_ep[MOS_ENDPT_TX] != NULL) {
1343 err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_TX]);
1344 if (err) {
1345 printf("%s: close tx pipe failed: %s\n",
1346 sc->mos_dev.dv_xname, usbd_errstr(err));
1347 }
1348 sc->mos_ep[MOS_ENDPT_TX] = NULL;
1349 }
1350
1351 if (sc->mos_ep[MOS_ENDPT_INTR] != NULL) {
1352 err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_INTR]);
1353 if (err) {
1354 printf("%s: close intr pipe failed: %s\n",
1355 sc->mos_dev.dv_xname, usbd_errstr(err));
1356 }
1357 sc->mos_ep[MOS_ENDPT_INTR] = NULL;
1358 }
1359
1360 /* Free RX resources. */
1361 for (i = 0; i < MOS_RX_LIST_CNT; i++) {
1362 if (sc->mos_cdata.mos_rx_chain[i].mos_mbuf != NULL) {
1363 m_freem(sc->mos_cdata.mos_rx_chain[i].mos_mbuf);
1364 sc->mos_cdata.mos_rx_chain[i].mos_mbuf = NULL;
1365 }
1366 if (sc->mos_cdata.mos_rx_chain[i].mos_xfer != NULL) {
1367 usbd_free_xfer(sc->mos_cdata.mos_rx_chain[i].mos_xfer);
1368 sc->mos_cdata.mos_rx_chain[i].mos_xfer = NULL;
1369 }
1370 }
1371
1372 /* Free TX resources. */
1373 for (i = 0; i < MOS_TX_LIST_CNT; i++) {
1374 if (sc->mos_cdata.mos_tx_chain[i].mos_mbuf != NULL) {
1375 m_freem(sc->mos_cdata.mos_tx_chain[i].mos_mbuf);
1376 sc->mos_cdata.mos_tx_chain[i].mos_mbuf = NULL;
1377 }
1378 if (sc->mos_cdata.mos_tx_chain[i].mos_xfer != NULL) {
1379 usbd_free_xfer(sc->mos_cdata.mos_tx_chain[i].mos_xfer);
1380 sc->mos_cdata.mos_tx_chain[i].mos_xfer = NULL;
1381 }
1382 }
1383
1384 sc->mos_link = 0;
1385 }
1386
1387