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

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

Initial import code for mos(4) driver USB to Ethernet module

File size: 25.9 KB
RevLine 
[171]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) 2010 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 USB_PRODUCT_MOSCHIP_MCS7730 0x7730 /* MCS7730 Ethernet */
134#define USB_PRODUCT_SITECOMEU_LN030 0x0021 /* LN-030 */
135
136
137
138/*
139 * Various supported device vendors/products.
140 */
141static const struct usb_device_id mos_devs[] = {
142 { USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730, MCS7730) },
143 { USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830 , MCS7830) },
144 { USB_VPI( USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030 , MCS7830) },
145};
146
147int mos_probe(device_t dev);
148int mos_attach(device_t dev);
149void mos_attach_post(struct usb_ether *ue);
150int mos_detach(device_t dev);
151
152int mos_encap(struct mos_softc *, struct mbuf *, int);
153void mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error);
154void mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error);
155void mos_intr_callback(struct usb_xfer *xfer, usb_error_t error);
156void mos_tick(struct usb_ether *);
157void mos_start(struct usb_ether *);
158void mos_init(struct usb_ether *);
159void mos_chip_init(struct mos_softc *);
160void mos_stop(struct usb_ether *);
161void mos_watchdog(struct usb_ether *);
162int mos_miibus_readreg(device_t , int, int);
163int mos_miibus_writereg(device_t , int, int, int);
164void mos_miibus_statchg(device_t);
165int mos_ifmedia_upd(struct ifnet *);
166void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *);
167void mos_reset(struct mos_softc *sc);
168
169int mos_reg_read_1(struct mos_softc *, int);
170int mos_reg_read_2(struct mos_softc *, int);
171int mos_reg_write_1(struct mos_softc *, int, int);
172int mos_reg_write_2(struct mos_softc *, int, int);
173int mos_readmac(struct mos_softc *, u_char *);
174int mos_writemac(struct mos_softc *, u_char *);
175int mos_write_mcast(struct mos_softc *, u_char *);
176
177void mos_setmulti(struct usb_ether *);
178
179static const struct usb_config mos_config[MOS_ENDPT_MAX] = {
180
181 [MOS_ENDPT_TX] = {
182 .type = UE_BULK,
183 .endpoint = UE_ADDR_ANY,
184 .direction = UE_DIR_OUT,
185 .bufsize = (MCLBYTES + 2),
186 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
187 .callback = mos_bulk_write_callback,
188 .timeout = 10000, /* 10 seconds */
189 },
190
191 [MOS_ENDPT_RX] = {
192 .type = UE_BULK,
193 .endpoint = UE_ADDR_ANY,
194 .direction = UE_DIR_IN,
195 .bufsize = (MCLBYTES + 4 + ETHER_CRC_LEN),
196 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
197 .callback = mos_bulk_read_callback,
198 },
199
200 [MOS_ENDPT_INTR] = {
201 .type = UE_INTERRUPT,
202 .endpoint = UE_ADDR_ANY,
203 .direction = UE_DIR_IN,
204 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
205 .bufsize = 0, /* use wMaxPacketSize */
206 .callback = mos_intr_callback,
207 },
208};
209
210static device_method_t mos_methods[] = {
211 /* Device interface */
212 DEVMETHOD(device_probe, mos_probe),
213 DEVMETHOD(device_attach, mos_attach),
214 DEVMETHOD(device_detach, mos_detach),
215
216 /* bus interface */
217 DEVMETHOD(bus_print_child, bus_generic_print_child),
218 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
219
220 /* MII interface */
221 DEVMETHOD(miibus_readreg, mos_miibus_readreg),
222 DEVMETHOD(miibus_writereg, mos_miibus_writereg),
223 DEVMETHOD(miibus_statchg, mos_miibus_statchg),
224
225 {0, 0}
226};
227
228static driver_t mos_driver = {
229 .name = "mos",
230 .methods = mos_methods,
231 .size = sizeof(struct mos_softc)
232};
233
234static devclass_t mos_devclass;
235
236DRIVER_MODULE(mos, uhub, mos_driver, mos_devclass, NULL, 0);
237DRIVER_MODULE(miibus, mos, miibus_driver, miibus_devclass, 0, 0);
238MODULE_DEPEND(mos, uether, 1, 1, 1);
239MODULE_DEPEND(mos, usb, 1, 1, 1);
240MODULE_DEPEND(mos, ether, 1, 1, 1);
241MODULE_DEPEND(mos, miibus, 1, 1, 1);
242
243static const struct usb_ether_methods mos_ue_methods = {
244 .ue_attach_post = mos_attach_post,
245 .ue_start = mos_start,
246 .ue_init = mos_init,
247 .ue_stop = mos_stop,
248 .ue_tick = mos_tick,
249 .ue_setmulti = mos_setmulti,
250 //.ue_setpromisc = mos_setpromisc,
251 .ue_mii_upd = mos_ifmedia_upd,
252 .ue_mii_sts = mos_ifmedia_sts,
253};
254
255
256int
257mos_reg_read_1(struct mos_softc *sc, int reg)
258{
259 struct usb_device_request req;
260 usb_error_t err;
261 uByte val = 0;
262
263 req.bmRequestType = UT_READ_VENDOR_DEVICE;
264 req.bRequest = MOS_UR_READREG;
265 USETW(req.wValue, 0);
266 USETW(req.wIndex, reg);
267 USETW(req.wLength, 1);
268
269 err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
270
271 if (err) {
272 DPRINTF("mos_reg_read_1 error, reg: %d\n", reg);
273 return (-1);
274 }
275
276 return (val);
277}
278
279int
280mos_reg_read_2(struct mos_softc *sc, int reg)
281{
282 struct usb_device_request req;
283 usb_error_t err;
284 uWord val;
285
286 USETW(val,0);
287
288 req.bmRequestType = UT_READ_VENDOR_DEVICE;
289 req.bRequest = MOS_UR_READREG;
290 USETW(req.wValue, 0);
291 USETW(req.wIndex, reg);
292 USETW(req.wLength, 2);
293
294 err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
295
296 if (err) {
297 DPRINTF("mos_reg_read_2 error, reg: %d\n", reg);
298 return (-1);
299 }
300
301 return(UGETW(val));
302}
303
304int
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
311 val = aval;
312
313 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
314 req.bRequest = MOS_UR_WRITEREG;
315 USETW(req.wValue, 0);
316 USETW(req.wIndex, reg);
317 USETW(req.wLength, 1);
318
319 err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
320
321 if (err) {
322 DPRINTF("mos_reg_write_1 error, reg: %d\n", reg);
323 return (-1);
324 }
325
326 return(0);
327}
328
329int
330mos_reg_write_2(struct mos_softc *sc, int reg, int aval)
331{
332 struct usb_device_request req;
333 usb_error_t err;
334 uWord val;
335
336 USETW(val, aval);
337
338 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
339 req.bRequest = MOS_UR_WRITEREG;
340 USETW(req.wValue, 0);
341 USETW(req.wIndex, reg);
342 USETW(req.wLength, 2);
343
344 err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
345
346 if (err) {
347 DPRINTF("mos_reg_write_2 error, reg: %d\n", reg);
348 return (-1);
349 }
350
351 return (0);
352}
353
354int
355mos_readmac(struct mos_softc *sc, u_char *mac)
356{
357 struct usb_device_request req;
358 usb_error_t err;
359
360 req.bmRequestType = UT_READ_VENDOR_DEVICE;
361 req.bRequest = MOS_UR_READREG;
362 USETW(req.wValue, 0);
363 USETW(req.wIndex, MOS_MAC);
364 USETW(req.wLength, ETHER_ADDR_LEN);
365
366 err = uether_do_request(&sc->sc_ue, &req, mac, 1000);
367
368 if (err) {
369 DPRINTF("mos_readmac error");
370 return (-1);
371 }
372
373 return (0);
374}
375
376int
377mos_writemac(struct mos_softc *sc, u_char *mac)
378{
379 struct usb_device_request req;
380 usb_error_t err;
381
382 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
383 req.bRequest = MOS_UR_WRITEREG;
384 USETW(req.wValue, 0);
385 USETW(req.wIndex, MOS_MAC);
386 USETW(req.wLength, ETHER_ADDR_LEN);
387
388 err = uether_do_request(&sc->sc_ue, &req, mac, 1000);
389
390 if (err) {
391 DPRINTF("mos_writemac error");
392 return (-1);
393 }
394
395 return (0);
396}
397
398int
399mos_write_mcast(struct mos_softc *sc, u_char *hashtbl)
400{
401 struct usb_device_request req;
402 usb_error_t err;
403
404 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
405 req.bRequest = MOS_UR_WRITEREG;
406 USETW(req.wValue, 0);
407 USETW(req.wIndex, MOS_MCAST_TABLE);
408 USETW(req.wLength, 8);
409
410 err = uether_do_request(&sc->sc_ue, &req, hashtbl, 1000);
411
412 if (err) {
413 DPRINTF("mos_reg_mcast error\n");
414 return(-1);
415 }
416
417 return(0);
418}
419
420int
421mos_miibus_readreg(struct device *dev, int phy, int reg)
422{
423 struct mos_softc *sc = (void *)dev;
424 uWord val;
425 int i,res, locked;
426
427 USETW(val, 0);
428
429 locked = mtx_owned(&sc->sc_mtx);
430 if (!locked)
431 MOS_LOCK(sc);
432
433 mos_reg_write_2(sc, MOS_PHY_DATA, 0);
434 mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
435 MOS_PHYCTL_READ);
436 mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
437 MOS_PHYSTS_PENDING);
438
439 for (i = 0; i < MOS_TIMEOUT; i++) {
440 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
441 break;
442 }
443 if (i == MOS_TIMEOUT) {
444 printf("%s: MII read timeout\n", "mos");
445 }
446
447 res = mos_reg_read_2(sc, MOS_PHY_DATA);
448
449 if (!locked)
450 MOS_UNLOCK(sc);
451 return (res);
452}
453
454int
455mos_miibus_writereg(device_t dev, int phy, int reg, int val)
456{
457 struct mos_softc *sc = (void *)dev;
458 int i, locked;
459
460 locked = mtx_owned(&sc->sc_mtx);
461 if (!locked)
462 MOS_LOCK(sc);
463
464 mos_reg_write_2(sc, MOS_PHY_DATA, val);
465 mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
466 MOS_PHYCTL_WRITE);
467 mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
468 MOS_PHYSTS_PENDING);
469
470 for (i = 0; i < MOS_TIMEOUT; i++) {
471 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
472 break;
473 }
474 if (i == MOS_TIMEOUT) {
475 printf("%s: MII write timeout\n", "mos");
476 }
477
478 if (!locked)
479 MOS_UNLOCK(sc);
480 return 0;
481}
482
483void
484mos_miibus_statchg(device_t dev)
485{
486 struct mos_softc *sc = device_get_softc(dev);
487 struct mii_data *mii = GET_MII(sc);
488 int val, err, locked;
489
490 locked = mtx_owned(&sc->sc_mtx);
491 if (!locked)
492 MOS_LOCK(sc);
493
494 /* disable RX, TX prior to changing FDX, SPEEDSEL */
495 val = mos_reg_read_1(sc, MOS_CTL);
496 val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
497 mos_reg_write_1(sc, MOS_CTL, val);
498
499 /* reset register which counts dropped frames */
500 mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
501
502 if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
503 val |= MOS_CTL_FDX_ENB;
504 else
505 val &= ~(MOS_CTL_FDX_ENB);
506
507 switch (IFM_SUBTYPE(mii->mii_media_active)) {
508 case IFM_100_TX:
509 val |= MOS_CTL_SPEEDSEL;
510 break;
511 case IFM_10_T:
512 val &= ~(MOS_CTL_SPEEDSEL);
513 break;
514 }
515
516 /* re-enable TX, RX */
517 val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
518 err = mos_reg_write_1(sc, MOS_CTL, val);
519 MOS_UNLOCK(sc);
520
521 if (err)
522 printf("%s: media change failed\n", "mos");
523
524 if (!locked)
525 MOS_UNLOCK(sc);
526}
527
528/*
529 * Set media options.
530 */
531int
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 sc->mos_link = 0;
538 if (mii->mii_instance) {
539 struct mii_softc *miisc;
540 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
541 mii_phy_reset(miisc);
542 }
543 mii_mediachg(mii);
544
545 return (0);
546}
547
548/*
549 * Report current media status.
550 */
551void
552mos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
553{
554 struct mos_softc *sc = ifp->if_softc;
555 struct mii_data *mii = GET_MII(sc);
556
557 mii_pollstat(mii);
558 ifmr->ifm_active = mii->mii_media_active;
559 ifmr->ifm_status = mii->mii_media_status;
560}
561
562void
563mos_setmulti(struct usb_ether *ue)
564{
565 struct mos_softc *sc = uether_getsc(ue);
566 struct ifnet *ifp = uether_getifp(ue);
567 //struct ether_multi *enm;
568 struct ifmultiaddr *ifma;
569 u_int32_t h = 0;
570 u_int8_t rxmode;
571 u_int8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
572
573
574 rxmode = mos_reg_read_1(sc, MOS_CTL);
575
576 if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
577allmulti:
578 rxmode |= MOS_CTL_ALLMULTI;
579 mos_reg_write_1(sc, MOS_CTL, rxmode);
580 return;
581 } else
582 rxmode &= ~MOS_CTL_ALLMULTI;
583
584 /* now program new ones */
585 if_maddr_rlock(ifp);
586 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
587 if (ifma->ifma_addr->sa_family != AF_LINK)
588 goto allmulti;
589 h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
590 ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
591 //h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
592 hashtbl[h / 8] |= 1 << (h % 8);
593 }
594 if_maddr_runlock(ifp);
595
596 ifp->if_flags &= ~IFF_ALLMULTI;
597 mos_write_mcast(sc, (void *)&hashtbl);
598 mos_reg_write_1(sc, MOS_CTL, rxmode);
599 return;
600}
601
602void
603mos_reset(struct mos_softc *sc)
604{
605 u_int8_t ctl;
606
607 ctl = mos_reg_read_1(sc, MOS_CTL);
608 ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB |
609 MOS_CTL_RX_ENB);
610 /* Disable RX, TX, promiscuous and allmulticast mode */
611 mos_reg_write_1(sc, MOS_CTL, ctl);
612
613 /* Reset frame drop counter register to zero */
614 mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
615
616 /* Wait a little while for the chip to get its brains in order. */
617 DELAY(1000);
618 return;
619}
620
621void
622mos_chip_init(struct mos_softc *sc)
623{
624 int i;
625
626 /*
627 * Rev.C devices have a pause threshold register which needs to be set
628 * at startup.
629 */
630 if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) {
631 for (i=0;i<MOS_PAUSE_REWRITES;i++)
632 mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0);
633 }
634
635 sc->mos_phyaddrs[0] = 1; sc->mos_phyaddrs[1] = 0xFF;
636}
637
638/*
639 * Probe for a MCS7x30 chip.
640 */
641int
642mos_probe(device_t dev)
643{
644 DPRINTF("mos: probe\n");
645 struct usb_attach_arg *uaa = device_get_ivars(dev);
646
647 if (uaa->usb_mode != USB_MODE_HOST) {
648 DPRINTF("mos: not USB_MODE_HOST\n");
649 return (ENXIO);
650 }
651 //uint8_t bIfaceIndex;
652 //uint8_t bIfaceNum;
653 //uint8_t bConfigIndex;
654 //uint8_t bConfigNum;
655
656 if (uaa->info.bConfigNum != MOS_CONFIG_NO) {
657 DPRINTF("mos: not MOS_CONFIG_NO %i vs %i\n", uaa->info.bConfigNum , MOS_CONFIG_NO);
658 return (ENXIO);
659 }
660 if (uaa->info.bIfaceIndex != MOS_IFACE_IDX) {
661 DPRINTF("mos: not MOS_IFACE_IDX %i vs %i\n", uaa->info.bIfaceIndex, MOS_IFACE_IDX);
662 return (ENXIO);
663 }
664
665 DPRINTF("mos: probe by generic means\n");
666 int retval = usbd_lookup_id_by_uaa(mos_devs, sizeof(mos_devs), uaa);
667 DPRINTF("mos: probe retval: %i (ENXIO:%i)\n", retval, ENXIO);
668 return retval;
669}
670
671/*
672 * Attach the interface. Allocate softc structures, do ifmedia
673 * setup and ethernet/BPF attach.
674 */
675int
676mos_attach(device_t dev)
677{
678 struct usb_attach_arg *uaa = device_get_ivars(dev);
679 struct mos_softc *sc = device_get_softc(dev);
680 struct usb_ether *ue = &sc->sc_ue;
681
682 uint8_t iface_index;
683 int error;
684
685 sc->mos_flags = USB_GET_DRIVER_INFO(uaa);
686
687 device_set_usb_desc(dev);
688 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
689
690 iface_index = MOS_IFACE_IDX;
691 error = usbd_transfer_setup(uaa->device, &iface_index,
692 sc->sc_xfer, mos_config, MOS_CONFIG_NO,
693 sc, &sc->sc_mtx);
694
695 if (error) {
696 device_printf(dev, "allocating USB transfers failed\n");
697 goto detach;
698 }
699
700 ue->ue_sc = sc;
701 ue->ue_dev = dev;
702 ue->ue_udev = uaa->device;
703 ue->ue_mtx = &sc->sc_mtx;
704 ue->ue_methods = &mos_ue_methods;
705
706
707 DPRINTFN(11,"%s:", "mos");
708
709 if (sc->mos_flags & MCS7730) {
710 DPRINTFN(11," MCS7730");
711 } else if (sc->mos_flags & MCS7830) {
712 DPRINTFN(11," MCS7830");
713 }
714
715 error = uether_ifattach(ue);
716 if (error) {
717 device_printf(dev, "could not attach interface\n");
718 goto detach;
719 }
720 return (0); /* success */
721
722
723detach:
724 mos_detach(dev);
725 return (ENXIO); /* failure */
726}
727
728
729void
730mos_attach_post(struct usb_ether *ue)
731{
732 struct mos_softc *sc = uether_getsc(ue);
733 /*
734 * Read MAC address, inform the world.
735 */
736 // int err = mos_readmac(sc, (void*)&eaddr);
737 // if (err) {
738 // printf("%s: couldn't get MAC address\n",
739 // "mos");
740 // return;
741 // }
742 // bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
743 // printf(", address %s\n", ether_sprintf(eaddr));
744 mos_chip_init(sc);
745
746
747 sc->mos_attached = 1;
748}
749
750int
751mos_detach(device_t dev)
752{
753 struct mos_softc *sc = device_get_softc(dev);
754 struct usb_ether *ue = &sc->sc_ue;
755
756 usbd_transfer_unsetup(sc->sc_xfer, MOS_CONFIG_NO);
757 uether_ifdetach(ue);
758 mtx_destroy(&sc->sc_mtx);
759
760 return (0);
761}
762
763
764
765
766/*
767 * A frame has been uploaded: pass the resulting mbuf chain up to
768 * the higher level protocols.
769 */
770void
771mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
772{
773 struct mos_softc *sc = usbd_xfer_softc(xfer);
774 struct usb_ether *ue = &sc->sc_ue;
775 struct ifnet *ifp = uether_getifp(ue);
776
777 u_int8_t rxstat = 0;
778 u_int32_t actlen;
779 u_int16_t pktlen = 0;
780 struct mbuf *stat;
781 uint8_t status;
782 struct usb_page_cache *pc;
783
784 DPRINTFN(10, "%s: %s: enter\n", "mos",__func__);
785
786 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
787 pc = usbd_xfer_get_frame(xfer, 0);
788
789 status = USB_GET_STATE(xfer);
790 if (status != USB_ST_SETUP) {
791 if (status == USB_ST_TRANSFERRED) {
792 if (actlen <= 1)
793 goto done;
794
795 usbd_copy_out(pc, actlen - sizeof(stat), &stat,
796 sizeof(stat));
797
798 /* evaluate status byte at the end */
799 pktlen = actlen - 1;
800 //rxstat = stat[pktlen] & MOS_RXSTS_MASK;
801 m_freem(stat);
802
803 if (rxstat != MOS_RXSTS_VALID) {
804 DPRINTF("%s: erroneous frame received: ",
805 "mos");
806 if (rxstat & MOS_RXSTS_SHORT_FRAME)
807 DPRINTF("frame size less than 64 bytes\n");
808 if (rxstat & MOS_RXSTS_LARGE_FRAME)
809 DPRINTF("frame size larger than 1532 bytes\n");
810 if (rxstat & MOS_RXSTS_CRC_ERROR)
811 DPRINTF("CRC error\n");
812 if (rxstat & MOS_RXSTS_ALIGN_ERROR)
813 DPRINTF("alignment error\n");
814 ifp->if_ierrors++;
815 goto done;
816 }
817
818 if ( pktlen < sizeof(struct ether_header) ) {
819 ifp->if_ierrors++;
820 goto done;
821 }
822
823 uether_rxbuf(ue, pc, 0, actlen);
824
825 } else {
826 DPRINTF("bulk read error, %s\n", usbd_errstr(error));
827 if (error == USB_ERR_CANCELLED) {
828 return;
829 } else {
830 /* try to clear stall first */
831 usbd_xfer_set_stall(xfer);
832 goto done;
833 }
834 }
835 }
836done:
837 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
838 usbd_transfer_submit(xfer);
839 uether_rxflush(ue);
840 DPRINTFN(10,"%s: %s: start rx\n", "mos", __func__);
841
842 return;
843}
844
845/*
846 * A frame was downloaded to the chip. It's safe for us to clean up
847 * the list buffers.
848 */
849
850void
851mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
852{
853 struct mos_softc *sc = usbd_xfer_softc(xfer);
854 struct ifnet *ifp = uether_getifp(&sc->sc_ue);
855 struct usb_page_cache *pc;
856 struct mbuf *m;
857 uint8_t status;
858 int actlen;
859
860 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
861 pc = usbd_xfer_get_frame(xfer, 0);
862
863 status = USB_GET_STATE(xfer);
864
865 if (status != USB_ST_SETUP) {
866 if (status == USB_ST_TRANSFERRED) {
867 DPRINTFN(11, "transfer of %d bytes complete\n", actlen);
868 ifp->if_opackets++;
869 } else {
870 DPRINTFN(11, "%s: usb error on tx: %s\n", "mos", usbd_errstr(status));
871 ifp->if_oerrors++;
872 if (error == USB_ERR_CANCELLED) {
873 return;
874 }
875 }
876 }
877
878 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
879
880 usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
881
882 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
883
884 /*
885 * if there's a BPF listener, bounce a copy
886 * of this frame to him:
887 */
888 BPF_MTAP(ifp, m);
889
890 m_freem(m);
891
892 usbd_transfer_submit(xfer);
893
894 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
895 mos_start(&sc->sc_ue);
896
897 ifp->if_opackets++;
898 return;
899}
900
901void
902mos_tick(struct usb_ether *ue)
903{
904 struct mos_softc *sc = uether_getsc(ue);
905 struct ifnet *ifp = uether_getifp(ue);
906 struct mii_data *mii = GET_MII(sc);
907
908 if (sc == NULL)
909 return;
910
911 DPRINTFN(0xff,"%s: %s: enter\n", "mos", __func__);
912
913 mii_tick(mii);
914 if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE &&
915 IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
916 DPRINTF("%s: %s: got link\n",
917 "mos", __func__);
918 sc->mos_link++;
919 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
920 mos_start(&sc->sc_ue);
921 }
922}
923
924
925//int
926//mos_encap(struct mos_softc *sc, struct mbuf *m, int idx)
927//{
928// struct mos_chain *c;
929// int err;
930// int length;
931//
932// c = &sc->mos_cdata.mos_tx_chain[idx];
933//
934// m_copydata(m, 0, m->m_pkthdr.len, c->mos_buf);
935// length = m->m_pkthdr.len;
936//
937// c->mos_mbuf = m;
938//
939// usbd_setup_xfer(c->mos_xfer, sc->mos_ep[MOS_ENDPT_TX],
940// c, c->mos_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
941// 10000, mos_txeof);
942//
943// /* Transmit */
944// err = usbd_transfer(c->mos_xfer);
945// if (err != USBD_IN_PROGRESS) {
946// mos_stop(sc);
947// return(EIO);
948// }
949//
950// sc->mos_cdata.mos_tx_cnt++;
951//
952// return(0);
953//}
954
955void
956mos_start(struct usb_ether *ue)
957{
958 struct mos_softc *sc = uether_getsc(ue);
959 struct ifnet *ifp = uether_getifp(ue);
960 struct mbuf *m_head = NULL;
961
962 sc = ifp->if_softc;
963
964 if (!sc->mos_link)
965 return;
966
967 //if (ifp->if_flags & IFF_OACTIVE)
968 // return;
969
970 IFQ_POLL(&ifp->if_snd, m_head);
971 if (m_head == NULL)
972 return;
973
974 //if (mos_encap(sc, m_head, 0)) {
975 // ifp->if_flags |= IFF_OACTIVE;
976 // return;
977 //}
978 IFQ_DEQUEUE(&ifp->if_snd, m_head);
979
980 /*
981 * If there's a BPF listener, bounce a copy of this frame
982 * to him.
983 */
984 BPF_MTAP(ifp, m_head);
985
986 /*
987 * Set a timeout in case the chip goes out to lunch.
988 */
989 //ifp->if_timer = 5;
990
991 return;
992}
993
994void
995mos_init(struct usb_ether *ue)
996{
997 struct mos_softc *sc = uether_getsc(ue);
998 struct ifnet *ifp = uether_getifp(ue);
999 u_int8_t rxmode;
1000
1001 /*
1002 * Cancel pending I/O and free all RX/TX buffers.
1003 */
1004 mos_reset(sc);
1005
1006 /*
1007 * Write MAC address
1008 */
1009 //mos_writemac(sc, sc->arpcom.ac_enaddr);
1010
1011
1012
1013 /* Read and set transmitter IPG values */
1014 sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0);
1015 sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1);
1016 mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]);
1017 mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]);
1018
1019 /* Enable receiver and transmitter, bridge controls speed/duplex mode */
1020 rxmode = mos_reg_read_1(sc, MOS_CTL);
1021 rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB;
1022 rxmode &= ~(MOS_CTL_SLEEP);
1023
1024 /* If we want promiscuous mode, set the allframes bit. */
1025 if (ifp->if_flags & IFF_PROMISC)
1026 rxmode |= MOS_CTL_RX_PROMISC;
1027
1028 /* XXX: broadcast mode? */
1029
1030 mos_reg_write_1(sc, MOS_CTL, rxmode);
1031
1032 /* Load the multicast filter. */
1033 mos_setmulti(ue);
1034
1035 mii_mediachg(GET_MII(sc));
1036
1037 ifp->if_flags |= IFF_DRV_RUNNING;
1038 mos_start(ue);
1039}
1040
1041
1042void
1043mos_intr_callback(struct usb_xfer *xfer, usb_error_t error)
1044{
1045 struct mos_softc *sc = usbd_xfer_softc(xfer);
1046 struct ifnet *ifp = uether_getifp(&sc->sc_ue);
1047 int actlen;
1048
1049 ifp->if_oerrors++;
1050 printf("%s: watchdog timeout\n", "mos");
1051
1052 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1053
1054 //XXX: Porting, how? mos_txeof(c->mos_xfer, c, stat);
1055
1056 if (!IFQ_IS_EMPTY(&ifp->if_snd))
1057 mos_start(&sc->sc_ue);
1058}
1059
1060
1061/*
1062 * Stop the adapter and free any mbufs allocated to the
1063 * RX and TX lists.
1064 */
1065void
1066mos_stop(struct usb_ether *ue)
1067{
1068 struct mos_softc *sc = uether_getsc(ue);
1069 struct ifnet *ifp = uether_getifp(ue);
1070
1071 mos_reset(sc);
1072
1073 ifp->if_flags &= ~IFF_DRV_RUNNING;
1074
1075 /*
1076 * stop all the transfers, if not already stopped:
1077 */
1078 usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_TX]);
1079 usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_RX]);
1080 usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_INTR]);
1081
1082 sc->mos_link = 0;
1083}
1084
Note: See TracBrowser for help on using the repository browser.