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