source: freebsd-mos-driver/if_mos.c@ 271

Last change on this file since 271 was 271, checked in by Rick van der Zwet, 14 years ago

Clean code:

  • static functions (usual behaviour)
  • debug statements cleanups


File size: 26.4 KB
Line 
1/* $OpenBSD: if_mos.c,v 1.7 2009/10/13 19:33:17 pirofti Exp $ */
2#define USB_DEBUG 1
3/*
4 * Copyright (c) 2011 Rick van der Zwet <info@rickvanderzwet.nl>
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) 2008 Johann Christian Rode <jcrode@gmx.net>
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) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org>
37 *
38 * Permission to use, copy, modify, and distribute this software for any
39 * purpose with or without fee is hereby granted, provided that the above
40 * copyright notice and this permission notice appear in all copies.
41 *
42 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
43 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
45 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
48 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49 */
50
51/*
52 * Copyright (c) 1997, 1998, 1999, 2000-2003
53 * Bill Paul <wpaul@windriver.com>. All rights reserved.
54 *
55 * Redistribution and use in source and binary forms, with or without
56 * modification, are permitted provided that the following conditions
57 * are met:
58 * 1. Redistributions of source code must retain the above copyright
59 * notice, this list of conditions and the following disclaimer.
60 * 2. Redistributions in binary form must reproduce the above copyright
61 * notice, this list of conditions and the following disclaimer in the
62 * documentation and/or other materials provided with the distribution.
63 * 3. All advertising materials mentioning features or use of this software
64 * must display the following acknowledgement:
65 * This product includes software developed by Bill Paul.
66 * 4. Neither the name of the author nor the names of any co-contributors
67 * may be used to endorse or promote products derived from this software
68 * without specific prior written permission.
69 *
70 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
71 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
74 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
75 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
76 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
77 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
78 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
79 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
80 * THE POSSIBILITY OF SUCH DAMAGE.
81 */
82
83#include <sys/cdefs.h>
84
85/*
86 * Moschip MCS7730/MCS7830 USB to Ethernet controller
87 * The datasheet is available at the following URL:
88 * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf
89 */
90
91#include <sys/stdint.h>
92#include <sys/stddef.h>
93#include <sys/param.h>
94#include <sys/queue.h>
95#include <sys/types.h>
96#include <sys/systm.h>
97#include <sys/kernel.h>
98#include <sys/bus.h>
99#include <sys/linker_set.h>
100#include <sys/module.h>
101#include <sys/lock.h>
102#include <sys/mutex.h>
103#include <sys/condvar.h>
104#include <sys/sysctl.h>
105#include <sys/sx.h>
106#include <sys/unistd.h>
107#include <sys/callout.h>
108#include <sys/malloc.h>
109#include <sys/priv.h>
110
111#include <dev/usb/usb.h>
112#include <dev/usb/usbdi.h>
113#include <dev/usb/usbdi_util.h>
114#include "usbdevs.h"
115
116#define USB_DEBUG_VAR mos_debug
117#include <dev/usb/usb_debug.h>
118#include <dev/usb/usb_process.h>
119
120#include <dev/usb/net/usb_ethernet.h>
121
122//#include <dev/usb/net/if_mosreg.h>
123#include "if_mosreg.h"
124
125#ifdef USB_DEBUG
126static int mos_debug = 10;
127
128SYSCTL_NODE(_hw_usb, OID_AUTO, mos, CTLFLAG_RW, 0, "USB mos");
129SYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RW, &mos_debug, 0,
130 "Debug level");
131#endif
132
133#define MOS_DPRINTFN(fmt,...) \
134 DPRINTF("mos: %s: " fmt "\n",__FUNCTION__,## __VA_ARGS__)
135
136#define USB_PRODUCT_MOSCHIP_MCS7730 0x7730 /* MCS7730 Ethernet */
137#define USB_PRODUCT_SITECOMEU_LN030 0x0021 /* LN-030 */
138
139
140
141/*
142 * Various supported device vendors/products.
143 */
144static const struct usb_device_id mos_devs[] = {
145 { USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730, MCS7730) },
146 { USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830 , MCS7830) },
147 { USB_VPI( USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030 , MCS7830) },
148};
149
150static int mos_probe(device_t dev);
151static int mos_attach(device_t dev);
152static void mos_attach_post(struct usb_ether *ue);
153static int mos_detach(device_t dev);
154
155static void mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error);
156static void mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error);
157static void mos_intr_callback(struct usb_xfer *xfer, usb_error_t error);
158static void mos_tick(struct usb_ether *);
159static void mos_start(struct usb_ether *);
160static void mos_init(struct usb_ether *);
161static void mos_chip_init(struct mos_softc *);
162static void mos_stop(struct usb_ether *);
163static int mos_miibus_readreg(device_t , int, int);
164static int mos_miibus_writereg(device_t , int, int, int);
165static void mos_miibus_statchg(device_t);
166static int mos_ifmedia_upd(struct ifnet *);
167static void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *);
168static void mos_reset(struct mos_softc *sc);
169
170static int mos_reg_read_1(struct mos_softc *, int);
171static int mos_reg_read_2(struct mos_softc *, int);
172static int mos_reg_write_1(struct mos_softc *, int, int);
173static int mos_reg_write_2(struct mos_softc *, int, int);
174static int mos_readmac(struct mos_softc *, uint8_t *);
175static int mos_writemac(struct mos_softc *, uint8_t *);
176static int mos_write_mcast(struct mos_softc *, u_char *);
177
178static void mos_setmulti(struct usb_ether *);
179static void mos_setpromisc(struct usb_ether *);
180
181static const struct usb_config mos_config[MOS_ENDPT_MAX] = {
182
183 [MOS_ENDPT_TX] = {
184 .type = UE_BULK,
185 .endpoint = UE_ADDR_ANY,
186 .direction = UE_DIR_OUT,
187 .bufsize = (MCLBYTES + 2),
188 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
189 .callback = mos_bulk_write_callback,
190 .timeout = 10000, /* 10 seconds */
191 },
192
193 [MOS_ENDPT_RX] = {
194 .type = UE_BULK,
195 .endpoint = UE_ADDR_ANY,
196 .direction = UE_DIR_IN,
197 .bufsize = (MCLBYTES + 4 + ETHER_CRC_LEN),
198 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
199 .callback = mos_bulk_read_callback,
200 },
201
202 [MOS_ENDPT_INTR] = {
203 .type = UE_INTERRUPT,
204 .endpoint = UE_ADDR_ANY,
205 .direction = UE_DIR_IN,
206 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
207 .bufsize = 0, /* use wMaxPacketSize */
208 .callback = mos_intr_callback,
209 },
210};
211
212static device_method_t mos_methods[] = {
213 /* Device interface */
214 DEVMETHOD(device_probe, mos_probe),
215 DEVMETHOD(device_attach, mos_attach),
216 DEVMETHOD(device_detach, mos_detach),
217
218 /* bus interface */
219 DEVMETHOD(bus_print_child, bus_generic_print_child),
220 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
221
222 /* MII interface */
223 DEVMETHOD(miibus_readreg, mos_miibus_readreg),
224 DEVMETHOD(miibus_writereg, mos_miibus_writereg),
225 DEVMETHOD(miibus_statchg, mos_miibus_statchg),
226
227 {0, 0}
228};
229
230static driver_t mos_driver = {
231 .name = "mos",
232 .methods = mos_methods,
233 .size = sizeof(struct mos_softc)
234};
235
236static devclass_t mos_devclass;
237
238DRIVER_MODULE(mos, uhub, mos_driver, mos_devclass, NULL, 0);
239DRIVER_MODULE(miibus, mos, miibus_driver, miibus_devclass, 0, 0);
240MODULE_DEPEND(mos, uether, 1, 1, 1);
241MODULE_DEPEND(mos, usb, 1, 1, 1);
242MODULE_DEPEND(mos, ether, 1, 1, 1);
243MODULE_DEPEND(mos, miibus, 1, 1, 1);
244
245static const struct usb_ether_methods mos_ue_methods = {
246 .ue_attach_post = mos_attach_post,
247 .ue_start = mos_start,
248 .ue_init = mos_init,
249 .ue_stop = mos_stop,
250 .ue_tick = mos_tick,
251 .ue_setmulti = mos_setmulti,
252 .ue_setpromisc = mos_setpromisc,
253 .ue_mii_upd = mos_ifmedia_upd,
254 .ue_mii_sts = mos_ifmedia_sts,
255};
256
257
258static int
259mos_reg_read_1(struct mos_softc *sc, int reg)
260{
261 struct usb_device_request req;
262 usb_error_t err;
263 uByte val = 0;
264
265 req.bmRequestType = UT_READ_VENDOR_DEVICE;
266 req.bRequest = MOS_UR_READREG;
267 USETW(req.wValue, 0);
268 USETW(req.wIndex, reg);
269 USETW(req.wLength, 1);
270
271 err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
272
273 if (err) {
274 MOS_DPRINTFN("mos_reg_read_1 error, reg: %d\n", reg);
275 return (-1);
276 }
277
278 return (val);
279}
280
281static int
282mos_reg_read_2(struct mos_softc *sc, int reg)
283{
284 struct usb_device_request req;
285 usb_error_t err;
286 uWord val;
287
288 USETW(val,0);
289
290 req.bmRequestType = UT_READ_VENDOR_DEVICE;
291 req.bRequest = MOS_UR_READREG;
292 USETW(req.wValue, 0);
293 USETW(req.wIndex, reg);
294 USETW(req.wLength, 2);
295
296 err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
297
298 if (err) {
299 MOS_DPRINTFN("mos_reg_read_2 error, reg: %d", reg);
300 return (-1);
301 }
302
303 return(UGETW(val));
304}
305
306static int
307mos_reg_write_1(struct mos_softc *sc, int reg, int aval)
308{
309 struct usb_device_request req;
310 usb_error_t err;
311 uByte val;
312
313 val = aval;
314
315 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
316 req.bRequest = MOS_UR_WRITEREG;
317 USETW(req.wValue, 0);
318 USETW(req.wIndex, reg);
319 USETW(req.wLength, 1);
320
321 err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
322
323 if (err) {
324 MOS_DPRINTFN("mos_reg_write_1 error, reg: %d", reg);
325 return (-1);
326 }
327
328 return(0);
329}
330
331static int
332mos_reg_write_2(struct mos_softc *sc, int reg, int aval)
333{
334 struct usb_device_request req;
335 usb_error_t err;
336 uWord val;
337
338 USETW(val, aval);
339
340 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
341 req.bRequest = MOS_UR_WRITEREG;
342 USETW(req.wValue, 0);
343 USETW(req.wIndex, reg);
344 USETW(req.wLength, 2);
345
346 err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
347
348 if (err) {
349 MOS_DPRINTFN("mos_reg_write_2 error, reg: %d", reg);
350 return (-1);
351 }
352
353 return (0);
354}
355
356static int
357mos_readmac(struct mos_softc *sc, u_char *mac)
358{
359 struct usb_device_request req;
360 usb_error_t err;
361
362 req.bmRequestType = UT_READ_VENDOR_DEVICE;
363 req.bRequest = MOS_UR_READREG;
364 USETW(req.wValue, 0);
365 USETW(req.wIndex, MOS_MAC);
366 USETW(req.wLength, ETHER_ADDR_LEN);
367
368 err = uether_do_request(&sc->sc_ue, &req, mac, 1000);
369
370 if (err) {
371 return (-1);
372 }
373
374 return (0);
375}
376
377static int
378mos_writemac(struct mos_softc *sc, uint8_t *mac)
379{
380 struct usb_device_request req;
381 usb_error_t err;
382
383 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
384 req.bRequest = MOS_UR_WRITEREG;
385 USETW(req.wValue, 0);
386 USETW(req.wIndex, MOS_MAC);
387 USETW(req.wLength, ETHER_ADDR_LEN);
388
389 err = uether_do_request(&sc->sc_ue, &req, mac, 1000);
390
391 if (err) {
392 MOS_DPRINTFN("mos_writemac error");
393 return (-1);
394 }
395
396 return (0);
397}
398
399static int
400mos_write_mcast(struct mos_softc *sc, u_char *hashtbl)
401{
402 struct usb_device_request req;
403 usb_error_t err;
404
405 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
406 req.bRequest = MOS_UR_WRITEREG;
407 USETW(req.wValue, 0);
408 USETW(req.wIndex, MOS_MCAST_TABLE);
409 USETW(req.wLength, 8);
410
411 err = uether_do_request(&sc->sc_ue, &req, hashtbl, 1000);
412
413 if (err) {
414 MOS_DPRINTFN("mos_reg_mcast error");
415 return(-1);
416 }
417
418 return(0);
419}
420
421static int
422mos_miibus_readreg(struct device *dev, int phy, int reg)
423{
424 struct mos_softc *sc = device_get_softc(dev);
425 uWord val;
426 int i,res, locked;
427
428 USETW(val, 0);
429
430 locked = mtx_owned(&sc->sc_mtx);
431 if (!locked)
432 MOS_LOCK(sc);
433
434 mos_reg_write_2(sc, MOS_PHY_DATA, 0);
435 mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
436 MOS_PHYCTL_READ);
437 mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
438 MOS_PHYSTS_PENDING);
439
440 for (i = 0; i < MOS_TIMEOUT; i++) {
441 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
442 break;
443 }
444 if (i == MOS_TIMEOUT) {
445 MOS_DPRINTFN("MII read timeout");
446 }
447
448 res = mos_reg_read_2(sc, MOS_PHY_DATA);
449
450 if (!locked)
451 MOS_UNLOCK(sc);
452 return (res);
453}
454
455static int
456mos_miibus_writereg(device_t dev, int phy, int reg, int val)
457{
458 struct mos_softc *sc = device_get_softc(dev);
459 int i, locked;
460
461 locked = mtx_owned(&sc->sc_mtx);
462 if (!locked)
463 MOS_LOCK(sc);
464
465 mos_reg_write_2(sc, MOS_PHY_DATA, val);
466 mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
467 MOS_PHYCTL_WRITE);
468 mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
469 MOS_PHYSTS_PENDING);
470
471 for (i = 0; i < MOS_TIMEOUT; i++) {
472 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
473 break;
474 }
475 if (i == MOS_TIMEOUT) {
476 MOS_DPRINTFN("MII write timeout");
477 }
478
479 if (!locked)
480 MOS_UNLOCK(sc);
481 return 0;
482}
483
484static void
485mos_miibus_statchg(device_t dev)
486{
487 struct mos_softc *sc = device_get_softc(dev);
488 struct mii_data *mii = GET_MII(sc);
489 int val, err, locked;
490
491 locked = mtx_owned(&sc->sc_mtx);
492 if (!locked)
493 MOS_LOCK(sc);
494
495 /* disable RX, TX prior to changing FDX, SPEEDSEL */
496 val = mos_reg_read_1(sc, MOS_CTL);
497 val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
498 mos_reg_write_1(sc, MOS_CTL, val);
499
500 /* reset register which counts dropped frames */
501 mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
502
503 if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
504 val |= MOS_CTL_FDX_ENB;
505 else
506 val &= ~(MOS_CTL_FDX_ENB);
507
508 switch (IFM_SUBTYPE(mii->mii_media_active)) {
509 case IFM_100_TX:
510 val |= MOS_CTL_SPEEDSEL;
511 break;
512 case IFM_10_T:
513 val &= ~(MOS_CTL_SPEEDSEL);
514 break;
515 }
516
517 /* re-enable TX, RX */
518 val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
519 err = mos_reg_write_1(sc, MOS_CTL, val);
520
521 if (err)
522 MOS_DPRINTFN("media change failed");
523
524 if (!locked)
525 MOS_UNLOCK(sc);
526}
527
528/*
529 * Set media options.
530 */
531static int
532mos_ifmedia_upd(struct ifnet *ifp)
533{
534 struct mos_softc *sc = ifp->if_softc;
535 struct mii_data *mii = GET_MII(sc);
536
537 MOS_LOCK_ASSERT(sc, MA_OWNED);
538
539 sc->mos_link = 0;
540 if (mii->mii_instance) {
541 struct mii_softc *miisc;
542
543 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
544 mii_phy_reset(miisc);
545 }
546 mii_mediachg(mii);
547 return (0);
548}
549
550/*
551 * Report current media status.
552 */
553static void
554mos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
555{
556 struct mos_softc *sc = ifp->if_softc;
557 struct mii_data *mii = GET_MII(sc);
558
559 MOS_LOCK(sc);
560 mii_pollstat(mii);
561 MOS_UNLOCK(sc);
562
563 ifmr->ifm_active = mii->mii_media_active;
564 ifmr->ifm_status = mii->mii_media_status;
565}
566
567static void
568mos_setpromisc(struct usb_ether *ue)
569{
570 struct mos_softc *sc = uether_getsc(ue);
571 struct ifnet *ifp = uether_getifp(ue);
572
573 u_int8_t rxmode;
574
575 MOS_LOCK_ASSERT(sc, MA_OWNED);
576
577 rxmode = mos_reg_read_1(sc, MOS_CTL);
578
579 /* If we want promiscuous mode, set the allframes bit. */
580 if (ifp->if_flags & IFF_PROMISC) {
581 rxmode |= MOS_CTL_RX_PROMISC;
582 } else {
583 rxmode &= ~MOS_CTL_RX_PROMISC;
584 }
585
586 mos_reg_write_1(sc, MOS_CTL, rxmode);
587}
588
589
590
591static void
592mos_setmulti(struct usb_ether *ue)
593{
594 struct mos_softc *sc = uether_getsc(ue);
595 struct ifnet *ifp = uether_getifp(ue);
596 struct ifmultiaddr *ifma;
597
598 u_int32_t h = 0;
599 u_int8_t rxmode;
600 u_int8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
601 int allmulti = 0;
602
603 MOS_LOCK_ASSERT(sc, MA_OWNED);
604
605 rxmode = mos_reg_read_1(sc, MOS_CTL);
606
607 if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC)
608 allmulti = 1;
609
610 /* get all new ones */
611 if_maddr_rlock(ifp);
612 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
613 if (ifma->ifma_addr->sa_family != AF_LINK) {
614 allmulti = 1;
615 continue;
616 };
617 h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
618 ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
619 //h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
620 hashtbl[h / 8] |= 1 << (h % 8);
621 }
622 if_maddr_runlock(ifp);
623
624 /* now program new ones */
625 if (allmulti == 1) {
626 rxmode |= MOS_CTL_ALLMULTI;
627 mos_reg_write_1(sc, MOS_CTL, rxmode);
628 } else {
629 rxmode &= ~MOS_CTL_ALLMULTI;
630 mos_write_mcast(sc, (void *)&hashtbl);
631 mos_reg_write_1(sc, MOS_CTL, rxmode);
632 }
633}
634
635static void
636mos_reset(struct mos_softc *sc)
637{
638 u_int8_t ctl;
639
640 ctl = mos_reg_read_1(sc, MOS_CTL);
641 ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB |
642 MOS_CTL_RX_ENB);
643 /* Disable RX, TX, promiscuous and allmulticast mode */
644 mos_reg_write_1(sc, MOS_CTL, ctl);
645
646 /* Reset frame drop counter register to zero */
647 mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
648
649 /* Wait a little while for the chip to get its brains in order. */
650 DELAY(1000);
651 return;
652}
653
654static void
655mos_chip_init(struct mos_softc *sc)
656{
657 int i;
658
659 /*
660 * Rev.C devices have a pause threshold register which needs to be set
661 * at startup.
662 */
663 if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) {
664 for (i=0;i<MOS_PAUSE_REWRITES;i++)
665 mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0);
666 }
667
668 sc->mos_phyaddrs[0] = 1; sc->mos_phyaddrs[1] = 0xFF;
669}
670
671/*
672 * Probe for a MCS7x30 chip.
673 */
674static int
675mos_probe(device_t dev)
676{
677 DPRINTFN(11, "mos: probe\n");
678 struct usb_attach_arg *uaa = device_get_ivars(dev);
679
680 if (uaa->usb_mode != USB_MODE_HOST) {
681 DPRINTFN(11, "mos: not USB_MODE_HOST\n");
682 return (ENXIO);
683 }
684 //uint8_t bIfaceIndex;
685 //uint8_t bIfaceNum;
686 //uint8_t bConfigIndex;
687 //uint8_t bConfigNum;
688
689 if (uaa->info.bConfigNum != MOS_CONFIG_NO) {
690 DPRINTFN(11, "mos: not MOS_CONFIG_NO %i vs %i\n", uaa->info.bConfigNum , MOS_CONFIG_NO);
691 return (ENXIO);
692 }
693 if (uaa->info.bIfaceIndex != MOS_IFACE_IDX) {
694 DPRINTFN(11, "mos: not MOS_IFACE_IDX %i vs %i\n", uaa->info.bIfaceIndex, MOS_IFACE_IDX);
695 return (ENXIO);
696 }
697
698 DPRINTFN(11, "mos: probe by generic means\n");
699 int retval = usbd_lookup_id_by_uaa(mos_devs, sizeof(mos_devs), uaa);
700 DPRINTFN(11, "mos: probe retval: %i (ENXIO:%i)\n", retval, ENXIO);
701 return retval;
702}
703
704/*
705 * Attach the interface. Allocate softc structures, do ifmedia
706 * setup and ethernet/BPF attach.
707 */
708static int
709mos_attach(device_t dev)
710{
711 struct usb_attach_arg *uaa = device_get_ivars(dev);
712 struct mos_softc *sc = device_get_softc(dev);
713 struct usb_ether *ue = &sc->sc_ue;
714
715 uint8_t iface_index;
716 int error;
717
718 sc->mos_flags = USB_GET_DRIVER_INFO(uaa);
719
720 device_set_usb_desc(dev);
721 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
722
723 iface_index = MOS_IFACE_IDX;
724 error = usbd_transfer_setup(uaa->device, &iface_index,
725 sc->sc_xfer, mos_config, MOS_ENDPT_MAX,
726 sc, &sc->sc_mtx);
727
728 if (error) {
729 device_printf(dev, "allocating USB transfers failed\n");
730 goto detach;
731 }
732
733 ue->ue_sc = sc;
734 ue->ue_dev = dev;
735 ue->ue_udev = uaa->device;
736 ue->ue_mtx = &sc->sc_mtx;
737 ue->ue_methods = &mos_ue_methods;
738
739
740 if (sc->mos_flags & MCS7730) {
741 DPRINTF("model: MCS7730\n");
742 } else if (sc->mos_flags & MCS7830) {
743 DPRINTF("model: MCS7830\n");
744 }
745
746 error = uether_ifattach(ue);
747 if (error) {
748 device_printf(dev, "could not attach interface\n");
749 goto detach;
750 }
751 return (0); /* success */
752
753
754detach:
755 mos_detach(dev);
756 return (ENXIO); /* failure */
757}
758
759
760static void
761mos_attach_post(struct usb_ether *ue)
762{
763 struct mos_softc *sc = uether_getsc(ue);
764 /*
765 * Read MAC address, inform the world.
766 */
767 int err = mos_readmac(sc, ue->ue_eaddr);
768 if (err) {
769 MOS_DPRINTFN("couldn't get MAC address");
770 }
771 MOS_DPRINTFN("address: %s", ether_sprintf(ue->ue_eaddr));
772
773 mos_chip_init(sc);
774
775 // ifp = GET_IFP(sc);
776 // ifp->if_softc = sc;
777 // ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST;
778 // ifp->if_ioctl = mos_ioctl;
779 // ifp->if_start = mos_start;
780 // ifp->if_watchdog = mos_watchdog;
781 // strlcpy(ifp->if_xname, sc->mos_dev.dv_xname, IFNAMSIZ);
782
783 // IFQ_SET_READY(&ifp->if_snd);
784 // ifp->if_capabilities = IFCAP_VLAN_MTU;
785
786 sc->mos_attached = 1;
787}
788
789static int
790mos_detach(device_t dev)
791{
792 struct mos_softc *sc = device_get_softc(dev);
793 struct usb_ether *ue = &sc->sc_ue;
794
795 usbd_transfer_unsetup(sc->sc_xfer, MOS_ENDPT_MAX);
796 uether_ifdetach(ue);
797 mtx_destroy(&sc->sc_mtx);
798
799 return (0);
800}
801
802
803
804
805/*
806 * A frame has been uploaded: pass the resulting mbuf chain up to
807 * the higher level protocols.
808 */
809static void
810mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
811{
812 struct mos_softc *sc = usbd_xfer_softc(xfer);
813 struct usb_ether *ue = &sc->sc_ue;
814 struct ifnet *ifp = uether_getifp(ue);
815
816 uint8_t rxstat = 0;
817 uint32_t actlen;
818 uint16_t pktlen = 0;
819 struct usb_page_cache *pc;
820
821
822 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
823 pc = usbd_xfer_get_frame(xfer, 0);
824
825 switch (USB_GET_STATE(xfer)) {
826 case USB_ST_TRANSFERRED:
827 MOS_DPRINTFN("actlen : %d", actlen);
828 if (actlen <= 1) {
829 ifp->if_ierrors++;
830 goto tr_setup;
831 }
832
833 /* evaluate status byte at the end */
834 usbd_copy_out(pc, actlen - sizeof(rxstat), &rxstat,
835 sizeof(rxstat));
836
837 if (rxstat != MOS_RXSTS_VALID) {
838 MOS_DPRINTFN("erroneous frame received");
839 if (rxstat & MOS_RXSTS_SHORT_FRAME)
840 MOS_DPRINTFN("frame size less than 64 bytes");
841 if (rxstat & MOS_RXSTS_LARGE_FRAME)
842 MOS_DPRINTFN("frame size larger than 1532 bytes");
843 if (rxstat & MOS_RXSTS_CRC_ERROR)
844 MOS_DPRINTFN("CRC error");
845 if (rxstat & MOS_RXSTS_ALIGN_ERROR)
846 MOS_DPRINTFN("alignment error");
847 ifp->if_ierrors++;
848 goto tr_setup;
849 }
850
851 /* Remember the last byte was used for the status fields */
852 pktlen = actlen - 1;
853 if ( pktlen < sizeof(struct ether_header) ) {
854 MOS_DPRINTFN("error: pktlen %i is smaller than ether_header %i", pktlen, sizeof(struct ether_header));
855 ifp->if_ierrors++;
856 goto tr_setup;
857 }
858
859 uether_rxbuf(ue, pc, 0, actlen);
860 /* FALLTHROUGH */
861 case USB_ST_SETUP:
862tr_setup:
863 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
864 usbd_transfer_submit(xfer);
865 uether_rxflush(ue);
866 return;
867 default: /* Error */
868 MOS_DPRINTFN("bulk read error, %s", usbd_errstr(error));
869 if (error != USB_ERR_CANCELLED) {
870 /* try to clear stall first */
871 usbd_xfer_set_stall(xfer);
872 goto tr_setup;
873 }
874 MOS_DPRINTFN("start rx %i", usbd_xfer_max_len(xfer));
875 return;
876 }
877}
878
879/*
880 * A frame was downloaded to the chip. It's safe for us to clean up
881 * the list buffers.
882 */
883
884static void
885mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
886{
887 struct mos_softc *sc = usbd_xfer_softc(xfer);
888 struct ifnet *ifp = uether_getifp(&sc->sc_ue);
889 struct usb_page_cache *pc;
890 struct mbuf *m;
891
892
893
894 switch (USB_GET_STATE(xfer)) {
895 case USB_ST_TRANSFERRED:
896 MOS_DPRINTFN("transfer of complete");
897 ifp->if_opackets++;
898 /* FALLTHROUGH */
899 case USB_ST_SETUP:
900tr_setup:
901 /*
902 * XXX: don't send anything if there is no link?
903 */
904 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
905 if (m == NULL)
906 return;
907
908 pc = usbd_xfer_get_frame(xfer, 0);
909 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
910
911 usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
912
913
914 /*
915 * if there's a BPF listener, bounce a copy
916 * of this frame to him:
917 */
918 BPF_MTAP(ifp, m);
919
920 m_freem(m);
921
922 usbd_transfer_submit(xfer);
923
924 ifp->if_opackets++;
925 return;
926 default: /* Error */
927 MOS_DPRINTFN("usb error on tx: %s\n", usbd_errstr(error));
928 ifp->if_oerrors++;
929 if (error != USB_ERR_CANCELLED) {
930 /* try to clear stall first */
931 usbd_xfer_set_stall(xfer);
932 goto tr_setup;
933 }
934 return;
935 }
936}
937
938static void
939mos_tick(struct usb_ether *ue)
940{
941 struct mos_softc *sc = uether_getsc(ue);
942 struct mii_data *mii = GET_MII(sc);
943
944 MOS_LOCK_ASSERT(sc, MA_OWNED);
945
946 mii_tick(mii);
947 if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE &&
948 IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
949 MOS_DPRINTFN("got link");
950 sc->mos_link++;
951 mos_start(ue);
952 }
953}
954
955
956static void
957mos_start(struct usb_ether *ue)
958{
959 struct mos_softc *sc = uether_getsc(ue);
960
961 /*
962 * start the USB transfers, if not already started:
963 */
964 usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_TX]);
965 usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_RX]);
966 usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_INTR]);
967}
968
969static void
970mos_init(struct usb_ether *ue)
971{
972 struct mos_softc *sc = uether_getsc(ue);
973 struct ifnet *ifp = uether_getifp(ue);
974 u_int8_t rxmode;
975
976 MOS_LOCK_ASSERT(sc, MA_OWNED);
977
978 /*
979 * Cancel pending I/O and free all RX/TX buffers.
980 */
981 mos_reset(sc);
982
983 /*
984 * Write MAC address
985 */
986 mos_writemac(sc, IF_LLADDR(ifp));
987
988
989
990 /* Read and set transmitter IPG values */
991 sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0);
992 sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1);
993 mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]);
994 mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]);
995
996 /* Enable receiver and transmitter, bridge controls speed/duplex mode */
997 rxmode = mos_reg_read_1(sc, MOS_CTL);
998 rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB;
999 rxmode &= ~(MOS_CTL_SLEEP);
1000
1001 mos_setpromisc(ue);
1002
1003 /* XXX: broadcast mode? */
1004
1005 mos_reg_write_1(sc, MOS_CTL, rxmode);
1006
1007 /* Load the multicast filter. */
1008 mos_setmulti(ue);
1009
1010 ifp->if_drv_flags |= IFF_DRV_RUNNING;
1011 mos_start(ue);
1012}
1013
1014
1015static void
1016mos_intr_callback(struct usb_xfer *xfer, usb_error_t error)
1017{
1018 struct mos_softc *sc = usbd_xfer_softc(xfer);
1019 struct ifnet *ifp = uether_getifp(&sc->sc_ue);
1020 struct usb_page_cache *pc;
1021 int actlen;
1022 long pkt;
1023
1024 ifp->if_oerrors++;
1025
1026 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1027 MOS_DPRINTFN("actlen %i", actlen);
1028
1029 switch (USB_GET_STATE(xfer)) {
1030 case USB_ST_TRANSFERRED:
1031
1032 pc = usbd_xfer_get_frame(xfer, 0);
1033 usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
1034 /* FALLTHROUGH */
1035 case USB_ST_SETUP:
1036tr_setup:
1037 return;
1038 default: /* Error */
1039 if (error != USB_ERR_CANCELLED) {
1040 /* try to clear stall first */
1041 usbd_xfer_set_stall(xfer);
1042 goto tr_setup;
1043 }
1044 return;
1045 }
1046}
1047
1048
1049/*
1050 * Stop the adapter and free any mbufs allocated to the
1051 * RX and TX lists.
1052 */
1053static void
1054mos_stop(struct usb_ether *ue)
1055{
1056 struct mos_softc *sc = uether_getsc(ue);
1057 struct ifnet *ifp = uether_getifp(ue);
1058
1059 mos_reset(sc);
1060
1061 MOS_LOCK_ASSERT(sc, MA_OWNED);
1062 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1063
1064 /*
1065 * stop all the transfers, if not already stopped:
1066 */
1067 usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_TX]);
1068 usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_RX]);
1069 usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_INTR]);
1070
1071 sc->mos_link = 0;
1072}
1073
Note: See TracBrowser for help on using the repository browser.