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

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

Get rid of the MACRO functions defined in usbdevs

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