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"
11*5c47fe09SDavid du Colombier #include "ureg.h"
125d9de2d3SDavid du Colombier #include "../port/error.h"
135d9de2d3SDavid du Colombier #include "../port/netif.h"
145d9de2d3SDavid du Colombier
155d9de2d3SDavid du Colombier #include "etherif.h"
165d9de2d3SDavid du Colombier #include "../ip/ip.h"
175d9de2d3SDavid du Colombier
185d9de2d3SDavid du Colombier #define GET4(p) ((p)[3]<<24 | (p)[2]<<16 | (p)[1]<<8 | (p)[0])
195d9de2d3SDavid du Colombier #define PUT4(p, v) ((p)[0] = (v), (p)[1] = (v)>>8, \
205d9de2d3SDavid du Colombier (p)[2] = (v)>>16, (p)[3] = (v)>>24)
215d9de2d3SDavid du Colombier #define dprint if(debug) print
225d9de2d3SDavid du Colombier #define ddump if(0) dump
235d9de2d3SDavid du Colombier
245d9de2d3SDavid du Colombier static int debug = 0;
255d9de2d3SDavid du Colombier
265d9de2d3SDavid du Colombier enum {
275d9de2d3SDavid du Colombier Bind = 0,
285d9de2d3SDavid du Colombier Unbind,
295d9de2d3SDavid du Colombier
305d9de2d3SDavid du Colombier SmscRxerror = 0x8000,
315d9de2d3SDavid du Colombier SmscTxfirst = 0x2000,
325d9de2d3SDavid du Colombier SmscTxlast = 0x1000,
33*5c47fe09SDavid du Colombier Lan78Rxerror = 0x00400000,
34*5c47fe09SDavid du Colombier Lan78Txfcs = 1<<22,
355d9de2d3SDavid du Colombier };
365d9de2d3SDavid du Colombier
375d9de2d3SDavid du Colombier typedef struct Ctlr Ctlr;
385d9de2d3SDavid du Colombier typedef struct Udev Udev;
395d9de2d3SDavid du Colombier
405d9de2d3SDavid du Colombier typedef int (Unpackfn)(Ether*, Block*);
415d9de2d3SDavid du Colombier typedef void (Transmitfn)(Ctlr*, Block*);
425d9de2d3SDavid du Colombier
435d9de2d3SDavid du Colombier struct Ctlr {
445d9de2d3SDavid du Colombier Ether* edev;
455d9de2d3SDavid du Colombier Udev* udev;
465d9de2d3SDavid du Colombier Chan* inchan;
475d9de2d3SDavid du Colombier Chan* outchan;
485d9de2d3SDavid du Colombier char* buf;
495d9de2d3SDavid du Colombier int bufsize;
505d9de2d3SDavid du Colombier int maxpkt;
515d9de2d3SDavid du Colombier uint rxbuf;
525d9de2d3SDavid du Colombier uint rxpkt;
535d9de2d3SDavid du Colombier uint txbuf;
545d9de2d3SDavid du Colombier uint txpkt;
555d9de2d3SDavid du Colombier QLock;
565d9de2d3SDavid du Colombier };
575d9de2d3SDavid du Colombier
585d9de2d3SDavid du Colombier struct Udev {
595d9de2d3SDavid du Colombier char *name;
605d9de2d3SDavid du Colombier Unpackfn *unpack;
615d9de2d3SDavid du Colombier Transmitfn *transmit;
625d9de2d3SDavid du Colombier };
635d9de2d3SDavid du Colombier
645d9de2d3SDavid du Colombier static Cmdtab cmds[] = {
655d9de2d3SDavid du Colombier { Bind, "bind", 7, },
665d9de2d3SDavid du Colombier { Unbind, "unbind", 0, },
675d9de2d3SDavid du Colombier };
685d9de2d3SDavid du Colombier
69*5c47fe09SDavid du Colombier static Unpackfn unpackcdc, unpackasix, unpacksmsc, unpacklan78;
70*5c47fe09SDavid du Colombier static Transmitfn transmitcdc, transmitasix, transmitsmsc, transmitlan78;
715d9de2d3SDavid du Colombier
725d9de2d3SDavid du Colombier static Udev udevtab[] = {
735d9de2d3SDavid du Colombier { "cdc", unpackcdc, transmitcdc, },
745d9de2d3SDavid du Colombier { "asix", unpackasix, transmitasix, },
755d9de2d3SDavid du Colombier { "smsc", unpacksmsc, transmitsmsc, },
76*5c47fe09SDavid du Colombier { "lan78xx", unpacklan78, transmitlan78, },
775d9de2d3SDavid du Colombier { nil },
785d9de2d3SDavid du Colombier };
795d9de2d3SDavid du Colombier
80*5c47fe09SDavid du Colombier static char nullea[Eaddrlen];
81*5c47fe09SDavid du Colombier
825d9de2d3SDavid du Colombier static void
dump(int c,Block * b)835d9de2d3SDavid du Colombier dump(int c, Block *b)
845d9de2d3SDavid du Colombier {
855d9de2d3SDavid du Colombier int s, i;
865d9de2d3SDavid du Colombier
875d9de2d3SDavid du Colombier s = splhi();
885d9de2d3SDavid du Colombier print("%c%ld:", c, BLEN(b));
895d9de2d3SDavid du Colombier for(i = 0; i < 32; i++)
905d9de2d3SDavid du Colombier print(" %2.2ux", b->rp[i]);
915d9de2d3SDavid du Colombier print("\n");
925d9de2d3SDavid du Colombier splx(s);
935d9de2d3SDavid du Colombier }
945d9de2d3SDavid du Colombier
955d9de2d3SDavid du Colombier static int
unpack(Ether * edev,Block * b,int m)965d9de2d3SDavid du Colombier unpack(Ether *edev, Block *b, int m)
975d9de2d3SDavid du Colombier {
985d9de2d3SDavid du Colombier Block *nb;
995d9de2d3SDavid du Colombier Ctlr *ctlr;
1005d9de2d3SDavid du Colombier
1015d9de2d3SDavid du Colombier ctlr = edev->ctlr;
1025d9de2d3SDavid du Colombier ddump('?', b);
1035d9de2d3SDavid du Colombier if(m == BLEN(b)){
1045d9de2d3SDavid du Colombier etheriq(edev, b, 1);
1055d9de2d3SDavid du Colombier ctlr->rxpkt++;
1065d9de2d3SDavid du Colombier return 1;
1075d9de2d3SDavid du Colombier }
1085d9de2d3SDavid du Colombier nb = iallocb(m);
1095d9de2d3SDavid du Colombier if(nb != nil){
1105d9de2d3SDavid du Colombier memmove(nb->wp, b->rp, m);
1115d9de2d3SDavid du Colombier nb->wp += m;
1125d9de2d3SDavid du Colombier etheriq(edev, nb, 1);
1135d9de2d3SDavid du Colombier ctlr->rxpkt++;
1145d9de2d3SDavid du Colombier }else
1155d9de2d3SDavid du Colombier edev->soverflows++;
1165d9de2d3SDavid du Colombier b->rp += m;
1175d9de2d3SDavid du Colombier return 0;
1185d9de2d3SDavid du Colombier }
1195d9de2d3SDavid du Colombier
1205d9de2d3SDavid du Colombier static int
unpackcdc(Ether * edev,Block * b)1215d9de2d3SDavid du Colombier unpackcdc(Ether *edev, Block *b)
1225d9de2d3SDavid du Colombier {
1235d9de2d3SDavid du Colombier int m;
1245d9de2d3SDavid du Colombier
1255d9de2d3SDavid du Colombier m = BLEN(b);
1265d9de2d3SDavid du Colombier if(m < 6)
1275d9de2d3SDavid du Colombier return -1;
1285d9de2d3SDavid du Colombier return unpack(edev, b, m);
1295d9de2d3SDavid du Colombier }
1305d9de2d3SDavid du Colombier
1315d9de2d3SDavid du Colombier static int
unpackasix(Ether * edev,Block * b)1325d9de2d3SDavid du Colombier unpackasix(Ether *edev, Block *b)
1335d9de2d3SDavid du Colombier {
1345d9de2d3SDavid du Colombier ulong hd;
1355d9de2d3SDavid du Colombier int m;
1365d9de2d3SDavid du Colombier uchar *wp;
1375d9de2d3SDavid du Colombier
1385d9de2d3SDavid du Colombier if(BLEN(b) < 4)
1395d9de2d3SDavid du Colombier return -1;
1405d9de2d3SDavid du Colombier hd = GET4(b->rp);
1415d9de2d3SDavid du Colombier b->rp += 4;
1425d9de2d3SDavid du Colombier m = hd & 0xFFFF;
1435d9de2d3SDavid du Colombier hd >>= 16;
1445d9de2d3SDavid du Colombier if(m != (~hd & 0xFFFF))
1455d9de2d3SDavid du Colombier return -1;
1465d9de2d3SDavid du Colombier m = ROUND(m, 2);
1475d9de2d3SDavid du Colombier if(m < 6 || m > BLEN(b))
1485d9de2d3SDavid du Colombier return -1;
1495d9de2d3SDavid du Colombier if((wp = b->rp + m) != b->wp && b->wp - wp < 4)
1505d9de2d3SDavid du Colombier b->wp = wp;
1515d9de2d3SDavid du Colombier return unpack(edev, b, m);
1525d9de2d3SDavid du Colombier }
1535d9de2d3SDavid du Colombier
1545d9de2d3SDavid du Colombier static int
unpacksmsc(Ether * edev,Block * b)1555d9de2d3SDavid du Colombier unpacksmsc(Ether *edev, Block *b)
1565d9de2d3SDavid du Colombier {
1575d9de2d3SDavid du Colombier ulong hd;
1585d9de2d3SDavid du Colombier int m;
1595d9de2d3SDavid du Colombier
1605d9de2d3SDavid du Colombier ddump('@', b);
1615d9de2d3SDavid du Colombier if(BLEN(b) < 4)
1625d9de2d3SDavid du Colombier return -1;
1635d9de2d3SDavid du Colombier hd = GET4(b->rp);
1645d9de2d3SDavid du Colombier b->rp += 4;
1655d9de2d3SDavid du Colombier m = hd >> 16;
1665d9de2d3SDavid du Colombier if(m < 6 || m > BLEN(b))
1675d9de2d3SDavid du Colombier return -1;
1685d9de2d3SDavid du Colombier if(BLEN(b) - m < 4)
1695d9de2d3SDavid du Colombier b->wp = b->rp + m;
1705d9de2d3SDavid du Colombier if(hd & SmscRxerror){
1715d9de2d3SDavid du Colombier edev->frames++;
1725d9de2d3SDavid du Colombier b->rp += m;
1735d9de2d3SDavid du Colombier if(BLEN(b) == 0){
1745d9de2d3SDavid du Colombier freeb(b);
1755d9de2d3SDavid du Colombier return 1;
1765d9de2d3SDavid du Colombier }
1775d9de2d3SDavid du Colombier }else if(unpack(edev, b, m) == 1)
1785d9de2d3SDavid du Colombier return 1;
1795d9de2d3SDavid du Colombier if((m &= 3) != 0)
1805d9de2d3SDavid du Colombier b->rp += 4 - m;
1815d9de2d3SDavid du Colombier return 0;
1825d9de2d3SDavid du Colombier }
1835d9de2d3SDavid du Colombier
184*5c47fe09SDavid du Colombier static int
unpacklan78(Ether * edev,Block * b)185*5c47fe09SDavid du Colombier unpacklan78(Ether *edev, Block *b)
186*5c47fe09SDavid du Colombier {
187*5c47fe09SDavid du Colombier ulong hd;
188*5c47fe09SDavid du Colombier int m;
189*5c47fe09SDavid du Colombier
190*5c47fe09SDavid du Colombier if(BLEN(b) < 10)
191*5c47fe09SDavid du Colombier return -1;
192*5c47fe09SDavid du Colombier hd = GET4(b->rp);
193*5c47fe09SDavid du Colombier b->rp += 10;
194*5c47fe09SDavid du Colombier m = hd & 0x3FFF;
195*5c47fe09SDavid du Colombier if(m < 6 || m > BLEN(b))
196*5c47fe09SDavid du Colombier return -1;
197*5c47fe09SDavid du Colombier if(hd & Lan78Rxerror){
198*5c47fe09SDavid du Colombier edev->frames++;
199*5c47fe09SDavid du Colombier b->rp += m;
200*5c47fe09SDavid du Colombier if(BLEN(b) == 0){
201*5c47fe09SDavid du Colombier freeb(b);
202*5c47fe09SDavid du Colombier return 1;
203*5c47fe09SDavid du Colombier }
204*5c47fe09SDavid du Colombier }else if(unpack(edev, b, m) == 1)
205*5c47fe09SDavid du Colombier return 1;
206*5c47fe09SDavid du Colombier if(BLEN(b) > 0)
207*5c47fe09SDavid du Colombier b->rp = (uchar*)((((uintptr)b->rp)+3)&~3);
208*5c47fe09SDavid du Colombier return 0;
209*5c47fe09SDavid du Colombier }
210*5c47fe09SDavid du Colombier
2115d9de2d3SDavid du Colombier static void
transmit(Ctlr * ctlr,Block * b)2125d9de2d3SDavid du Colombier transmit(Ctlr *ctlr, Block *b)
2135d9de2d3SDavid du Colombier {
2145d9de2d3SDavid du Colombier Chan *c;
2155d9de2d3SDavid du Colombier
2165d9de2d3SDavid du Colombier ddump('!', b);
2175d9de2d3SDavid du Colombier c = ctlr->outchan;
2185d9de2d3SDavid du Colombier devtab[c->type]->bwrite(c, b, 0);
2195d9de2d3SDavid du Colombier }
2205d9de2d3SDavid du Colombier
2215d9de2d3SDavid du Colombier static void
transmitcdc(Ctlr * ctlr,Block * b)2225d9de2d3SDavid du Colombier transmitcdc(Ctlr *ctlr, Block *b)
2235d9de2d3SDavid du Colombier {
2245d9de2d3SDavid du Colombier transmit(ctlr, b);
2255d9de2d3SDavid du Colombier }
2265d9de2d3SDavid du Colombier
2275d9de2d3SDavid du Colombier static void
transmitasix(Ctlr * ctlr,Block * b)2285d9de2d3SDavid du Colombier transmitasix(Ctlr *ctlr, Block *b)
2295d9de2d3SDavid du Colombier {
2305d9de2d3SDavid du Colombier int n;
2315d9de2d3SDavid du Colombier
2325d9de2d3SDavid du Colombier n = BLEN(b) & 0xFFFF;
233b4d1cf41SDavid du Colombier n |= ~n << 16;
234*5c47fe09SDavid du Colombier b = padblock(b, 4);
2355d9de2d3SDavid du Colombier PUT4(b->rp, n);
2365d9de2d3SDavid du Colombier if(BLEN(b) % ctlr->maxpkt == 0){
237*5c47fe09SDavid du Colombier b = padblock(b, -4);
2385d9de2d3SDavid du Colombier PUT4(b->wp, 0xFFFF0000);
2395d9de2d3SDavid du Colombier b->wp += 4;
2405d9de2d3SDavid du Colombier }
2415d9de2d3SDavid du Colombier transmit(ctlr, b);
2425d9de2d3SDavid du Colombier }
2435d9de2d3SDavid du Colombier
2445d9de2d3SDavid du Colombier static void
transmitsmsc(Ctlr * ctlr,Block * b)2455d9de2d3SDavid du Colombier transmitsmsc(Ctlr *ctlr, Block *b)
2465d9de2d3SDavid du Colombier {
2475d9de2d3SDavid du Colombier int n;
2485d9de2d3SDavid du Colombier
2495d9de2d3SDavid du Colombier n = BLEN(b) & 0x7FF;
250*5c47fe09SDavid du Colombier b = padblock(b, 8);
2515d9de2d3SDavid du Colombier PUT4(b->rp, n | SmscTxfirst | SmscTxlast);
2525d9de2d3SDavid du Colombier PUT4(b->rp+4, n);
2535d9de2d3SDavid du Colombier transmit(ctlr, b);
2545d9de2d3SDavid du Colombier }
2555d9de2d3SDavid du Colombier
2565d9de2d3SDavid du Colombier static void
transmitlan78(Ctlr * ctlr,Block * b)257*5c47fe09SDavid du Colombier transmitlan78(Ctlr *ctlr, Block *b)
258*5c47fe09SDavid du Colombier {
259*5c47fe09SDavid du Colombier int n;
260*5c47fe09SDavid du Colombier
261*5c47fe09SDavid du Colombier n = BLEN(b) & 0xFFFFF;
262*5c47fe09SDavid du Colombier b = padblock(b, 8);
263*5c47fe09SDavid du Colombier PUT4(b->rp, n | Lan78Txfcs);
264*5c47fe09SDavid du Colombier PUT4(b->rp+4, n);
265*5c47fe09SDavid du Colombier transmit(ctlr, b);
266*5c47fe09SDavid du Colombier }
267*5c47fe09SDavid du Colombier
268*5c47fe09SDavid du Colombier static void
etherusbproc(void * a)2695d9de2d3SDavid du Colombier etherusbproc(void *a)
2705d9de2d3SDavid du Colombier {
2715d9de2d3SDavid du Colombier Ether *edev;
2725d9de2d3SDavid du Colombier Ctlr *ctlr;
2735d9de2d3SDavid du Colombier Chan *c;
2745d9de2d3SDavid du Colombier Block *b;
2755d9de2d3SDavid du Colombier
2765d9de2d3SDavid du Colombier edev = a;
2775d9de2d3SDavid du Colombier ctlr = edev->ctlr;
2785d9de2d3SDavid du Colombier c = ctlr->inchan;
2795d9de2d3SDavid du Colombier b = nil;
2805d9de2d3SDavid du Colombier if(waserror()){
2815d9de2d3SDavid du Colombier print("etherusbproc: error exit %s\n", up->errstr);
2825d9de2d3SDavid du Colombier pexit(up->errstr, 1);
2835d9de2d3SDavid du Colombier return;
2845d9de2d3SDavid du Colombier }
2855d9de2d3SDavid du Colombier for(;;){
2865d9de2d3SDavid du Colombier if(b == nil){
2875d9de2d3SDavid du Colombier b = devtab[c->type]->bread(c, ctlr->bufsize, 0);
2885d9de2d3SDavid du Colombier ctlr->rxbuf++;
2895d9de2d3SDavid du Colombier }
2905d9de2d3SDavid du Colombier switch(ctlr->udev->unpack(edev, b)){
2915d9de2d3SDavid du Colombier case -1:
2925d9de2d3SDavid du Colombier edev->buffs++;
2935d9de2d3SDavid du Colombier freeb(b);
2945d9de2d3SDavid du Colombier /* fall through */
2955d9de2d3SDavid du Colombier case 1:
2965d9de2d3SDavid du Colombier b = nil;
2975d9de2d3SDavid du Colombier break;
2985d9de2d3SDavid du Colombier }
2995d9de2d3SDavid du Colombier }
3005d9de2d3SDavid du Colombier }
3015d9de2d3SDavid du Colombier
3025d9de2d3SDavid du Colombier /*
3035d9de2d3SDavid du Colombier * bind type indev outdev mac bufsize maxpkt
3045d9de2d3SDavid du Colombier */
3055d9de2d3SDavid du Colombier static void
bind(Ctlr * ctlr,Udev * udev,Cmdbuf * cb)3065d9de2d3SDavid du Colombier bind(Ctlr *ctlr, Udev *udev, Cmdbuf *cb)
3075d9de2d3SDavid du Colombier {
3085d9de2d3SDavid du Colombier Chan *inchan, *outchan;
3095d9de2d3SDavid du Colombier char *buf;
3105d9de2d3SDavid du Colombier uint bufsize, maxpkt;
311*5c47fe09SDavid du Colombier uchar ea[Eaddrlen];
3125d9de2d3SDavid du Colombier
3135d9de2d3SDavid du Colombier qlock(ctlr);
3145d9de2d3SDavid du Colombier inchan = outchan = nil;
3155d9de2d3SDavid du Colombier buf = nil;
3165d9de2d3SDavid du Colombier if(waserror()){
3175d9de2d3SDavid du Colombier free(buf);
3185d9de2d3SDavid du Colombier if(inchan)
3195d9de2d3SDavid du Colombier cclose(inchan);
3205d9de2d3SDavid du Colombier if(outchan)
3215d9de2d3SDavid du Colombier cclose(outchan);
3225d9de2d3SDavid du Colombier qunlock(ctlr);
3235d9de2d3SDavid du Colombier nexterror();
3245d9de2d3SDavid du Colombier }
3255d9de2d3SDavid du Colombier if(ctlr->buf != nil)
3265d9de2d3SDavid du Colombier cmderror(cb, "already bound to a device");
3275d9de2d3SDavid du Colombier maxpkt = strtol(cb->f[6], 0, 0);
3285d9de2d3SDavid du Colombier if(maxpkt < 8 || maxpkt > 512)
3295d9de2d3SDavid du Colombier cmderror(cb, "bad maxpkt");
3305d9de2d3SDavid du Colombier bufsize = strtol(cb->f[5], 0, 0);
3315d9de2d3SDavid du Colombier if(bufsize < maxpkt || bufsize > 32*1024)
3325d9de2d3SDavid du Colombier cmderror(cb, "bad bufsize");
3335d9de2d3SDavid du Colombier buf = smalloc(bufsize);
3345d9de2d3SDavid du Colombier inchan = namec(cb->f[2], Aopen, OREAD, 0);
3355d9de2d3SDavid du Colombier outchan = namec(cb->f[3], Aopen, OWRITE, 0);
3365d9de2d3SDavid du Colombier assert(inchan != nil && outchan != nil);
337*5c47fe09SDavid du Colombier if(parsemac(ea, cb->f[4], Eaddrlen) != Eaddrlen)
3385d9de2d3SDavid du Colombier cmderror(cb, "bad etheraddr");
339*5c47fe09SDavid du Colombier if(memcmp(ctlr->edev->ea, nullea, Eaddrlen) == 0)
340*5c47fe09SDavid du Colombier memmove(ctlr->edev->ea, ea, Eaddrlen);
341*5c47fe09SDavid du Colombier else if(memcmp(ctlr->edev->ea, ea, Eaddrlen) != 0)
342*5c47fe09SDavid du Colombier cmderror(cb, "wrong ether address");
3435d9de2d3SDavid du Colombier ctlr->buf = buf;
3445d9de2d3SDavid du Colombier ctlr->inchan = inchan;
3455d9de2d3SDavid du Colombier ctlr->outchan = outchan;
3465d9de2d3SDavid du Colombier ctlr->bufsize = bufsize;
3475d9de2d3SDavid du Colombier ctlr->maxpkt = maxpkt;
3485d9de2d3SDavid du Colombier ctlr->udev = udev;
3495d9de2d3SDavid du Colombier kproc("etherusb", etherusbproc, ctlr->edev);
350*5c47fe09SDavid du Colombier memmove(ctlr->edev->addr, ea, Eaddrlen);
351*5c47fe09SDavid du Colombier print("\netherusb %s: %E\n", udev->name, ctlr->edev->addr);
3525d9de2d3SDavid du Colombier poperror();
3535d9de2d3SDavid du Colombier qunlock(ctlr);
3545d9de2d3SDavid du Colombier }
3555d9de2d3SDavid du Colombier
3565d9de2d3SDavid du Colombier static void
unbind(Ctlr * ctlr)3575d9de2d3SDavid du Colombier unbind(Ctlr *ctlr)
3585d9de2d3SDavid du Colombier {
3595d9de2d3SDavid du Colombier qlock(ctlr);
3605d9de2d3SDavid du Colombier if(ctlr->buf != nil){
3615d9de2d3SDavid du Colombier free(ctlr->buf);
3625d9de2d3SDavid du Colombier ctlr->buf = nil;
3635d9de2d3SDavid du Colombier if(ctlr->inchan)
3645d9de2d3SDavid du Colombier cclose(ctlr->inchan);
3655d9de2d3SDavid du Colombier if(ctlr->outchan)
3665d9de2d3SDavid du Colombier cclose(ctlr->outchan);
3675d9de2d3SDavid du Colombier ctlr->inchan = ctlr->outchan = nil;
3685d9de2d3SDavid du Colombier }
3695d9de2d3SDavid du Colombier qunlock(ctlr);
3705d9de2d3SDavid du Colombier }
3715d9de2d3SDavid du Colombier
3725d9de2d3SDavid du Colombier static long
etherusbifstat(Ether * edev,void * a,long n,ulong offset)3735d9de2d3SDavid du Colombier etherusbifstat(Ether* edev, void* a, long n, ulong offset)
3745d9de2d3SDavid du Colombier {
3755d9de2d3SDavid du Colombier Ctlr *ctlr;
3765d9de2d3SDavid du Colombier char *p;
3775d9de2d3SDavid du Colombier int l;
3785d9de2d3SDavid du Colombier
3795d9de2d3SDavid du Colombier ctlr = edev->ctlr;
3805d9de2d3SDavid du Colombier p = malloc(READSTR);
3815d9de2d3SDavid du Colombier l = 0;
3825d9de2d3SDavid du Colombier
3835d9de2d3SDavid du Colombier l += snprint(p+l, READSTR-l, "rxbuf: %ud\n", ctlr->rxbuf);
3845d9de2d3SDavid du Colombier l += snprint(p+l, READSTR-l, "rxpkt: %ud\n", ctlr->rxpkt);
3855d9de2d3SDavid du Colombier l += snprint(p+l, READSTR-l, "txbuf: %ud\n", ctlr->txbuf);
3865d9de2d3SDavid du Colombier l += snprint(p+l, READSTR-l, "txpkt: %ud\n", ctlr->txpkt);
3875d9de2d3SDavid du Colombier USED(l);
3885d9de2d3SDavid du Colombier
3895d9de2d3SDavid du Colombier n = readstr(offset, a, n, p);
3905d9de2d3SDavid du Colombier free(p);
3915d9de2d3SDavid du Colombier return n;
3925d9de2d3SDavid du Colombier }
3935d9de2d3SDavid du Colombier
3945d9de2d3SDavid du Colombier static void
etherusbtransmit(Ether * edev)3955d9de2d3SDavid du Colombier etherusbtransmit(Ether *edev)
3965d9de2d3SDavid du Colombier {
3975d9de2d3SDavid du Colombier Ctlr *ctlr;
3985d9de2d3SDavid du Colombier Block *b;
3995d9de2d3SDavid du Colombier
4005d9de2d3SDavid du Colombier ctlr = edev->ctlr;
4015d9de2d3SDavid du Colombier while((b = qget(edev->oq)) != nil){
4025d9de2d3SDavid du Colombier ctlr->txpkt++;
4035d9de2d3SDavid du Colombier if(ctlr->buf == nil)
4045d9de2d3SDavid du Colombier freeb(b);
4055d9de2d3SDavid du Colombier else{
4065d9de2d3SDavid du Colombier ctlr->udev->transmit(ctlr, b);
4075d9de2d3SDavid du Colombier ctlr->txbuf++;
4085d9de2d3SDavid du Colombier }
4095d9de2d3SDavid du Colombier }
4105d9de2d3SDavid du Colombier }
4115d9de2d3SDavid du Colombier
4125d9de2d3SDavid du Colombier static long
etherusbctl(Ether * edev,void * buf,long n)4135d9de2d3SDavid du Colombier etherusbctl(Ether* edev, void* buf, long n)
4145d9de2d3SDavid du Colombier {
4155d9de2d3SDavid du Colombier Ctlr *ctlr;
4165d9de2d3SDavid du Colombier Cmdbuf *cb;
4175d9de2d3SDavid du Colombier Cmdtab *ct;
4185d9de2d3SDavid du Colombier Udev *udev;
4195d9de2d3SDavid du Colombier
4205d9de2d3SDavid du Colombier if((ctlr = edev->ctlr) == nil)
4215d9de2d3SDavid du Colombier error(Enonexist);
4225d9de2d3SDavid du Colombier
4235d9de2d3SDavid du Colombier cb = parsecmd(buf, n);
4245d9de2d3SDavid du Colombier if(waserror()){
4255d9de2d3SDavid du Colombier free(cb);
4265d9de2d3SDavid du Colombier nexterror();
4275d9de2d3SDavid du Colombier }
4285d9de2d3SDavid du Colombier ct = lookupcmd(cb, cmds, nelem(cmds));
4295d9de2d3SDavid du Colombier switch(ct->index){
4305d9de2d3SDavid du Colombier case Bind:
4315d9de2d3SDavid du Colombier for(udev = udevtab; udev->name; udev++)
4325d9de2d3SDavid du Colombier if(strcmp(cb->f[1], udev->name) == 0)
4335d9de2d3SDavid du Colombier break;
4345d9de2d3SDavid du Colombier if(udev->name == nil)
4355d9de2d3SDavid du Colombier cmderror(cb, "unknown etherusb type");
4365d9de2d3SDavid du Colombier bind(ctlr, udev, cb);
4375d9de2d3SDavid du Colombier break;
4385d9de2d3SDavid du Colombier case Unbind:
4395d9de2d3SDavid du Colombier unbind(ctlr);
4405d9de2d3SDavid du Colombier break;
4415d9de2d3SDavid du Colombier default:
4425d9de2d3SDavid du Colombier cmderror(cb, "unknown etherusb control message");
4435d9de2d3SDavid du Colombier }
4445d9de2d3SDavid du Colombier poperror();
4455d9de2d3SDavid du Colombier free(cb);
4465d9de2d3SDavid du Colombier return n;
4475d9de2d3SDavid du Colombier }
4485d9de2d3SDavid du Colombier
4495d9de2d3SDavid du Colombier static void
etherusbmulticast(void *,uchar *,int)450*5c47fe09SDavid du Colombier etherusbmulticast(void*, uchar*, int)
451*5c47fe09SDavid du Colombier {
452*5c47fe09SDavid du Colombier /* nothing to do, we allow all multicast packets in */
453*5c47fe09SDavid du Colombier }
454*5c47fe09SDavid du Colombier
455*5c47fe09SDavid du Colombier static void
etherusbshutdown(Ether *)456*5c47fe09SDavid du Colombier etherusbshutdown(Ether*)
457*5c47fe09SDavid du Colombier {
458*5c47fe09SDavid du Colombier }
459*5c47fe09SDavid du Colombier
460*5c47fe09SDavid du Colombier static void
etherusbattach(Ether * edev)4615d9de2d3SDavid du Colombier etherusbattach(Ether* edev)
4625d9de2d3SDavid du Colombier {
4635d9de2d3SDavid du Colombier Ctlr *ctlr;
4645d9de2d3SDavid du Colombier
4655d9de2d3SDavid du Colombier ctlr = edev->ctlr;
466*5c47fe09SDavid du Colombier if(ctlr->edev == 0){
467*5c47fe09SDavid du Colombier /*
468*5c47fe09SDavid du Colombier * Don't let boot process access etherusb until
469*5c47fe09SDavid du Colombier * usbether driver has assigned an address.
470*5c47fe09SDavid du Colombier */
471*5c47fe09SDavid du Colombier if(up->pid == 1 && strcmp(up->text, "boot") == 0)
472*5c47fe09SDavid du Colombier while(memcmp(edev->ea, nullea, Eaddrlen) == 0)
473*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, 0, 100);
4745d9de2d3SDavid du Colombier ctlr->edev = edev;
4755d9de2d3SDavid du Colombier }
476*5c47fe09SDavid du Colombier }
4775d9de2d3SDavid du Colombier
4785d9de2d3SDavid du Colombier static int
etherusbpnp(Ether * edev)4795d9de2d3SDavid du Colombier etherusbpnp(Ether* edev)
4805d9de2d3SDavid du Colombier {
4815d9de2d3SDavid du Colombier Ctlr *ctlr;
4825d9de2d3SDavid du Colombier
4835d9de2d3SDavid du Colombier ctlr = malloc(sizeof(Ctlr));
4845d9de2d3SDavid du Colombier edev->ctlr = ctlr;
4855d9de2d3SDavid du Colombier edev->irq = -1;
4865d9de2d3SDavid du Colombier edev->mbps = 100; /* TODO: get this from usbether */
487853458f3SDavid du Colombier
488853458f3SDavid du Colombier /*
489853458f3SDavid du Colombier * Linkage to the generic ethernet driver.
490853458f3SDavid du Colombier */
4915d9de2d3SDavid du Colombier edev->attach = etherusbattach;
4925d9de2d3SDavid du Colombier edev->transmit = etherusbtransmit;
493853458f3SDavid du Colombier edev->interrupt = nil;
4945d9de2d3SDavid du Colombier edev->ifstat = etherusbifstat;
4955d9de2d3SDavid du Colombier edev->ctl = etherusbctl;
496853458f3SDavid du Colombier
497853458f3SDavid du Colombier edev->arg = edev;
498853458f3SDavid du Colombier /* TODO: promiscuous, multicast (for ipv6), shutdown (for reboot) */
499853458f3SDavid du Colombier // edev->promiscuous = etherusbpromiscuous;
500*5c47fe09SDavid du Colombier edev->shutdown = etherusbshutdown;
501*5c47fe09SDavid du Colombier edev->multicast = etherusbmulticast;
502853458f3SDavid du Colombier
5035d9de2d3SDavid du Colombier return 0;
5045d9de2d3SDavid du Colombier }
5055d9de2d3SDavid du Colombier
5065d9de2d3SDavid du Colombier void
etherusblink(void)5075d9de2d3SDavid du Colombier etherusblink(void)
5085d9de2d3SDavid du Colombier {
5095d9de2d3SDavid du Colombier addethercard("usb", etherusbpnp);
5105d9de2d3SDavid du Colombier }
511