ref: 9b69f546334e94ec191d35b15dcaace98fbdcb1b
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,
};