15d9de2d3SDavid du Colombier /*
25d9de2d3SDavid du Colombier * Kernel proxy for usb ethernet device
35d9de2d3SDavid du Colombier */
45d9de2d3SDavid du Colombier
55d9de2d3SDavid du Colombier #include "u.h"
65d9de2d3SDavid du Colombier #include "../port/lib.h"
75d9de2d3SDavid du Colombier #include "mem.h"
85d9de2d3SDavid du Colombier #include "dat.h"
95d9de2d3SDavid du Colombier #include "fns.h"
105d9de2d3SDavid du Colombier #include "io.h"
115d9de2d3SDavid du Colombier #include "../port/error.h"
125d9de2d3SDavid du Colombier #include "../port/netif.h"
135d9de2d3SDavid du Colombier
145d9de2d3SDavid du Colombier #include "etherif.h"
155d9de2d3SDavid du Colombier #include "../ip/ip.h"
165d9de2d3SDavid du Colombier
175d9de2d3SDavid du Colombier #define GET4(p) ((p)[3]<<24 | (p)[2]<<16 | (p)[1]<<8 | (p)[0])
185d9de2d3SDavid du Colombier #define PUT4(p, v) ((p)[0] = (v), (p)[1] = (v)>>8, \
195d9de2d3SDavid du Colombier (p)[2] = (v)>>16, (p)[3] = (v)>>24)
205d9de2d3SDavid du Colombier #define dprint if(debug) print
215d9de2d3SDavid du Colombier #define ddump if(0) dump
225d9de2d3SDavid du Colombier
235d9de2d3SDavid du Colombier static int debug = 0;
245d9de2d3SDavid du Colombier
255d9de2d3SDavid du Colombier enum {
265d9de2d3SDavid du Colombier Bind = 0,
275d9de2d3SDavid du Colombier Unbind,
285d9de2d3SDavid du Colombier
295d9de2d3SDavid du Colombier SmscRxerror = 0x8000,
305d9de2d3SDavid du Colombier SmscTxfirst = 0x2000,
315d9de2d3SDavid du Colombier SmscTxlast = 0x1000,
325d9de2d3SDavid du Colombier };
335d9de2d3SDavid du Colombier
345d9de2d3SDavid du Colombier typedef struct Ctlr Ctlr;
355d9de2d3SDavid du Colombier typedef struct Udev Udev;
365d9de2d3SDavid du Colombier
375d9de2d3SDavid du Colombier typedef int (Unpackfn)(Ether*, Block*);
385d9de2d3SDavid du Colombier typedef void (Transmitfn)(Ctlr*, Block*);
395d9de2d3SDavid du Colombier
405d9de2d3SDavid du Colombier struct Ctlr {
415d9de2d3SDavid du Colombier Ether* edev;
425d9de2d3SDavid du Colombier Udev* udev;
435d9de2d3SDavid du Colombier Chan* inchan;
445d9de2d3SDavid du Colombier Chan* outchan;
455d9de2d3SDavid du Colombier char* buf;
465d9de2d3SDavid du Colombier int bufsize;
475d9de2d3SDavid du Colombier int maxpkt;
485d9de2d3SDavid du Colombier uint rxbuf;
495d9de2d3SDavid du Colombier uint rxpkt;
505d9de2d3SDavid du Colombier uint txbuf;
515d9de2d3SDavid du Colombier uint txpkt;
525d9de2d3SDavid du Colombier QLock;
535d9de2d3SDavid du Colombier };
545d9de2d3SDavid du Colombier
555d9de2d3SDavid du Colombier struct Udev {
565d9de2d3SDavid du Colombier char *name;
575d9de2d3SDavid du Colombier Unpackfn *unpack;
585d9de2d3SDavid du Colombier Transmitfn *transmit;
595d9de2d3SDavid du Colombier };
605d9de2d3SDavid du Colombier
615d9de2d3SDavid du Colombier static Cmdtab cmds[] = {
625d9de2d3SDavid du Colombier { Bind, "bind", 7, },
635d9de2d3SDavid du Colombier { Unbind, "unbind", 0, },
645d9de2d3SDavid du Colombier };
655d9de2d3SDavid du Colombier
665d9de2d3SDavid du Colombier static Unpackfn unpackcdc, unpackasix, unpacksmsc;
675d9de2d3SDavid du Colombier static Transmitfn transmitcdc, transmitasix, transmitsmsc;
685d9de2d3SDavid du Colombier
695d9de2d3SDavid du Colombier static Udev udevtab[] = {
705d9de2d3SDavid du Colombier { "cdc", unpackcdc, transmitcdc, },
715d9de2d3SDavid du Colombier { "asix", unpackasix, transmitasix, },
725d9de2d3SDavid du Colombier { "smsc", unpacksmsc, transmitsmsc, },
735d9de2d3SDavid du Colombier { nil },
745d9de2d3SDavid du Colombier };
755d9de2d3SDavid du Colombier
765d9de2d3SDavid du Colombier static void
dump(int c,Block * b)775d9de2d3SDavid du Colombier dump(int c, Block *b)
785d9de2d3SDavid du Colombier {
795d9de2d3SDavid du Colombier int s, i;
805d9de2d3SDavid du Colombier
815d9de2d3SDavid du Colombier s = splhi();
825d9de2d3SDavid du Colombier print("%c%ld:", c, BLEN(b));
835d9de2d3SDavid du Colombier for(i = 0; i < 32; i++)
845d9de2d3SDavid du Colombier print(" %2.2ux", b->rp[i]);
855d9de2d3SDavid du Colombier print("\n");
865d9de2d3SDavid du Colombier splx(s);
875d9de2d3SDavid du Colombier }
885d9de2d3SDavid du Colombier
895d9de2d3SDavid du Colombier static int
unpack(Ether * edev,Block * b,int m)905d9de2d3SDavid du Colombier unpack(Ether *edev, Block *b, int m)
915d9de2d3SDavid du Colombier {
925d9de2d3SDavid du Colombier Block *nb;
935d9de2d3SDavid du Colombier Ctlr *ctlr;
945d9de2d3SDavid du Colombier
955d9de2d3SDavid du Colombier ctlr = edev->ctlr;
965d9de2d3SDavid du Colombier ddump('?', b);
975d9de2d3SDavid du Colombier if(m == BLEN(b)){
985d9de2d3SDavid du Colombier etheriq(edev, b, 1);
995d9de2d3SDavid du Colombier ctlr->rxpkt++;
1005d9de2d3SDavid du Colombier return 1;
1015d9de2d3SDavid du Colombier }
1025d9de2d3SDavid du Colombier nb = iallocb(m);
1035d9de2d3SDavid du Colombier if(nb != nil){
1045d9de2d3SDavid du Colombier memmove(nb->wp, b->rp, m);
1055d9de2d3SDavid du Colombier nb->wp += m;
1065d9de2d3SDavid du Colombier etheriq(edev, nb, 1);
1075d9de2d3SDavid du Colombier ctlr->rxpkt++;
1085d9de2d3SDavid du Colombier }else
1095d9de2d3SDavid du Colombier edev->soverflows++;
1105d9de2d3SDavid du Colombier b->rp += m;
1115d9de2d3SDavid du Colombier return 0;
1125d9de2d3SDavid du Colombier }
1135d9de2d3SDavid du Colombier
1145d9de2d3SDavid du Colombier static int
unpackcdc(Ether * edev,Block * b)1155d9de2d3SDavid du Colombier unpackcdc(Ether *edev, Block *b)
1165d9de2d3SDavid du Colombier {
1175d9de2d3SDavid du Colombier int m;
1185d9de2d3SDavid du Colombier
1195d9de2d3SDavid du Colombier m = BLEN(b);
1205d9de2d3SDavid du Colombier if(m < 6)
1215d9de2d3SDavid du Colombier return -1;
1225d9de2d3SDavid du Colombier return unpack(edev, b, m);
1235d9de2d3SDavid du Colombier }
1245d9de2d3SDavid du Colombier
1255d9de2d3SDavid du Colombier static int
unpackasix(Ether * edev,Block * b)1265d9de2d3SDavid du Colombier unpackasix(Ether *edev, Block *b)
1275d9de2d3SDavid du Colombier {
1285d9de2d3SDavid du Colombier ulong hd;
1295d9de2d3SDavid du Colombier int m;
1305d9de2d3SDavid du Colombier uchar *wp;
1315d9de2d3SDavid du Colombier
1325d9de2d3SDavid du Colombier if(BLEN(b) < 4)
1335d9de2d3SDavid du Colombier return -1;
1345d9de2d3SDavid du Colombier hd = GET4(b->rp);
1355d9de2d3SDavid du Colombier b->rp += 4;
1365d9de2d3SDavid du Colombier m = hd & 0xFFFF;
1375d9de2d3SDavid du Colombier hd >>= 16;
1385d9de2d3SDavid du Colombier if(m != (~hd & 0xFFFF))
1395d9de2d3SDavid du Colombier return -1;
1405d9de2d3SDavid du Colombier m = ROUND(m, 2);
1415d9de2d3SDavid du Colombier if(m < 6 || m > BLEN(b))
1425d9de2d3SDavid du Colombier return -1;
1435d9de2d3SDavid du Colombier if((wp = b->rp + m) != b->wp && b->wp - wp < 4)
1445d9de2d3SDavid du Colombier b->wp = wp;
1455d9de2d3SDavid du Colombier return unpack(edev, b, m);
1465d9de2d3SDavid du Colombier }
1475d9de2d3SDavid du Colombier
1485d9de2d3SDavid du Colombier static int
unpacksmsc(Ether * edev,Block * b)1495d9de2d3SDavid du Colombier unpacksmsc(Ether *edev, Block *b)
1505d9de2d3SDavid du Colombier {
1515d9de2d3SDavid du Colombier ulong hd;
1525d9de2d3SDavid du Colombier int m;
1535d9de2d3SDavid du Colombier
1545d9de2d3SDavid du Colombier ddump('@', b);
1555d9de2d3SDavid du Colombier if(BLEN(b) < 4)
1565d9de2d3SDavid du Colombier return -1;
1575d9de2d3SDavid du Colombier hd = GET4(b->rp);
1585d9de2d3SDavid du Colombier b->rp += 4;
1595d9de2d3SDavid du Colombier m = hd >> 16;
1605d9de2d3SDavid du Colombier if(m < 6 || m > BLEN(b))
1615d9de2d3SDavid du Colombier return -1;
1625d9de2d3SDavid du Colombier if(BLEN(b) - m < 4)
1635d9de2d3SDavid du Colombier b->wp = b->rp + m;
1645d9de2d3SDavid du Colombier if(hd & SmscRxerror){
1655d9de2d3SDavid du Colombier edev->frames++;
1665d9de2d3SDavid du Colombier b->rp += m;
1675d9de2d3SDavid du Colombier if(BLEN(b) == 0){
1685d9de2d3SDavid du Colombier freeb(b);
1695d9de2d3SDavid du Colombier return 1;
1705d9de2d3SDavid du Colombier }
1715d9de2d3SDavid du Colombier }else if(unpack(edev, b, m) == 1)
1725d9de2d3SDavid du Colombier return 1;
1735d9de2d3SDavid du Colombier if((m &= 3) != 0)
1745d9de2d3SDavid du Colombier b->rp += 4 - m;
1755d9de2d3SDavid du Colombier return 0;
1765d9de2d3SDavid du Colombier }
1775d9de2d3SDavid du Colombier
1785d9de2d3SDavid du Colombier static void
transmit(Ctlr * ctlr,Block * b)1795d9de2d3SDavid du Colombier transmit(Ctlr *ctlr, Block *b)
1805d9de2d3SDavid du Colombier {
1815d9de2d3SDavid du Colombier Chan *c;
1825d9de2d3SDavid du Colombier
1835d9de2d3SDavid du Colombier ddump('!', b);
1845d9de2d3SDavid du Colombier c = ctlr->outchan;
1855d9de2d3SDavid du Colombier devtab[c->type]->bwrite(c, b, 0);
1865d9de2d3SDavid du Colombier }
1875d9de2d3SDavid du Colombier
1885d9de2d3SDavid du Colombier static void
transmitcdc(Ctlr * ctlr,Block * b)1895d9de2d3SDavid du Colombier transmitcdc(Ctlr *ctlr, Block *b)
1905d9de2d3SDavid du Colombier {
1915d9de2d3SDavid du Colombier transmit(ctlr, b);
1925d9de2d3SDavid du Colombier }
1935d9de2d3SDavid du Colombier
1945d9de2d3SDavid du Colombier static void
transmitasix(Ctlr * ctlr,Block * b)1955d9de2d3SDavid du Colombier transmitasix(Ctlr *ctlr, Block *b)
1965d9de2d3SDavid du Colombier {
1975d9de2d3SDavid du Colombier int n;
1985d9de2d3SDavid du Colombier
1995d9de2d3SDavid du Colombier n = BLEN(b) & 0xFFFF;
200b4d1cf41SDavid du Colombier n |= ~n << 16;
2015d9de2d3SDavid du Colombier padblock(b, 4);
2025d9de2d3SDavid du Colombier PUT4(b->rp, n);
2035d9de2d3SDavid du Colombier if(BLEN(b) % ctlr->maxpkt == 0){
2045d9de2d3SDavid du Colombier padblock(b, -4);
2055d9de2d3SDavid du Colombier PUT4(b->wp, 0xFFFF0000);
2065d9de2d3SDavid du Colombier b->wp += 4;
2075d9de2d3SDavid du Colombier }
2085d9de2d3SDavid du Colombier transmit(ctlr, b);
2095d9de2d3SDavid du Colombier }
2105d9de2d3SDavid du Colombier
2115d9de2d3SDavid du Colombier static void
transmitsmsc(Ctlr * ctlr,Block * b)2125d9de2d3SDavid du Colombier transmitsmsc(Ctlr *ctlr, Block *b)
2135d9de2d3SDavid du Colombier {
2145d9de2d3SDavid du Colombier int n;
2155d9de2d3SDavid du Colombier
2165d9de2d3SDavid du Colombier n = BLEN(b) & 0x7FF;
2175d9de2d3SDavid du Colombier padblock(b, 8);
2185d9de2d3SDavid du Colombier PUT4(b->rp, n | SmscTxfirst | SmscTxlast);
2195d9de2d3SDavid du Colombier PUT4(b->rp+4, n);
2205d9de2d3SDavid du Colombier transmit(ctlr, b);
2215d9de2d3SDavid du Colombier }
2225d9de2d3SDavid du Colombier
2235d9de2d3SDavid du Colombier static void
etherusbproc(void * a)2245d9de2d3SDavid du Colombier etherusbproc(void *a)
2255d9de2d3SDavid du Colombier {
2265d9de2d3SDavid du Colombier Ether *edev;
2275d9de2d3SDavid du Colombier Ctlr *ctlr;
2285d9de2d3SDavid du Colombier Chan *c;
2295d9de2d3SDavid du Colombier Block *b;
2305d9de2d3SDavid du Colombier
2315d9de2d3SDavid du Colombier edev = a;
2325d9de2d3SDavid du Colombier ctlr = edev->ctlr;
2335d9de2d3SDavid du Colombier c = ctlr->inchan;
2345d9de2d3SDavid du Colombier b = nil;
2355d9de2d3SDavid du Colombier if(waserror()){
2365d9de2d3SDavid du Colombier print("etherusbproc: error exit %s\n", up->errstr);
2375d9de2d3SDavid du Colombier pexit(up->errstr, 1);
2385d9de2d3SDavid du Colombier return;
2395d9de2d3SDavid du Colombier }
2405d9de2d3SDavid du Colombier for(;;){
2415d9de2d3SDavid du Colombier if(b == nil){
2425d9de2d3SDavid du Colombier b = devtab[c->type]->bread(c, ctlr->bufsize, 0);
2435d9de2d3SDavid du Colombier ctlr->rxbuf++;
2445d9de2d3SDavid du Colombier }
2455d9de2d3SDavid du Colombier switch(ctlr->udev->unpack(edev, b)){
2465d9de2d3SDavid du Colombier case -1:
2475d9de2d3SDavid du Colombier edev->buffs++;
2485d9de2d3SDavid du Colombier freeb(b);
2495d9de2d3SDavid du Colombier /* fall through */
2505d9de2d3SDavid du Colombier case 1:
2515d9de2d3SDavid du Colombier b = nil;
2525d9de2d3SDavid du Colombier break;
2535d9de2d3SDavid du Colombier }
2545d9de2d3SDavid du Colombier }
2555d9de2d3SDavid du Colombier }
2565d9de2d3SDavid du Colombier
2575d9de2d3SDavid du Colombier /*
2585d9de2d3SDavid du Colombier * bind type indev outdev mac bufsize maxpkt
2595d9de2d3SDavid du Colombier */
2605d9de2d3SDavid du Colombier static void
bind(Ctlr * ctlr,Udev * udev,Cmdbuf * cb)2615d9de2d3SDavid du Colombier bind(Ctlr *ctlr, Udev *udev, Cmdbuf *cb)
2625d9de2d3SDavid du Colombier {
2635d9de2d3SDavid du Colombier Chan *inchan, *outchan;
2645d9de2d3SDavid du Colombier char *buf;
2655d9de2d3SDavid du Colombier uint bufsize, maxpkt;
2665d9de2d3SDavid du Colombier
2675d9de2d3SDavid du Colombier qlock(ctlr);
2685d9de2d3SDavid du Colombier inchan = outchan = nil;
2695d9de2d3SDavid du Colombier buf = nil;
2705d9de2d3SDavid du Colombier if(waserror()){
2715d9de2d3SDavid du Colombier free(buf);
2725d9de2d3SDavid du Colombier if(inchan)
2735d9de2d3SDavid du Colombier cclose(inchan);
2745d9de2d3SDavid du Colombier if(outchan)
2755d9de2d3SDavid du Colombier cclose(outchan);
2765d9de2d3SDavid du Colombier qunlock(ctlr);
2775d9de2d3SDavid du Colombier nexterror();
2785d9de2d3SDavid du Colombier }
2795d9de2d3SDavid du Colombier if(ctlr->buf != nil)
2805d9de2d3SDavid du Colombier cmderror(cb, "already bound to a device");
2815d9de2d3SDavid du Colombier maxpkt = strtol(cb->f[6], 0, 0);
2825d9de2d3SDavid du Colombier if(maxpkt < 8 || maxpkt > 512)
2835d9de2d3SDavid du Colombier cmderror(cb, "bad maxpkt");
2845d9de2d3SDavid du Colombier bufsize = strtol(cb->f[5], 0, 0);
2855d9de2d3SDavid du Colombier if(bufsize < maxpkt || bufsize > 32*1024)
2865d9de2d3SDavid du Colombier cmderror(cb, "bad bufsize");
2875d9de2d3SDavid du Colombier buf = smalloc(bufsize);
2885d9de2d3SDavid du Colombier inchan = namec(cb->f[2], Aopen, OREAD, 0);
2895d9de2d3SDavid du Colombier outchan = namec(cb->f[3], Aopen, OWRITE, 0);
2905d9de2d3SDavid du Colombier assert(inchan != nil && outchan != nil);
2915d9de2d3SDavid du Colombier if(parsemac(ctlr->edev->ea, cb->f[4], Eaddrlen) != Eaddrlen)
2925d9de2d3SDavid du Colombier cmderror(cb, "bad etheraddr");
2935d9de2d3SDavid du Colombier memmove(ctlr->edev->addr, ctlr->edev->ea, Eaddrlen);
2945d9de2d3SDavid du Colombier print("\netherusb %s: %E\n", udev->name, ctlr->edev->addr);
2955d9de2d3SDavid du Colombier ctlr->buf = buf;
2965d9de2d3SDavid du Colombier ctlr->inchan = inchan;
2975d9de2d3SDavid du Colombier ctlr->outchan = outchan;
2985d9de2d3SDavid du Colombier ctlr->bufsize = bufsize;
2995d9de2d3SDavid du Colombier ctlr->maxpkt = maxpkt;
3005d9de2d3SDavid du Colombier ctlr->udev = udev;
3015d9de2d3SDavid du Colombier kproc("etherusb", etherusbproc, ctlr->edev);
3025d9de2d3SDavid du Colombier poperror();
3035d9de2d3SDavid du Colombier qunlock(ctlr);
3045d9de2d3SDavid du Colombier }
3055d9de2d3SDavid du Colombier
3065d9de2d3SDavid du Colombier static void
unbind(Ctlr * ctlr)3075d9de2d3SDavid du Colombier unbind(Ctlr *ctlr)
3085d9de2d3SDavid du Colombier {
3095d9de2d3SDavid du Colombier qlock(ctlr);
3105d9de2d3SDavid du Colombier if(ctlr->buf != nil){
3115d9de2d3SDavid du Colombier free(ctlr->buf);
3125d9de2d3SDavid du Colombier ctlr->buf = nil;
3135d9de2d3SDavid du Colombier if(ctlr->inchan)
3145d9de2d3SDavid du Colombier cclose(ctlr->inchan);
3155d9de2d3SDavid du Colombier if(ctlr->outchan)
3165d9de2d3SDavid du Colombier cclose(ctlr->outchan);
3175d9de2d3SDavid du Colombier ctlr->inchan = ctlr->outchan = nil;
3185d9de2d3SDavid du Colombier }
3195d9de2d3SDavid du Colombier qunlock(ctlr);
3205d9de2d3SDavid du Colombier }
3215d9de2d3SDavid du Colombier
3225d9de2d3SDavid du Colombier static long
etherusbifstat(Ether * edev,void * a,long n,ulong offset)3235d9de2d3SDavid du Colombier etherusbifstat(Ether* edev, void* a, long n, ulong offset)
3245d9de2d3SDavid du Colombier {
3255d9de2d3SDavid du Colombier Ctlr *ctlr;
3265d9de2d3SDavid du Colombier char *p;
3275d9de2d3SDavid du Colombier int l;
3285d9de2d3SDavid du Colombier
3295d9de2d3SDavid du Colombier ctlr = edev->ctlr;
3305d9de2d3SDavid du Colombier p = malloc(READSTR);
3315d9de2d3SDavid du Colombier l = 0;
3325d9de2d3SDavid du Colombier
3335d9de2d3SDavid du Colombier l += snprint(p+l, READSTR-l, "rxbuf: %ud\n", ctlr->rxbuf);
3345d9de2d3SDavid du Colombier l += snprint(p+l, READSTR-l, "rxpkt: %ud\n", ctlr->rxpkt);
3355d9de2d3SDavid du Colombier l += snprint(p+l, READSTR-l, "txbuf: %ud\n", ctlr->txbuf);
3365d9de2d3SDavid du Colombier l += snprint(p+l, READSTR-l, "txpkt: %ud\n", ctlr->txpkt);
3375d9de2d3SDavid du Colombier USED(l);
3385d9de2d3SDavid du Colombier
3395d9de2d3SDavid du Colombier n = readstr(offset, a, n, p);
3405d9de2d3SDavid du Colombier free(p);
3415d9de2d3SDavid du Colombier return n;
3425d9de2d3SDavid du Colombier }
3435d9de2d3SDavid du Colombier
3445d9de2d3SDavid du Colombier static void
etherusbtransmit(Ether * edev)3455d9de2d3SDavid du Colombier etherusbtransmit(Ether *edev)
3465d9de2d3SDavid du Colombier {
3475d9de2d3SDavid du Colombier Ctlr *ctlr;
3485d9de2d3SDavid du Colombier Block *b;
3495d9de2d3SDavid du Colombier
3505d9de2d3SDavid du Colombier ctlr = edev->ctlr;
3515d9de2d3SDavid du Colombier while((b = qget(edev->oq)) != nil){
3525d9de2d3SDavid du Colombier ctlr->txpkt++;
3535d9de2d3SDavid du Colombier if(ctlr->buf == nil)
3545d9de2d3SDavid du Colombier freeb(b);
3555d9de2d3SDavid du Colombier else{
3565d9de2d3SDavid du Colombier ctlr->udev->transmit(ctlr, b);
3575d9de2d3SDavid du Colombier ctlr->txbuf++;
3585d9de2d3SDavid du Colombier }
3595d9de2d3SDavid du Colombier }
3605d9de2d3SDavid du Colombier }
3615d9de2d3SDavid du Colombier
3625d9de2d3SDavid du Colombier static long
etherusbctl(Ether * edev,void * buf,long n)3635d9de2d3SDavid du Colombier etherusbctl(Ether* edev, void* buf, long n)
3645d9de2d3SDavid du Colombier {
3655d9de2d3SDavid du Colombier Ctlr *ctlr;
3665d9de2d3SDavid du Colombier Cmdbuf *cb;
3675d9de2d3SDavid du Colombier Cmdtab *ct;
3685d9de2d3SDavid du Colombier Udev *udev;
3695d9de2d3SDavid du Colombier
3705d9de2d3SDavid du Colombier if((ctlr = edev->ctlr) == nil)
3715d9de2d3SDavid du Colombier error(Enonexist);
3725d9de2d3SDavid du Colombier
3735d9de2d3SDavid du Colombier cb = parsecmd(buf, n);
3745d9de2d3SDavid du Colombier if(waserror()){
3755d9de2d3SDavid du Colombier free(cb);
3765d9de2d3SDavid du Colombier nexterror();
3775d9de2d3SDavid du Colombier }
3785d9de2d3SDavid du Colombier ct = lookupcmd(cb, cmds, nelem(cmds));
3795d9de2d3SDavid du Colombier switch(ct->index){
3805d9de2d3SDavid du Colombier case Bind:
3815d9de2d3SDavid du Colombier for(udev = udevtab; udev->name; udev++)
3825d9de2d3SDavid du Colombier if(strcmp(cb->f[1], udev->name) == 0)
3835d9de2d3SDavid du Colombier break;
3845d9de2d3SDavid du Colombier if(udev->name == nil)
3855d9de2d3SDavid du Colombier cmderror(cb, "unknown etherusb type");
3865d9de2d3SDavid du Colombier bind(ctlr, udev, cb);
3875d9de2d3SDavid du Colombier break;
3885d9de2d3SDavid du Colombier case Unbind:
3895d9de2d3SDavid du Colombier unbind(ctlr);
3905d9de2d3SDavid du Colombier break;
3915d9de2d3SDavid du Colombier default:
3925d9de2d3SDavid du Colombier cmderror(cb, "unknown etherusb control message");
3935d9de2d3SDavid du Colombier }
3945d9de2d3SDavid du Colombier poperror();
3955d9de2d3SDavid du Colombier free(cb);
3965d9de2d3SDavid du Colombier return n;
3975d9de2d3SDavid du Colombier }
3985d9de2d3SDavid du Colombier
3995d9de2d3SDavid du Colombier static void
etherusbattach(Ether * edev)4005d9de2d3SDavid du Colombier etherusbattach(Ether* edev)
4015d9de2d3SDavid du Colombier {
4025d9de2d3SDavid du Colombier Ctlr *ctlr;
4035d9de2d3SDavid du Colombier
4045d9de2d3SDavid du Colombier ctlr = edev->ctlr;
4055d9de2d3SDavid du Colombier ctlr->edev = edev;
4065d9de2d3SDavid du Colombier }
4075d9de2d3SDavid du Colombier
4085d9de2d3SDavid du Colombier static int
etherusbpnp(Ether * edev)4095d9de2d3SDavid du Colombier etherusbpnp(Ether* edev)
4105d9de2d3SDavid du Colombier {
4115d9de2d3SDavid du Colombier Ctlr *ctlr;
4125d9de2d3SDavid du Colombier
4135d9de2d3SDavid du Colombier ctlr = malloc(sizeof(Ctlr));
4145d9de2d3SDavid du Colombier edev->ctlr = ctlr;
4155d9de2d3SDavid du Colombier edev->irq = -1;
4165d9de2d3SDavid du Colombier edev->mbps = 100; /* TODO: get this from usbether */
417*853458f3SDavid du Colombier
418*853458f3SDavid du Colombier /*
419*853458f3SDavid du Colombier * Linkage to the generic ethernet driver.
420*853458f3SDavid du Colombier */
4215d9de2d3SDavid du Colombier edev->attach = etherusbattach;
4225d9de2d3SDavid du Colombier edev->transmit = etherusbtransmit;
423*853458f3SDavid du Colombier edev->interrupt = nil;
4245d9de2d3SDavid du Colombier edev->ifstat = etherusbifstat;
4255d9de2d3SDavid du Colombier edev->ctl = etherusbctl;
426*853458f3SDavid du Colombier
427*853458f3SDavid du Colombier edev->arg = edev;
428*853458f3SDavid du Colombier /* TODO: promiscuous, multicast (for ipv6), shutdown (for reboot) */
429*853458f3SDavid du Colombier // edev->promiscuous = etherusbpromiscuous;
430*853458f3SDavid du Colombier // edev->shutdown = etherusbshutdown;
431*853458f3SDavid du Colombier // edev->multicast = etherusbmulticast;
432*853458f3SDavid du Colombier
4335d9de2d3SDavid du Colombier return 0;
4345d9de2d3SDavid du Colombier }
4355d9de2d3SDavid du Colombier
4365d9de2d3SDavid du Colombier void
etherusblink(void)4375d9de2d3SDavid du Colombier etherusblink(void)
4385d9de2d3SDavid du Colombier {
4395d9de2d3SDavid du Colombier addethercard("usb", etherusbpnp);
4405d9de2d3SDavid du Colombier }
441