1*5e4f5c78SDavid du Colombier #include <u.h> 2*5e4f5c78SDavid du Colombier #include <libc.h> 3*5e4f5c78SDavid du Colombier #include <thread.h> 4*5e4f5c78SDavid du Colombier #include "usb.h" 5*5e4f5c78SDavid du Colombier #include "usbfs.h" 6*5e4f5c78SDavid du Colombier #include "serial.h" 7*5e4f5c78SDavid du Colombier #include "prolific.h" 8*5e4f5c78SDavid du Colombier 9*5e4f5c78SDavid du Colombier static void statusreader(void *u); 10*5e4f5c78SDavid du Colombier 11*5e4f5c78SDavid du Colombier static void 12*5e4f5c78SDavid du Colombier dumpbuf(uchar *buf, int bufsz) 13*5e4f5c78SDavid du Colombier { 14*5e4f5c78SDavid du Colombier int i; 15*5e4f5c78SDavid du Colombier 16*5e4f5c78SDavid du Colombier for(i=0; i<bufsz; i++) 17*5e4f5c78SDavid du Colombier print("buf[%d]=%#ux ", i, buf[i]); 18*5e4f5c78SDavid du Colombier print("\n"); 19*5e4f5c78SDavid du Colombier } 20*5e4f5c78SDavid du Colombier 21*5e4f5c78SDavid du Colombier static int 22*5e4f5c78SDavid du Colombier vendorread(Serial *ser, int val, int index, uchar *buf) 23*5e4f5c78SDavid du Colombier { 24*5e4f5c78SDavid du Colombier int res; 25*5e4f5c78SDavid du Colombier 26*5e4f5c78SDavid du Colombier dsprint(2, "serial: vendorread val: 0x%x idx:%d buf:%p\n", 27*5e4f5c78SDavid du Colombier val, index, buf); 28*5e4f5c78SDavid du Colombier res = usbcmd(ser->dev, Rd2h | Rvendor | Rdev, VendorReadReq, 29*5e4f5c78SDavid du Colombier val, index, buf, 1); 30*5e4f5c78SDavid du Colombier dsprint(2, "serial: vendorread res:%d\n", res); 31*5e4f5c78SDavid du Colombier return res; 32*5e4f5c78SDavid du Colombier } 33*5e4f5c78SDavid du Colombier 34*5e4f5c78SDavid du Colombier static int 35*5e4f5c78SDavid du Colombier vendorwrite(Serial *ser, int val, int index) 36*5e4f5c78SDavid du Colombier { 37*5e4f5c78SDavid du Colombier int res; 38*5e4f5c78SDavid du Colombier 39*5e4f5c78SDavid du Colombier dsprint(2, "serial: vendorwrite val: 0x%x idx:%d\n", val, index); 40*5e4f5c78SDavid du Colombier res = usbcmd(ser->dev, Rh2d | Rvendor | Rdev, VendorWriteReq, 41*5e4f5c78SDavid du Colombier val, index, nil, 0); 42*5e4f5c78SDavid du Colombier dsprint(2, "serial: vendorwrite res:%d\n", res); 43*5e4f5c78SDavid du Colombier return res; 44*5e4f5c78SDavid du Colombier } 45*5e4f5c78SDavid du Colombier 46*5e4f5c78SDavid du Colombier static int 47*5e4f5c78SDavid du Colombier plgetparam(Serial *ser) 48*5e4f5c78SDavid du Colombier { 49*5e4f5c78SDavid du Colombier uchar buf[7]; 50*5e4f5c78SDavid du Colombier int res; 51*5e4f5c78SDavid du Colombier 52*5e4f5c78SDavid du Colombier res = usbcmd(ser->dev, Rd2h | Rclass | Riface, GetLineReq, 53*5e4f5c78SDavid du Colombier 0, 0, buf, sizeof buf); 54*5e4f5c78SDavid du Colombier ser->baud = GET4(buf); 55*5e4f5c78SDavid du Colombier 56*5e4f5c78SDavid du Colombier /* 57*5e4f5c78SDavid du Colombier * with the Pl9 interface it is not possible to set `1.5' as stop bits 58*5e4f5c78SDavid du Colombier * for the prologic: 59*5e4f5c78SDavid du Colombier * 0 is 1 stop bit 60*5e4f5c78SDavid du Colombier * 1 is 1.5 stop bits 61*5e4f5c78SDavid du Colombier * 2 is 2 stop bits 62*5e4f5c78SDavid du Colombier */ 63*5e4f5c78SDavid du Colombier if(buf[4] == 1) 64*5e4f5c78SDavid du Colombier fprint(2, "warning, stop bit set to 1.5 unsupported"); 65*5e4f5c78SDavid du Colombier else if(buf[4] == 0) 66*5e4f5c78SDavid du Colombier ser->stop = 1; 67*5e4f5c78SDavid du Colombier else if(buf[4] == 2) 68*5e4f5c78SDavid du Colombier ser->stop = 2; 69*5e4f5c78SDavid du Colombier ser->parity = buf[5]; 70*5e4f5c78SDavid du Colombier ser->bits = buf[6]; 71*5e4f5c78SDavid du Colombier 72*5e4f5c78SDavid du Colombier dsprint(2, "serial: getparam: "); 73*5e4f5c78SDavid du Colombier if(serialdebug) 74*5e4f5c78SDavid du Colombier dumpbuf(buf, sizeof buf); 75*5e4f5c78SDavid du Colombier dsprint(2, "serial: getparam res: %d\n", res); 76*5e4f5c78SDavid du Colombier return res; 77*5e4f5c78SDavid du Colombier } 78*5e4f5c78SDavid du Colombier 79*5e4f5c78SDavid du Colombier static void 80*5e4f5c78SDavid du Colombier plmodemctl(Serial *ser, int set) 81*5e4f5c78SDavid du Colombier { 82*5e4f5c78SDavid du Colombier if(set == 0){ 83*5e4f5c78SDavid du Colombier ser->mctl = 0; 84*5e4f5c78SDavid du Colombier vendorwrite(ser, 0x0, 0x0); 85*5e4f5c78SDavid du Colombier return; 86*5e4f5c78SDavid du Colombier } 87*5e4f5c78SDavid du Colombier 88*5e4f5c78SDavid du Colombier ser->mctl = 1; 89*5e4f5c78SDavid du Colombier if(ser->type == TypeHX) 90*5e4f5c78SDavid du Colombier vendorwrite(ser, 0x0, Dcr0InitX); 91*5e4f5c78SDavid du Colombier else 92*5e4f5c78SDavid du Colombier vendorwrite(ser, 0x0, Dcr0InitH); 93*5e4f5c78SDavid du Colombier } 94*5e4f5c78SDavid du Colombier 95*5e4f5c78SDavid du Colombier static int 96*5e4f5c78SDavid du Colombier plsetparam(Serial *ser) 97*5e4f5c78SDavid du Colombier { 98*5e4f5c78SDavid du Colombier uchar buf[7]; 99*5e4f5c78SDavid du Colombier int res; 100*5e4f5c78SDavid du Colombier 101*5e4f5c78SDavid du Colombier PUT4(buf, ser->baud); 102*5e4f5c78SDavid du Colombier 103*5e4f5c78SDavid du Colombier if(ser->stop == 1) 104*5e4f5c78SDavid du Colombier buf[4] = 0; 105*5e4f5c78SDavid du Colombier else if(ser->stop == 2) 106*5e4f5c78SDavid du Colombier buf[4] = 2; /* see comment in getparam */ 107*5e4f5c78SDavid du Colombier buf[5] = ser->parity; 108*5e4f5c78SDavid du Colombier buf[6] = ser->bits; 109*5e4f5c78SDavid du Colombier 110*5e4f5c78SDavid du Colombier dsprint(2, "serial: setparam: "); 111*5e4f5c78SDavid du Colombier if(serialdebug) 112*5e4f5c78SDavid du Colombier dumpbuf(buf, sizeof buf); 113*5e4f5c78SDavid du Colombier res = usbcmd(ser->dev, Rh2d | Rclass | Riface, SetLineReq, 114*5e4f5c78SDavid du Colombier 0, 0, buf, sizeof buf); 115*5e4f5c78SDavid du Colombier plmodemctl(ser, ser->mctl); 116*5e4f5c78SDavid du Colombier plgetparam(ser); /* make sure our state corresponds */ 117*5e4f5c78SDavid du Colombier 118*5e4f5c78SDavid du Colombier dsprint(2, "serial: setparam res: %d\n", res); 119*5e4f5c78SDavid du Colombier return res; 120*5e4f5c78SDavid du Colombier } 121*5e4f5c78SDavid du Colombier 122*5e4f5c78SDavid du Colombier static int 123*5e4f5c78SDavid du Colombier plinit(Serial *ser) 124*5e4f5c78SDavid du Colombier { 125*5e4f5c78SDavid du Colombier ulong csp; 126*5e4f5c78SDavid du Colombier char *st; 127*5e4f5c78SDavid du Colombier uchar *buf; 128*5e4f5c78SDavid du Colombier 129*5e4f5c78SDavid du Colombier buf = emallocz(VendorReqSize, 1); 130*5e4f5c78SDavid du Colombier qlock(ser); 131*5e4f5c78SDavid du Colombier serialreset(ser); 132*5e4f5c78SDavid du Colombier csp = ser->dev->usb->csp; 133*5e4f5c78SDavid du Colombier 134*5e4f5c78SDavid du Colombier if(Class(csp) == 0x02) 135*5e4f5c78SDavid du Colombier ser->type = Type0; 136*5e4f5c78SDavid du Colombier else if(ser->dev->maxpkt == 0x40) 137*5e4f5c78SDavid du Colombier ser->type = TypeHX; 138*5e4f5c78SDavid du Colombier else if(Class(csp) == 0x00 || Class(csp) == 0xFF) 139*5e4f5c78SDavid du Colombier ser->type = Type1; 140*5e4f5c78SDavid du Colombier 141*5e4f5c78SDavid du Colombier if(ser->type != ser->dev->usb->psid) 142*5e4f5c78SDavid du Colombier fprint(2, "serial: warning, heuristics: %#ux and psid: " 143*5e4f5c78SDavid du Colombier "%#ux, not a match\n", ser->type, ser->dev->usb->psid); 144*5e4f5c78SDavid du Colombier dsprint(2, "serial: type %d\n", ser->type); 145*5e4f5c78SDavid du Colombier 146*5e4f5c78SDavid du Colombier vendorread(ser, 0x8484, 0, buf); 147*5e4f5c78SDavid du Colombier vendorwrite(ser, 0x0404, 0); 148*5e4f5c78SDavid du Colombier vendorread(ser, 0x8484, 0, buf); 149*5e4f5c78SDavid du Colombier vendorread(ser, 0x8383, 0, buf); 150*5e4f5c78SDavid du Colombier vendorread(ser, 0x8484, 0, buf); 151*5e4f5c78SDavid du Colombier vendorwrite(ser, 0x0404, 1); 152*5e4f5c78SDavid du Colombier vendorread(ser, 0x8484, 0, buf); 153*5e4f5c78SDavid du Colombier vendorread(ser, 0x8383, 0, buf); 154*5e4f5c78SDavid du Colombier vendorwrite(ser, 0, 1); 155*5e4f5c78SDavid du Colombier vendorwrite(ser, 1, 0); 156*5e4f5c78SDavid du Colombier 157*5e4f5c78SDavid du Colombier if(ser->type == TypeHX) 158*5e4f5c78SDavid du Colombier vendorwrite(ser, 2, Dcr2InitX); 159*5e4f5c78SDavid du Colombier else 160*5e4f5c78SDavid du Colombier vendorwrite(ser, 2, Dcr2InitH); 161*5e4f5c78SDavid du Colombier 162*5e4f5c78SDavid du Colombier plgetparam(ser); 163*5e4f5c78SDavid du Colombier qunlock(ser); 164*5e4f5c78SDavid du Colombier free(buf); 165*5e4f5c78SDavid du Colombier st = emallocz(255, 1); 166*5e4f5c78SDavid du Colombier qlock(ser); 167*5e4f5c78SDavid du Colombier if(serialdebug) 168*5e4f5c78SDavid du Colombier dumpstatus(ser, st, 255); 169*5e4f5c78SDavid du Colombier dsprint(2, st); 170*5e4f5c78SDavid du Colombier qunlock(ser); 171*5e4f5c78SDavid du Colombier free(st); 172*5e4f5c78SDavid du Colombier /* ser gets freed by closedev, the process has a reference */ 173*5e4f5c78SDavid du Colombier incref(ser->dev); 174*5e4f5c78SDavid du Colombier proccreate(statusreader, ser, 8*1024); 175*5e4f5c78SDavid du Colombier return 0; 176*5e4f5c78SDavid du Colombier } 177*5e4f5c78SDavid du Colombier 178*5e4f5c78SDavid du Colombier static int 179*5e4f5c78SDavid du Colombier plsetbreak(Serial *ser, int val) 180*5e4f5c78SDavid du Colombier { 181*5e4f5c78SDavid du Colombier return usbcmd(ser->dev, Rh2d | Rclass | Riface, 182*5e4f5c78SDavid du Colombier (val != 0? BreakOn: BreakOff), val, 0, nil, 0); 183*5e4f5c78SDavid du Colombier } 184*5e4f5c78SDavid du Colombier 185*5e4f5c78SDavid du Colombier static void 186*5e4f5c78SDavid du Colombier plclearpipes(Serial *ser) 187*5e4f5c78SDavid du Colombier { 188*5e4f5c78SDavid du Colombier if(ser->type == TypeHX){ 189*5e4f5c78SDavid du Colombier vendorwrite(ser, 8, 0x0); 190*5e4f5c78SDavid du Colombier vendorwrite(ser, 9, 0x0); 191*5e4f5c78SDavid du Colombier }else{ 192*5e4f5c78SDavid du Colombier if(unstall(ser->dev, ser->epout, Eout) < 0) 193*5e4f5c78SDavid du Colombier dprint(2, "disk: unstall epout: %r\n"); 194*5e4f5c78SDavid du Colombier if(unstall(ser->dev, ser->epin, Ein) < 0) 195*5e4f5c78SDavid du Colombier dprint(2, "disk: unstall epin: %r\n"); 196*5e4f5c78SDavid du Colombier if(unstall(ser->dev, ser->epintr, Ein) < 0) 197*5e4f5c78SDavid du Colombier dprint(2, "disk: unstall epintr: %r\n"); 198*5e4f5c78SDavid du Colombier } 199*5e4f5c78SDavid du Colombier } 200*5e4f5c78SDavid du Colombier 201*5e4f5c78SDavid du Colombier static int 202*5e4f5c78SDavid du Colombier setctlline(Serial *ser, uchar val) 203*5e4f5c78SDavid du Colombier { 204*5e4f5c78SDavid du Colombier return usbcmd(ser->dev, Rh2d | Rclass | Riface, SetCtlReq, 205*5e4f5c78SDavid du Colombier val, 0, nil, 0); 206*5e4f5c78SDavid du Colombier } 207*5e4f5c78SDavid du Colombier 208*5e4f5c78SDavid du Colombier static void 209*5e4f5c78SDavid du Colombier composectl(Serial *ser) 210*5e4f5c78SDavid du Colombier { 211*5e4f5c78SDavid du Colombier if(ser->rts) 212*5e4f5c78SDavid du Colombier ser->ctlstate |= CtlRTS; 213*5e4f5c78SDavid du Colombier else 214*5e4f5c78SDavid du Colombier ser->ctlstate &= ~CtlRTS; 215*5e4f5c78SDavid du Colombier if(ser->dtr) 216*5e4f5c78SDavid du Colombier ser->ctlstate |= CtlDTR; 217*5e4f5c78SDavid du Colombier else 218*5e4f5c78SDavid du Colombier ser->ctlstate &= ~CtlDTR; 219*5e4f5c78SDavid du Colombier } 220*5e4f5c78SDavid du Colombier 221*5e4f5c78SDavid du Colombier void 222*5e4f5c78SDavid du Colombier plsendlines(Serial *ser) 223*5e4f5c78SDavid du Colombier { 224*5e4f5c78SDavid du Colombier int res; 225*5e4f5c78SDavid du Colombier 226*5e4f5c78SDavid du Colombier dsprint(2, "serial: sendlines: %#2.2x\n", ser->ctlstate); 227*5e4f5c78SDavid du Colombier composectl(ser); 228*5e4f5c78SDavid du Colombier res = setctlline(ser, ser->ctlstate); 229*5e4f5c78SDavid du Colombier dsprint(2, "serial: getparam res: %d\n", res); 230*5e4f5c78SDavid du Colombier } 231*5e4f5c78SDavid du Colombier 232*5e4f5c78SDavid du Colombier static int 233*5e4f5c78SDavid du Colombier plreadstatus(Serial *ser) 234*5e4f5c78SDavid du Colombier { 235*5e4f5c78SDavid du Colombier int nr, dfd; 236*5e4f5c78SDavid du Colombier char err[40]; 237*5e4f5c78SDavid du Colombier uchar buf[10]; 238*5e4f5c78SDavid du Colombier 239*5e4f5c78SDavid du Colombier qlock(ser); 240*5e4f5c78SDavid du Colombier dsprint(2, "serial: reading from interrupt\n"); 241*5e4f5c78SDavid du Colombier dfd = ser->epintr->dfd; 242*5e4f5c78SDavid du Colombier 243*5e4f5c78SDavid du Colombier qunlock(ser); 244*5e4f5c78SDavid du Colombier nr = read(dfd, buf, sizeof buf); 245*5e4f5c78SDavid du Colombier qlock(ser); 246*5e4f5c78SDavid du Colombier snprint(err, sizeof err, "%r"); 247*5e4f5c78SDavid du Colombier dsprint(2, "serial: interrupt read %d %r\n", nr); 248*5e4f5c78SDavid du Colombier 249*5e4f5c78SDavid du Colombier if(nr < 0 && strstr(err, "timed out") != nil){ 250*5e4f5c78SDavid du Colombier dsprint(2, "serial: need to recover, status read %d %r\n", nr); 251*5e4f5c78SDavid du Colombier if(serialrecover(ser, err) < 0){ 252*5e4f5c78SDavid du Colombier qunlock(ser); 253*5e4f5c78SDavid du Colombier return -1; 254*5e4f5c78SDavid du Colombier } 255*5e4f5c78SDavid du Colombier } 256*5e4f5c78SDavid du Colombier if(nr < 0) 257*5e4f5c78SDavid du Colombier dsprint(2, "serial: reading status: %r"); 258*5e4f5c78SDavid du Colombier else if(nr >= sizeof buf - 1){ 259*5e4f5c78SDavid du Colombier ser->dcd = buf[8] & DcdStatus; 260*5e4f5c78SDavid du Colombier ser->dsr = buf[8] & DsrStatus; 261*5e4f5c78SDavid du Colombier ser->cts = buf[8] & BreakerrStatus; 262*5e4f5c78SDavid du Colombier ser->ring = buf[8] & RingStatus; 263*5e4f5c78SDavid du Colombier ser->cts = buf[8] & CtsStatus; 264*5e4f5c78SDavid du Colombier if (buf[8] & FrerrStatus) 265*5e4f5c78SDavid du Colombier ser->nframeerr++; 266*5e4f5c78SDavid du Colombier if (buf[8] & ParerrStatus) 267*5e4f5c78SDavid du Colombier ser->nparityerr++; 268*5e4f5c78SDavid du Colombier if (buf[8] & OvererrStatus) 269*5e4f5c78SDavid du Colombier ser->novererr++; 270*5e4f5c78SDavid du Colombier } else 271*5e4f5c78SDavid du Colombier dsprint(2, "serial: bad status read %d\n", nr); 272*5e4f5c78SDavid du Colombier dsprint(2, "serial: finished read from interrupt %d\n", nr); 273*5e4f5c78SDavid du Colombier qunlock(ser); 274*5e4f5c78SDavid du Colombier return 0; 275*5e4f5c78SDavid du Colombier } 276*5e4f5c78SDavid du Colombier 277*5e4f5c78SDavid du Colombier static void 278*5e4f5c78SDavid du Colombier statusreader(void *u) 279*5e4f5c78SDavid du Colombier { 280*5e4f5c78SDavid du Colombier Serial *ser; 281*5e4f5c78SDavid du Colombier 282*5e4f5c78SDavid du Colombier ser = u; 283*5e4f5c78SDavid du Colombier threadsetname("statusreaderproc"); 284*5e4f5c78SDavid du Colombier 285*5e4f5c78SDavid du Colombier while(plreadstatus(ser) > 0) 286*5e4f5c78SDavid du Colombier ; 287*5e4f5c78SDavid du Colombier closedev(ser->dev); 288*5e4f5c78SDavid du Colombier } 289*5e4f5c78SDavid du Colombier 290*5e4f5c78SDavid du Colombier Serialops plops = { 291*5e4f5c78SDavid du Colombier .init = plinit, 292*5e4f5c78SDavid du Colombier .getparam = plgetparam, 293*5e4f5c78SDavid du Colombier .setparam = plsetparam, 294*5e4f5c78SDavid du Colombier .clearpipes = plclearpipes, 295*5e4f5c78SDavid du Colombier .sendlines = plsendlines, 296*5e4f5c78SDavid du Colombier .modemctl = plmodemctl, 297*5e4f5c78SDavid du Colombier .setbreak = plsetbreak, 298*5e4f5c78SDavid du Colombier }; 299