ref: 4c583d2f6d739b044385a429eca85e7a2dd8333c
dir: /sys/src/cmd/nusb/serial/acm.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <fcall.h> #include <9p.h> #include "usb.h" #include "serial.h" enum { SetCommReq = 0x02, SetLineReq = 0x20, BreakReq = 0x23, BreakOn = 0xffff, BreakOff = 0x0000, ParamReqSz = 7, Fncm = 0x1, /* call management */ Fnacm = 0x2, /* abstract control management */ }; static Serialops acmops; static int did; static int acmsetparam(Serialport *); static int acmmultiplex(Serial *); static int acmsetbreak(Serialport *, int); int acmprobe(Serial *ser) { int i, acmcap; Usbdev *ud; uchar *b; Desc *dd; acmcap = did = -1; ud = ser->dev->usb; for(i = 0; i < nelem(ud->ddesc); i++) if((dd = ud->ddesc[i]) != nil){ b = (uchar *)&dd->data; if(b[1] == Dfunction && b[2] == Fncm){ did = b[4]; } else if(b[1] == Dfunction && b[2] == Fnacm) acmcap = b[3]; } if(did < 0 || acmcap < 0) return -1; ser->Serialops = acmops; return 0; } static int acmsetparam(Serialport *p) { uchar buf[ParamReqSz]; int res; Serial *ser; ser = p->s; PUT4(buf, p->baud); buf[4] = p->stop; buf[5] = p->parity; buf[6] = p->bits; dsprint(2, "serial: setparam: "); res = usbcmd(ser->dev, Rh2d | Rclass | Riface, SetLineReq, 0, 0, buf, sizeof buf); if(res != ParamReqSz){ fprint(2, "serial: acmsetparam failed with res=%d\n", res); if(res >= 0) werrstr("acmsetparam failed with res=%d", res); return -1; } return 0; } static int acminit(Serialport *p) { p->baud = 9600; p->stop = 1; p->bits = 8; acmops.setparam(p); return 0; } static int acmwait4data(Serialport *p, uchar *data, int count) { int n; qunlock(p->s); while ((n = read(p->epin->dfd, data, count)) == 0) ; qlock(p->s); return n; } static int acmfindeps(Serial *ser, int ifc) { Ep **eps, *ep, *epin, *epout, *epintr; Usbdev *ud; Conf *c; int i; eps = nil; ud = ser->dev->usb; c = ud->conf[0]; for(i = 0; i < nelem(c->iface); i++) if(c->iface[i] != nil && c->iface[i]->id == did){ eps = c->iface[i]->ep; break; } epintr = epin = epout = nil; for(i = 0; i < Nep; i++){ if((ep = eps[i]) == nil) break; if(ser->hasepintr && ep->type == Eintr && ep->dir == Ein && epintr == nil) epintr = ep; if(ep->type == Ebulk){ if((ep->dir == Ein || ep->dir == Eboth) && epin == nil) epin = ep; if((ep->dir == Eout || ep->dir == Eboth) && epout == nil) epout = ep; } } if(epin == nil || epout == nil) return -1; if(openeps(&ser->p[ifc], epin, epout, nil) < 0) return -1; return 0; } static Serialops acmops = { .init = acminit, .setparam = acmsetparam, .wait4data = acmwait4data, .findeps = acmfindeps, };