1*906943f9SDavid du Colombier /* 2*906943f9SDavid du Colombier * Asix USB ether adapters 3*906943f9SDavid du Colombier * I got no documentation for it, thus the bits 4*906943f9SDavid du Colombier * come from other systems; it's likely this is 5*906943f9SDavid du Colombier * doing more than needed in some places and 6*906943f9SDavid du Colombier * less than required in others. 7*906943f9SDavid du Colombier */ 8*906943f9SDavid du Colombier #include <u.h> 9*906943f9SDavid du Colombier #include <libc.h> 10*906943f9SDavid du Colombier #include <fcall.h> 11*906943f9SDavid du Colombier #include <thread.h> 12*906943f9SDavid du Colombier #include "usb.h" 13*906943f9SDavid du Colombier #include "usbfs.h" 14*906943f9SDavid du Colombier #include "ether.h" 15*906943f9SDavid du Colombier 16*906943f9SDavid du Colombier enum 17*906943f9SDavid du Colombier { 18*906943f9SDavid du Colombier 19*906943f9SDavid du Colombier /* Asix commands */ 20*906943f9SDavid du Colombier Cswmii = 0x06, /* set sw mii */ 21*906943f9SDavid du Colombier Crmii = 0x07, /* read mii reg */ 22*906943f9SDavid du Colombier Cwmii = 0x08, /* write mii reg */ 23*906943f9SDavid du Colombier Chwmii = 0x0a, /* set hw mii */ 24*906943f9SDavid du Colombier Creeprom = 0x0b, /* read eeprom */ 25*906943f9SDavid du Colombier Cwdis = 0x0e, /* write disable */ 26*906943f9SDavid du Colombier Cwena = 0x0d, /* write enable */ 27*906943f9SDavid du Colombier Crrxctl = 0x0f, /* read rx ctl */ 28*906943f9SDavid du Colombier Cwrxctl = 0x10, /* write rx ctl */ 29*906943f9SDavid du Colombier Cwipg = 0x12, /* write ipg */ 30*906943f9SDavid du Colombier Crmac = 0x13, /* read mac addr */ 31*906943f9SDavid du Colombier Crphy = 0x19, /* read phy id */ 32*906943f9SDavid du Colombier Cwmedium = 0x1b, /* write medium mode */ 33*906943f9SDavid du Colombier Crgpio = 0x1e, /* read gpio */ 34*906943f9SDavid du Colombier Cwgpio = 0x1f, /* write gpios */ 35*906943f9SDavid du Colombier Creset = 0x20, /* reset */ 36*906943f9SDavid du Colombier Cwphy = 0x22, /* select phy */ 37*906943f9SDavid du Colombier 38*906943f9SDavid du Colombier /* reset codes */ 39*906943f9SDavid du Colombier Rclear = 0x00, 40*906943f9SDavid du Colombier Rprte = 0x04, 41*906943f9SDavid du Colombier Rprl = 0x08, 42*906943f9SDavid du Colombier Riprl = 0x20, 43*906943f9SDavid du Colombier Rippd = 0x40, 44*906943f9SDavid du Colombier 45*906943f9SDavid du Colombier Gpiogpo1en = 0x04, /* gpio1 enable */, 46*906943f9SDavid du Colombier Gpiogpo1 = 0x08, /* gpio1 value */ 47*906943f9SDavid du Colombier Gpiogpo2en = 0x10, /* gpio2 enable */ 48*906943f9SDavid du Colombier Gpiogpo2 = 0x20, /* gpio2 value */ 49*906943f9SDavid du Colombier Gpiorse = 0x80, /* gpio reload serial eeprom */ 50*906943f9SDavid du Colombier 51*906943f9SDavid du Colombier Pmask = 0x1F, 52*906943f9SDavid du Colombier Pembed = 0x10, /* embedded phy */ 53*906943f9SDavid du Colombier 54*906943f9SDavid du Colombier Mfd = 0x002, /* media */ 55*906943f9SDavid du Colombier Mac = 0x004, 56*906943f9SDavid du Colombier Mrfc = 0x010, 57*906943f9SDavid du Colombier Mtfc = 0x020, 58*906943f9SDavid du Colombier Mjfe = 0x040, 59*906943f9SDavid du Colombier Mre = 0x100, 60*906943f9SDavid du Colombier Mps = 0x200, 61*906943f9SDavid du Colombier Mall772 = Mfd|Mrfc|Mtfc|Mps|Mac|Mre, 62*906943f9SDavid du Colombier Mall178 = Mps|Mfd|Mac|Mrfc|Mtfc|Mjfe|Mre, 63*906943f9SDavid du Colombier 64*906943f9SDavid du Colombier Ipgdflt = 0x15|0x0c|0x12, /* default ipg0, 1, 2 */ 65*906943f9SDavid du Colombier Rxctlso = 0x80, 66*906943f9SDavid du Colombier Rxctlab = 0x08, 67*906943f9SDavid du Colombier Rxctlsep = 0x04, 68*906943f9SDavid du Colombier Rxctlamall = 0x02, /* all multicast */ 69*906943f9SDavid du Colombier Rxctlprom = 0x01, /* promiscuous */ 70*906943f9SDavid du Colombier 71*906943f9SDavid du Colombier /* MII */ 72*906943f9SDavid du Colombier Miibmcr = 0x00, /* basic mode ctrl reg. */ 73*906943f9SDavid du Colombier Bmcrreset = 0x8000, /* reset */ 74*906943f9SDavid du Colombier Bmcranena = 0x1000, /* auto neg. enable */ 75*906943f9SDavid du Colombier Bmcrar = 0x0200, /* announce restart */ 76*906943f9SDavid du Colombier 77*906943f9SDavid du Colombier Miiad = 0x04, /* advertise reg. */ 78*906943f9SDavid du Colombier Adcsma = 0x0001, 79*906943f9SDavid du Colombier Ad1000f = 0x0200, 80*906943f9SDavid du Colombier Ad1000h = 0x0100, 81*906943f9SDavid du Colombier Ad10h = 0x0020, 82*906943f9SDavid du Colombier Ad10f = 0x0040, 83*906943f9SDavid du Colombier Ad100h = 0x0080, 84*906943f9SDavid du Colombier Ad100f = 0x0100, 85*906943f9SDavid du Colombier Adpause = 0x0400, 86*906943f9SDavid du Colombier Adall = Ad10h|Ad10f|Ad100h|Ad100f, 87*906943f9SDavid du Colombier 88*906943f9SDavid du Colombier Miimctl = 0x14, /* marvell ctl */ 89*906943f9SDavid du Colombier Mtxdly = 0x02, 90*906943f9SDavid du Colombier Mrxdly = 0x80, 91*906943f9SDavid du Colombier Mtxrxdly = 0x82, 92*906943f9SDavid du Colombier 93*906943f9SDavid du Colombier Miic1000 = 0x09, 94*906943f9SDavid du Colombier 95*906943f9SDavid du Colombier }; 96*906943f9SDavid du Colombier 97*906943f9SDavid du Colombier static int 98*906943f9SDavid du Colombier asixset(Dev *d, int c, int v) 99*906943f9SDavid du Colombier { 100*906943f9SDavid du Colombier int r; 101*906943f9SDavid du Colombier int ec; 102*906943f9SDavid du Colombier 103*906943f9SDavid du Colombier r = Rh2d|Rvendor|Rdev; 104*906943f9SDavid du Colombier ec = usbcmd(d, r, c, v, 0, nil, 0); 105*906943f9SDavid du Colombier if(ec < 0) 106*906943f9SDavid du Colombier deprint(2, "%s: asixset %x %x: %r\n", argv0, c, v); 107*906943f9SDavid du Colombier return ec; 108*906943f9SDavid du Colombier } 109*906943f9SDavid du Colombier 110*906943f9SDavid du Colombier static int 111*906943f9SDavid du Colombier asixget(Dev *d, int c, uchar *buf, int l) 112*906943f9SDavid du Colombier { 113*906943f9SDavid du Colombier int r; 114*906943f9SDavid du Colombier int ec; 115*906943f9SDavid du Colombier 116*906943f9SDavid du Colombier r = Rd2h|Rvendor|Rdev; 117*906943f9SDavid du Colombier ec = usbcmd(d, r, c, 0, 0, buf, l); 118*906943f9SDavid du Colombier if(ec < 0) 119*906943f9SDavid du Colombier deprint(2, "%s: asixget %x: %r\n", argv0, c); 120*906943f9SDavid du Colombier return ec; 121*906943f9SDavid du Colombier } 122*906943f9SDavid du Colombier 123*906943f9SDavid du Colombier static int 124*906943f9SDavid du Colombier getgpio(Dev *d) 125*906943f9SDavid du Colombier { 126*906943f9SDavid du Colombier uchar c; 127*906943f9SDavid du Colombier 128*906943f9SDavid du Colombier if(asixget(d, Crgpio, &c, 1) < 0) 129*906943f9SDavid du Colombier return -1; 130*906943f9SDavid du Colombier return c; 131*906943f9SDavid du Colombier } 132*906943f9SDavid du Colombier 133*906943f9SDavid du Colombier static int 134*906943f9SDavid du Colombier getphy(Dev *d) 135*906943f9SDavid du Colombier { 136*906943f9SDavid du Colombier uchar buf[2]; 137*906943f9SDavid du Colombier 138*906943f9SDavid du Colombier if(asixget(d, Crphy, buf, sizeof(buf)) < 0) 139*906943f9SDavid du Colombier return -1; 140*906943f9SDavid du Colombier deprint(2, "%s: phy addr %#ux\n", argv0, buf[1]); 141*906943f9SDavid du Colombier return buf[1]; 142*906943f9SDavid du Colombier } 143*906943f9SDavid du Colombier 144*906943f9SDavid du Colombier static int 145*906943f9SDavid du Colombier getrxctl(Dev *d) 146*906943f9SDavid du Colombier { 147*906943f9SDavid du Colombier uchar buf[2]; 148*906943f9SDavid du Colombier int r; 149*906943f9SDavid du Colombier 150*906943f9SDavid du Colombier memset(buf, 0, sizeof(buf)); 151*906943f9SDavid du Colombier if(asixget(d, Crrxctl, buf, sizeof(buf)) < 0) 152*906943f9SDavid du Colombier return -1; 153*906943f9SDavid du Colombier r = GET2(buf); 154*906943f9SDavid du Colombier deprint(2, "%s: rxctl %#x\n", argv0, r); 155*906943f9SDavid du Colombier return r; 156*906943f9SDavid du Colombier } 157*906943f9SDavid du Colombier 158*906943f9SDavid du Colombier static int 159*906943f9SDavid du Colombier getmac(Dev *d, uchar buf[]) 160*906943f9SDavid du Colombier { 161*906943f9SDavid du Colombier if(asixget(d, Crmac, buf, Eaddrlen) < 0) 162*906943f9SDavid du Colombier return -1; 163*906943f9SDavid du Colombier return Eaddrlen; 164*906943f9SDavid du Colombier } 165*906943f9SDavid du Colombier 166*906943f9SDavid du Colombier static int 167*906943f9SDavid du Colombier miiread(Dev *d, int phy, int reg) 168*906943f9SDavid du Colombier { 169*906943f9SDavid du Colombier int r; 170*906943f9SDavid du Colombier uchar v[2]; 171*906943f9SDavid du Colombier 172*906943f9SDavid du Colombier r = Rd2h|Rvendor|Rdev; 173*906943f9SDavid du Colombier if(usbcmd(d, r, Crmii, phy, reg, v, 2) < 0){ 174*906943f9SDavid du Colombier dprint(2, "%s: miiwrite: %r\n", argv0); 175*906943f9SDavid du Colombier return -1; 176*906943f9SDavid du Colombier } 177*906943f9SDavid du Colombier r = GET2(v); 178*906943f9SDavid du Colombier if(r == 0xFFFF) 179*906943f9SDavid du Colombier return -1; 180*906943f9SDavid du Colombier return r; 181*906943f9SDavid du Colombier } 182*906943f9SDavid du Colombier 183*906943f9SDavid du Colombier 184*906943f9SDavid du Colombier static int 185*906943f9SDavid du Colombier miiwrite(Dev *d, int phy, int reg, int val) 186*906943f9SDavid du Colombier { 187*906943f9SDavid du Colombier int r; 188*906943f9SDavid du Colombier uchar v[2]; 189*906943f9SDavid du Colombier 190*906943f9SDavid du Colombier if(asixset(d, Cswmii, 0) < 0) 191*906943f9SDavid du Colombier return -1; 192*906943f9SDavid du Colombier r = Rh2d|Rvendor|Rdev; 193*906943f9SDavid du Colombier PUT2(v, val); 194*906943f9SDavid du Colombier if(usbcmd(d, r, Cwmii, phy, reg, v, 2) < 0){ 195*906943f9SDavid du Colombier deprint(2, "%s: miiwrite: %#x %#x %r\n", argv0, reg, val); 196*906943f9SDavid du Colombier return -1; 197*906943f9SDavid du Colombier } 198*906943f9SDavid du Colombier if(asixset(d, Chwmii, 0) < 0) 199*906943f9SDavid du Colombier return -1; 200*906943f9SDavid du Colombier return 0; 201*906943f9SDavid du Colombier } 202*906943f9SDavid du Colombier 203*906943f9SDavid du Colombier static int 204*906943f9SDavid du Colombier eepromread(Dev *d, int i) 205*906943f9SDavid du Colombier { 206*906943f9SDavid du Colombier int r; 207*906943f9SDavid du Colombier int ec; 208*906943f9SDavid du Colombier uchar buf[2]; 209*906943f9SDavid du Colombier 210*906943f9SDavid du Colombier r = Rd2h|Rvendor|Rdev; 211*906943f9SDavid du Colombier ec = usbcmd(d, r, Creeprom, i, 0, buf, sizeof(buf)); 212*906943f9SDavid du Colombier if(ec < 0) 213*906943f9SDavid du Colombier deprint(2, "%s: eepromread %d: %r\n", argv0, i); 214*906943f9SDavid du Colombier ec = GET2(buf); 215*906943f9SDavid du Colombier deprint(2, "%s: eeprom %#x = %#x\n", argv0, i, ec); 216*906943f9SDavid du Colombier if(ec == 0xFFFF) 217*906943f9SDavid du Colombier ec = -1; 218*906943f9SDavid du Colombier return ec; 219*906943f9SDavid du Colombier } 220*906943f9SDavid du Colombier 221*906943f9SDavid du Colombier /* 222*906943f9SDavid du Colombier * No doc. we are doing what Linux does as closely 223*906943f9SDavid du Colombier * as we can. 224*906943f9SDavid du Colombier */ 225*906943f9SDavid du Colombier static int 226*906943f9SDavid du Colombier ctlrinit(Ether *ether) 227*906943f9SDavid du Colombier { 228*906943f9SDavid du Colombier Dev *d; 229*906943f9SDavid du Colombier int i; 230*906943f9SDavid du Colombier int bmcr; 231*906943f9SDavid du Colombier int gpio; 232*906943f9SDavid du Colombier int ee17; 233*906943f9SDavid du Colombier int rc; 234*906943f9SDavid du Colombier 235*906943f9SDavid du Colombier d = ether->dev; 236*906943f9SDavid du Colombier switch(ether->cid){ 237*906943f9SDavid du Colombier default: 238*906943f9SDavid du Colombier fprint(2, "%s: card known but not implemented\n", argv0); 239*906943f9SDavid du Colombier return -1; 240*906943f9SDavid du Colombier 241*906943f9SDavid du Colombier case A88178: 242*906943f9SDavid du Colombier deprint(2, "%s: setting up A88178\n", argv0); 243*906943f9SDavid du Colombier gpio = getgpio(d); 244*906943f9SDavid du Colombier if(gpio < 0) 245*906943f9SDavid du Colombier return -1; 246*906943f9SDavid du Colombier deprint(2, "%s: gpio sts %#x\n", argv0, gpio); 247*906943f9SDavid du Colombier asixset(d, Cwena, 0); 248*906943f9SDavid du Colombier ee17 = eepromread(d, 0x0017); 249*906943f9SDavid du Colombier asixset(d, Cwdis, 0); 250*906943f9SDavid du Colombier asixset(d, Cwgpio, Gpiorse|Gpiogpo1|Gpiogpo1en); 251*906943f9SDavid du Colombier if((ee17 >> 8) != 1){ 252*906943f9SDavid du Colombier asixset(d, Cwgpio, 0x003c); 253*906943f9SDavid du Colombier asixset(d, Cwgpio, 0x001c); 254*906943f9SDavid du Colombier asixset(d, Cwgpio, 0x003c); 255*906943f9SDavid du Colombier }else{ 256*906943f9SDavid du Colombier asixset(d, Cwgpio, Gpiogpo1en); 257*906943f9SDavid du Colombier asixset(d, Cwgpio, Gpiogpo1|Gpiogpo1en); 258*906943f9SDavid du Colombier } 259*906943f9SDavid du Colombier asixset(d, Creset, Rclear); 260*906943f9SDavid du Colombier sleep(150); 261*906943f9SDavid du Colombier asixset(d, Creset, Rippd|Rprl); 262*906943f9SDavid du Colombier sleep(150); 263*906943f9SDavid du Colombier asixset(d, Cwrxctl, 0); 264*906943f9SDavid du Colombier if(getmac(d, ether->addr) < 0) 265*906943f9SDavid du Colombier return -1; 266*906943f9SDavid du Colombier ether->phy = getphy(d); 267*906943f9SDavid du Colombier if(ee17 < 0 || (ee17 & 0x7) == 0){ 268*906943f9SDavid du Colombier miiwrite(d, ether->phy, Miimctl, Mtxrxdly); 269*906943f9SDavid du Colombier sleep(60); 270*906943f9SDavid du Colombier } 271*906943f9SDavid du Colombier miiwrite(d, ether->phy, Miibmcr, Bmcrreset|Bmcranena); 272*906943f9SDavid du Colombier miiwrite(d, ether->phy, Miiad, Adall|Adcsma|Adpause); 273*906943f9SDavid du Colombier miiwrite(d, ether->phy, Miic1000, Ad1000f); 274*906943f9SDavid du Colombier bmcr = miiread(d, ether->phy, Miibmcr); 275*906943f9SDavid du Colombier if((bmcr & Bmcranena) != 0){ 276*906943f9SDavid du Colombier bmcr |= Bmcrar; 277*906943f9SDavid du Colombier miiwrite(d, ether->phy, Miibmcr, bmcr); 278*906943f9SDavid du Colombier } 279*906943f9SDavid du Colombier asixset(d, Cwmedium, Mall178); 280*906943f9SDavid du Colombier asixset(d, Cwrxctl, Rxctlso|Rxctlab); 281*906943f9SDavid du Colombier break; 282*906943f9SDavid du Colombier 283*906943f9SDavid du Colombier case A88772: 284*906943f9SDavid du Colombier deprint(2, "%s: setting up A88772\n", argv0); 285*906943f9SDavid du Colombier if(asixset(d, Cwgpio, Gpiorse|Gpiogpo2|Gpiogpo2en) < 0) 286*906943f9SDavid du Colombier return -1; 287*906943f9SDavid du Colombier ether->phy = getphy(d); 288*906943f9SDavid du Colombier dprint(2, "%s: phy %#x\n", argv0, ether->phy); 289*906943f9SDavid du Colombier if((ether->phy & Pmask) == Pembed){ 290*906943f9SDavid du Colombier /* embedded 10/100 ethernet */ 291*906943f9SDavid du Colombier rc = asixset(d, Cwphy, 1); 292*906943f9SDavid du Colombier }else 293*906943f9SDavid du Colombier rc = asixset(d, Cwphy, 0); 294*906943f9SDavid du Colombier if(rc < 0) 295*906943f9SDavid du Colombier return -1; 296*906943f9SDavid du Colombier if(asixset(d, Creset, Rippd|Rprl) < 0) 297*906943f9SDavid du Colombier return -1; 298*906943f9SDavid du Colombier sleep(150); 299*906943f9SDavid du Colombier if((ether->phy & Pmask) == Pembed) 300*906943f9SDavid du Colombier rc = asixset(d, Creset, Riprl); 301*906943f9SDavid du Colombier else 302*906943f9SDavid du Colombier rc = asixset(d, Creset, Rprte); 303*906943f9SDavid du Colombier if(rc < 0) 304*906943f9SDavid du Colombier return -1; 305*906943f9SDavid du Colombier sleep(150); 306*906943f9SDavid du Colombier rc = getrxctl(d); 307*906943f9SDavid du Colombier deprint(2, "%s: rxctl is %#x\n", argv0, rc); 308*906943f9SDavid du Colombier if(asixset(d, Cwrxctl, 0) < 0) 309*906943f9SDavid du Colombier return -1; 310*906943f9SDavid du Colombier if(getmac(d, ether->addr) < 0) 311*906943f9SDavid du Colombier return -1; 312*906943f9SDavid du Colombier 313*906943f9SDavid du Colombier 314*906943f9SDavid du Colombier if(asixset(d, Creset, Rprl) < 0) 315*906943f9SDavid du Colombier return -1; 316*906943f9SDavid du Colombier sleep(150); 317*906943f9SDavid du Colombier if(asixset(d, Creset, Riprl|Rprl) < 0) 318*906943f9SDavid du Colombier return -1; 319*906943f9SDavid du Colombier sleep(150); 320*906943f9SDavid du Colombier 321*906943f9SDavid du Colombier miiwrite(d, ether->phy, Miibmcr, Bmcrreset); 322*906943f9SDavid du Colombier miiwrite(d, ether->phy, Miiad, Adall|Adcsma); 323*906943f9SDavid du Colombier bmcr = miiread(d, ether->phy, Miibmcr); 324*906943f9SDavid du Colombier if((bmcr & Bmcranena) != 0){ 325*906943f9SDavid du Colombier bmcr |= Bmcrar; 326*906943f9SDavid du Colombier miiwrite(d, ether->phy, Miibmcr, bmcr); 327*906943f9SDavid du Colombier } 328*906943f9SDavid du Colombier if(asixset(d, Cwmedium, Mall772) < 0) 329*906943f9SDavid du Colombier return -1; 330*906943f9SDavid du Colombier if(asixset(d, Cwipg, Ipgdflt) < 0) 331*906943f9SDavid du Colombier return -1; 332*906943f9SDavid du Colombier if(asixset(d, Cwrxctl, Rxctlso|Rxctlab) < 0) 333*906943f9SDavid du Colombier return -1; 334*906943f9SDavid du Colombier deprint(2, "%s: final rxctl: %#x\n", argv0, getrxctl(d)); 335*906943f9SDavid du Colombier break; 336*906943f9SDavid du Colombier } 337*906943f9SDavid du Colombier 338*906943f9SDavid du Colombier if(etherdebug){ 339*906943f9SDavid du Colombier fprint(2, "%s: ether: phy %#x addr ", argv0, ether->phy); 340*906943f9SDavid du Colombier for(i = 0; i < sizeof(ether->addr); i++) 341*906943f9SDavid du Colombier fprint(2, "%02x", ether->addr[i]); 342*906943f9SDavid du Colombier fprint(2, "\n"); 343*906943f9SDavid du Colombier } 344*906943f9SDavid du Colombier return 0; 345*906943f9SDavid du Colombier } 346*906943f9SDavid du Colombier 347*906943f9SDavid du Colombier 348*906943f9SDavid du Colombier static long 349*906943f9SDavid du Colombier asixbread(Ether *e, Buf *bp) 350*906943f9SDavid du Colombier { 351*906943f9SDavid du Colombier ulong nr; 352*906943f9SDavid du Colombier ulong hd; 353*906943f9SDavid du Colombier Buf *rbp; 354*906943f9SDavid du Colombier 355*906943f9SDavid du Colombier rbp = e->aux; 356*906943f9SDavid du Colombier if(rbp == nil || rbp->ndata < 4){ 357*906943f9SDavid du Colombier rbp->rp = rbp->data; 358*906943f9SDavid du Colombier rbp->ndata = read(e->epin->dfd, rbp->rp, sizeof(bp->data)); 359*906943f9SDavid du Colombier if(rbp->ndata < 0) 360*906943f9SDavid du Colombier return -1; 361*906943f9SDavid du Colombier } 362*906943f9SDavid du Colombier if(rbp->ndata < 4){ 363*906943f9SDavid du Colombier werrstr("short frame"); 364*906943f9SDavid du Colombier deprint(2, "%s: asixbread got %d bytes\n", argv0, rbp->ndata); 365*906943f9SDavid du Colombier rbp->ndata = 0; 366*906943f9SDavid du Colombier return 0; 367*906943f9SDavid du Colombier } 368*906943f9SDavid du Colombier hd = GET4(rbp->rp); 369*906943f9SDavid du Colombier nr = hd & 0xFFFF; 370*906943f9SDavid du Colombier hd = (hd>>16) & 0xFFFF; 371*906943f9SDavid du Colombier if(nr != (~hd & 0xFFFF)){ 372*906943f9SDavid du Colombier if(0)deprint(2, "%s: asixread: bad header %#ulx %#ulx\n", 373*906943f9SDavid du Colombier argv0, nr, (~hd & 0xFFFF)); 374*906943f9SDavid du Colombier werrstr("bad usb packet header"); 375*906943f9SDavid du Colombier rbp->ndata = 0; 376*906943f9SDavid du Colombier return 0; 377*906943f9SDavid du Colombier } 378*906943f9SDavid du Colombier rbp->rp += 4; 379*906943f9SDavid du Colombier if(nr < 6 || nr > Epktlen){ 380*906943f9SDavid du Colombier if(nr < 6) 381*906943f9SDavid du Colombier werrstr("short frame"); 382*906943f9SDavid du Colombier else 383*906943f9SDavid du Colombier werrstr("long frame"); 384*906943f9SDavid du Colombier deprint(2, "%s: asixbread %r (%ld)\n", argv0, nr); 385*906943f9SDavid du Colombier rbp->ndata = 0; 386*906943f9SDavid du Colombier return 0; 387*906943f9SDavid du Colombier } 388*906943f9SDavid du Colombier bp->rp = bp->data + Hdrsize; 389*906943f9SDavid du Colombier memmove(bp->rp, rbp->rp, nr); 390*906943f9SDavid du Colombier bp->ndata = nr; 391*906943f9SDavid du Colombier rbp->rp += 4 + nr; 392*906943f9SDavid du Colombier rbp->ndata -= (4 + nr); 393*906943f9SDavid du Colombier return bp->ndata; 394*906943f9SDavid du Colombier } 395*906943f9SDavid du Colombier 396*906943f9SDavid du Colombier static long 397*906943f9SDavid du Colombier asixbwrite(Ether *e, Buf *bp) 398*906943f9SDavid du Colombier { 399*906943f9SDavid du Colombier ulong len; 400*906943f9SDavid du Colombier long n; 401*906943f9SDavid du Colombier 402*906943f9SDavid du Colombier deprint(2, "%s: asixbwrite %d bytes\n", argv0, bp->ndata); 403*906943f9SDavid du Colombier assert(bp->rp - bp->data >= Hdrsize); 404*906943f9SDavid du Colombier bp->ndata &= 0xFFFF; 405*906943f9SDavid du Colombier len = (0xFFFF0000 & ~(bp->ndata<<16)) | bp->ndata; 406*906943f9SDavid du Colombier bp->rp -= 4; 407*906943f9SDavid du Colombier PUT4(bp->rp, len); 408*906943f9SDavid du Colombier bp->ndata += 4; 409*906943f9SDavid du Colombier if((bp->ndata % e->epout->maxpkt) == 0){ 410*906943f9SDavid du Colombier PUT4(bp->rp+bp->ndata, 0xFFFF0000); 411*906943f9SDavid du Colombier bp->ndata += 4; 412*906943f9SDavid du Colombier } 413*906943f9SDavid du Colombier n = write(e->epout->dfd, bp->rp, bp->ndata); 414*906943f9SDavid du Colombier deprint(2, "%s: asixbwrite wrote %ld bytes\n", argv0, n); 415*906943f9SDavid du Colombier if(n <= 0) 416*906943f9SDavid du Colombier return n; 417*906943f9SDavid du Colombier return n; 418*906943f9SDavid du Colombier } 419*906943f9SDavid du Colombier 420*906943f9SDavid du Colombier static int 421*906943f9SDavid du Colombier asixpromiscuous(Ether *e, int on) 422*906943f9SDavid du Colombier { 423*906943f9SDavid du Colombier int rxctl; 424*906943f9SDavid du Colombier 425*906943f9SDavid du Colombier deprint(2, "%s: aixprompiscuous %d\n", argv0, on); 426*906943f9SDavid du Colombier rxctl = getrxctl(e->dev); 427*906943f9SDavid du Colombier if(on != 0) 428*906943f9SDavid du Colombier rxctl |= Rxctlprom; 429*906943f9SDavid du Colombier else 430*906943f9SDavid du Colombier rxctl &= ~Rxctlprom; 431*906943f9SDavid du Colombier return asixset(e->dev, Cwrxctl, rxctl); 432*906943f9SDavid du Colombier } 433*906943f9SDavid du Colombier 434*906943f9SDavid du Colombier static int 435*906943f9SDavid du Colombier asixmulticast(Ether *e, uchar *addr, int on) 436*906943f9SDavid du Colombier { 437*906943f9SDavid du Colombier int rxctl; 438*906943f9SDavid du Colombier 439*906943f9SDavid du Colombier USED(addr); 440*906943f9SDavid du Colombier USED(on); 441*906943f9SDavid du Colombier /* BUG: should write multicast filter */ 442*906943f9SDavid du Colombier rxctl = getrxctl(e->dev); 443*906943f9SDavid du Colombier if(e->nmcasts != 0) 444*906943f9SDavid du Colombier rxctl |= Rxctlamall; 445*906943f9SDavid du Colombier else 446*906943f9SDavid du Colombier rxctl &= ~Rxctlamall; 447*906943f9SDavid du Colombier deprint(2, "%s: asixmulticast %d\n", argv0, e->nmcasts); 448*906943f9SDavid du Colombier return asixset(e->dev, Cwrxctl, rxctl); 449*906943f9SDavid du Colombier } 450*906943f9SDavid du Colombier 451*906943f9SDavid du Colombier static void 452*906943f9SDavid du Colombier asixfree(Ether *ether) 453*906943f9SDavid du Colombier { 454*906943f9SDavid du Colombier deprint(2, "%s: aixfree %#p\n", argv0, ether); 455*906943f9SDavid du Colombier free(ether->aux); 456*906943f9SDavid du Colombier ether->aux = nil; 457*906943f9SDavid du Colombier } 458*906943f9SDavid du Colombier 459*906943f9SDavid du Colombier int 460*906943f9SDavid du Colombier asixreset(Ether *ether) 461*906943f9SDavid du Colombier { 462*906943f9SDavid du Colombier Cinfo *ip; 463*906943f9SDavid du Colombier Dev *dev; 464*906943f9SDavid du Colombier 465*906943f9SDavid du Colombier dev = ether->dev; 466*906943f9SDavid du Colombier for(ip = cinfo; ip->vid != 0; ip++) 467*906943f9SDavid du Colombier if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){ 468*906943f9SDavid du Colombier ether->cid = ip->cid; 469*906943f9SDavid du Colombier if(ctlrinit(ether) < 0){ 470*906943f9SDavid du Colombier deprint(2, "%s: init failed: %r\n", argv0); 471*906943f9SDavid du Colombier return -1; 472*906943f9SDavid du Colombier } 473*906943f9SDavid du Colombier deprint(2, "%s: asix reset done\n", argv0); 474*906943f9SDavid du Colombier ether->aux = emallocz(sizeof(Buf), 1); 475*906943f9SDavid du Colombier ether->bread = asixbread; 476*906943f9SDavid du Colombier ether->bwrite = asixbwrite; 477*906943f9SDavid du Colombier ether->free = asixfree; 478*906943f9SDavid du Colombier ether->promiscuous = asixpromiscuous; 479*906943f9SDavid du Colombier ether->multicast = asixmulticast; 480*906943f9SDavid du Colombier ether->mbps = 100; /* BUG */ 481*906943f9SDavid du Colombier return 0; 482*906943f9SDavid du Colombier } 483*906943f9SDavid du Colombier return -1; 484*906943f9SDavid du Colombier } 485