123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972 |
- #include <u.h>
- #include <libc.h>
- #include <thread.h>
- #include <auth.h>
- #include <fcall.h>
- #include <libsec.h>
- #include "usb.h"
- #include "usbaudio.h"
- #include "usbaudioctl.h"
- int attachok;
- #define STACKSIZE 16*1024
- enum
- {
- OPERM = 0x3, /* mask of all permission types in open mode */
- };
- typedef struct Fid Fid;
- typedef struct Audioctldata Audioctldata;
- typedef struct Worker Worker;
- struct Audioctldata
- {
- long offoff; /* offset of the offset for audioctl */
- long values[2][Ncontrol][8]; /* last values transmitted */
- char *s;
- int ns;
- };
- enum {
- Busy = 0x01,
- Open = 0x02,
- Eof = 0x04,
- };
- struct Fid
- {
- QLock;
- int fid;
- Dir *dir;
- ushort flags;
- short readers;
- void *fiddata; /* file specific per-fid data (used for audioctl) */
- Fid *next;
- };
- struct Worker
- {
- Fid *fid;
- ushort tag;
- Fcall *rhdr;
- Dir *dir;
- Channel *eventc;
- Worker *next;
- };
- enum {
- /* Event channel messages for worker */
- Work = 0x01,
- Check = 0x02,
- Flush = 0x03,
- };
- enum {
- Qdir,
- Qvolume,
- Qaudioctl,
- Qaudiostat,
- Qaudio,
- Qaudioin,
- Nqid,
- };
- Dir dirs[] = {
- /* Note: Qaudio{in} used as mount point for /dev/usb/%d/ep%ddata only */
- [Qdir] = {0,0,{Qdir, 0,QTDIR},0555|DMDIR,0,0,0, ".", nil,nil,nil},
- [Qvolume] = {0,0,{Qvolume, 0,QTFILE},0666,0,0,0, "volume", nil,nil,nil},
- [Qaudioctl] = {0,0,{Qaudioctl, 0,QTFILE},0666,0,0,0, "audioctl",nil,nil,nil},
- [Qaudiostat] = {0,0,{Qaudiostat,0,QTFILE},0666,0,0,0, "audiostat",nil,nil,nil},
- [Qaudio] = {0,0,{Qaudio, 0,QTFILE},0222,0,0,0, "audio", nil,nil,nil},
- [Qaudioin] = {0,0,{Qaudioin, 0,QTFILE},0444,0,0,0, "audioin", nil,nil,nil},
- };
- int messagesize = 4*1024+IOHDRSZ;
- uchar mdata[8*1024+IOHDRSZ];
- uchar mbuf[8*1024+IOHDRSZ];
- Fcall thdr;
- Fcall rhdr;
- Worker *workers;
- char srvfile[64], mntdir[64], epdata[64], audiofile[64];
- int mfd[2], p[2];
- char user[32];
- char *srvpost;
- Channel *procchan;
- Channel *replchan;
- Fid *fids;
- Fid* newfid(int);
- void io(void *);
- void usage(void);
- extern char *mntpt;
- char *rflush(Fid*), *rauth(Fid*),
- *rattach(Fid*), *rwalk(Fid*),
- *ropen(Fid*), *rcreate(Fid*),
- *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
- *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
- *rversion(Fid*);
- char *(*fcalls[])(Fid*) = {
- [Tflush] rflush,
- [Tversion] rversion,
- [Tauth] rauth,
- [Tattach] rattach,
- [Twalk] rwalk,
- [Topen] ropen,
- [Tcreate] rcreate,
- [Tread] rread,
- [Twrite] rwrite,
- [Tclunk] rclunk,
- [Tremove] rremove,
- [Tstat] rstat,
- [Twstat] rwstat,
- };
- char Eperm[] = "permission denied";
- char Enotdir[] = "not a directory";
- char Enoauth[] = "no authentication in ramfs";
- char Enotexist[] = "file does not exist";
- char Einuse[] = "file in use";
- char Eexist[] = "file exists";
- char Enotowner[] = "not owner";
- char Eisopen[] = "file already open for I/O";
- char Excl[] = "exclusive use file already open";
- char Ename[] = "illegal name";
- char Ebadctl[] = "unknown control message";
- int
- notifyf(void *, char *s)
- {
- if(strncmp(s, "interrupt", 9) == 0)
- return 1;
- return 0;
- }
- void
- post(char *name, char *envname, int srvfd)
- {
- int fd;
- char buf[32];
- fd = create(name, OWRITE, attachok?0666:0600);
- if(fd < 0)
- return;
- sprint(buf, "%d",srvfd);
- if(write(fd, buf, strlen(buf)) != strlen(buf))
- sysfatal("srv write");
- close(fd);
- putenv(envname, name);
- }
- void
- serve(void *)
- {
- int i;
- ulong t;
- if(pipe(p) < 0)
- sysfatal("pipe failed");
- mfd[0] = p[0];
- mfd[1] = p[0];
- atnotify(notifyf, 1);
- strcpy(user, getuser());
- t = time(nil);
- for (i = 0; i < Nqid; i++){
- dirs[i].uid = user;
- dirs[i].gid = user;
- dirs[i].muid = user;
- dirs[i].atime = t;
- dirs[i].mtime = t;
- }
- if(mntpt == nil){
- snprint(mntdir, sizeof(mntdir), "/dev");
- mntpt = mntdir;
- }
- if(debug)
- fmtinstall('F', fcallfmt);
- procrfork(io, nil, STACKSIZE, RFFDG|RFNAMEG);
- close(p[0]); /* don't deadlock if child fails */
- if(srvpost){
- sprint(srvfile, "/srv/%s", srvpost);
- remove(srvfile);
- post(srvfile, "usbaudio", p[1]);
- }
- if(mount(p[1], -1, mntpt, MBEFORE, "") < 0)
- sysfatal("mount failed");
- if (endpt[Play] >= 0){
- sprint(epdata, "#U/usb%d/%d/ep%ddata", ad->ctlrno, ad->id,
- endpt[Play]);
- sprint(audiofile, "%s/audio", mntpt);
- if(bind(epdata, audiofile, MREPL) < 0)
- sysfatal("bind failed");
- }
- if (endpt[Record] >= 0){
- sprint(epdata, "#U/usb%d/%d/ep%ddata", ad->ctlrno, ad->id,
- endpt[Record]);
- sprint(audiofile, "%s/audioin", mntpt);
- if(bind(epdata, audiofile, MREPL) < 0)
- sysfatal("bind failed");
- }
- threadexits(nil);
- }
- char*
- rversion(Fid*)
- {
- Fid *f;
- if(thdr.msize < 256)
- return "max messagesize too small";
- if(thdr.msize < messagesize)
- messagesize = thdr.msize;
- rhdr.msize = messagesize;
- if(strncmp(thdr.version, "9P2000", 6) != 0)
- return "unknown 9P version";
- else
- rhdr.version = "9P2000";
- for(f = fids; f; f = f->next)
- if(f->flags & Busy)
- rclunk(f);
- return nil;
- }
- char*
- rauth(Fid*)
- {
- return "usbaudio: no authentication required";
- }
- char*
- rflush(Fid *)
- {
- Worker *w;
- int waitflush;
- do {
- waitflush = 0;
- for (w = workers; w; w = w->next)
- if (w->tag == thdr.oldtag){
- waitflush++;
- nbsendul(w->eventc, thdr.oldtag << 16 | Flush);
- }
- if (waitflush)
- sleep(50);
- } while(waitflush);
- if (debug & Dbgproc)
- fprint(2, "flush done on tag %d\n", thdr.oldtag);
- return 0;
- }
- char*
- rattach(Fid *f)
- {
- f->flags |= Busy;
- f->dir = &dirs[Qdir];
- rhdr.qid = f->dir->qid;
- if(attachok == 0 && strcmp(thdr.uname, user) != 0)
- return Eperm;
- return 0;
- }
- static Fid*
- doclone(Fid *f, int nfid)
- {
- Fid *nf;
- nf = newfid(nfid);
- if(nf->flags & Busy)
- return nil;
- nf->flags |= Busy;
- nf->flags &= ~Open;
- nf->dir = f->dir;
- return nf;
- }
- char*
- dowalk(Fid *f, char *name)
- {
- int t;
- if (strcmp(name, ".") == 0)
- return nil;
- if (strcmp(name, "..") == 0){
- f->dir = &dirs[Qdir];
- return nil;
- }
- if(f->dir != &dirs[Qdir])
- return Enotexist;
- for (t = 1; t < Nqid; t++){
- if (t == Qaudio && endpt[Play] < 0)
- continue;
- if (t == Qaudioin && endpt[Record] < 0)
- continue;
- if(strcmp(name, dirs[t].name) == 0){
- f->dir = &dirs[t];
- return nil;
- }
- }
- return Enotexist;
- }
- char*
- rwalk(Fid *f)
- {
- Fid *nf;
- char *rv;
- int i;
- Dir *savedir;
- if(f->flags & Open)
- return Eisopen;
- rhdr.nwqid = 0;
- nf = nil;
- savedir = f->dir;
- /* clone if requested */
- if(thdr.newfid != thdr.fid){
- nf = doclone(f, thdr.newfid);
- if(nf == nil)
- return "new fid in use";
- f = nf;
- }
- /* if it's just a clone, return */
- if(thdr.nwname == 0 && nf != nil)
- return nil;
- /* walk each element */
- rv = nil;
- for(i = 0; i < thdr.nwname; i++){
- rv = dowalk(f, thdr.wname[i]);
- if(rv != nil){
- if(nf != nil)
- rclunk(nf);
- else
- f->dir = savedir;
- break;
- }
- rhdr.wqid[i] = f->dir->qid;
- }
- rhdr.nwqid = i;
- /* we only error out if no walk */
- if(i > 0)
- rv = nil;
- return rv;
- }
- Audioctldata *
- allocaudioctldata(void)
- {
- int i, j, k;
- Audioctldata *a;
- a = emallocz(sizeof(Audioctldata), 1);
- for (i = 0; i < 2; i++)
- for(j=0; j < Ncontrol; j++)
- for(k=0; k < 8; k++)
- a->values[i][j][k] = Undef;
- return a;
- }
- char *
- ropen(Fid *f)
- {
- if(f->flags & Open)
- return Eisopen;
- if(f->dir == &dirs[Qaudio] || f->dir == &dirs[Qaudioin])
- return Eperm;
- if(thdr.mode != OREAD && (f->dir->mode & 0x2) == 0)
- return Eperm;
- qlock(f);
- if(f->dir == &dirs[Qaudioctl] && f->fiddata == nil)
- f->fiddata = allocaudioctldata();
- qunlock(f);
- rhdr.iounit = 0;
- rhdr.qid = f->dir->qid;
- f->flags |= Open;
- return nil;
- }
- char *
- rcreate(Fid*)
- {
- return Eperm;
- }
- int
- readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
- {
- int i, m, n;
- long pos;
- n = 0;
- pos = 0;
- for (i = 1; i < Nqid; i++){
- if (endpt[Play] < 0 && i == Qaudio)
- continue;
- if (endpt[Record] < 0 && i == Qaudioin)
- continue;
- m = convD2M(&dirs[i], &buf[n], blen-n);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- break;
- n += m;
- cnt -= m;
- }
- pos += m;
- }
- return n;
- }
- enum { Chunk = 1024, };
- int
- makeaudioctldata(Fid *f)
- {
- int rec, ctl, i, diff;
- long *actls; /* 8 of them */
- char *p, *e;
- Audiocontrol *c;
- Audioctldata *a;
- if ((a = f->fiddata) == nil)
- sysfatal("fiddata");
- if ((p = a->s) == nil)
- a->s = p = emalloc(Chunk);
- e = p + Chunk - 1; /* e must point *at* last byte, not *after* */
- for (rec = 0; rec < 2; rec++)
- for (ctl = 0; ctl < Ncontrol; ctl++) {
- c = &controls[rec][ctl];
- actls = a->values[rec][ctl];
- diff = 0;
- if (c->chans){
- for (i = 1; i < 8; i++)
- if ((c->chans & 1<<i) &&
- c->value[i] != actls[i])
- diff = 1;
- }else
- if (c->value[0] != actls[0])
- diff = 1;
- if (diff){
- p = seprint(p, e, "%s %s %A", c->name,
- rec? "in": "out", c);
- memmove(actls, c->value, sizeof c->value);
- if (c->min != Undef){
- p = seprint(p, e, " %ld %ld", c->min,
- c->max);
- if (c->step != Undef)
- p = seprint(p, e, " %ld",
- c->step);
- }
- p = seprint(p, e, "\n");
- }
- }
- assert(strlen(a->s) < Chunk);
- a->ns = p - a->s;
- return a->ns;
- }
- void
- readproc(void *x)
- {
- int n, cnt;
- ulong event;
- vlong off;
- uchar *mdata;
- Audioctldata *a;
- Fcall *rhdr;
- Fid *f;
- Worker *w;
- w = x;
- mdata = emalloc(8*1024+IOHDRSZ);
- while(event = recvul(w->eventc)){
- if (event != Work)
- continue;
- f = w->fid;
- rhdr = w->rhdr;
- a = f->fiddata;
- off = rhdr->offset;
- cnt = rhdr->count;
- assert(a->offoff == off);
- /* f is already locked */
- for(;;){
- qunlock(f);
- event = recvul(w->eventc);
- qlock(f);
- if (debug & Dbgproc)
- fprint(2, "readproc unblocked fid %d %lld\n",
- f->fid, f->dir->qid.path);
- switch (event & 0xffff) {
- case Work:
- sysfatal("readproc phase error");
- case Check:
- if (f->fiddata && makeaudioctldata(f) == 0)
- continue;
- break;
- case Flush:
- if ((event >> 16) == rhdr->tag) {
- if (debug & Dbgproc)
- fprint(2, "readproc flushing fid %d, tag %d\n",
- f->fid, rhdr->tag);
- goto flush;
- }
- continue;
- }
- if (f->fiddata){
- rhdr->data = a->s;
- rhdr->count = a->ns;
- break;
- }
- yield();
- }
- if (rhdr->count > cnt)
- rhdr->count = cnt;
- if (rhdr->count)
- f->flags &= ~Eof;
- if(debug & (Dbgproc|Dbgfs))
- fprint(2, "readproc:->%F\n", rhdr);
- n = convS2M(rhdr, mdata, messagesize);
- if(write(mfd[1], mdata, n) != n)
- sysfatal("mount write");
- flush:
- w->tag = NOTAG;
- f->readers--;
- assert(f->readers == 0);
- free(rhdr);
- w->rhdr = nil;
- qunlock(f);
- sendp(procchan, w);
- }
- threadexits(nil);
- }
- char*
- rread(Fid *f)
- {
- int i, n, cnt, rec;
- vlong off;
- char *p;
- Audiocontrol *c;
- Audioctldata *a;
- Worker *w;
- static char buf[1024];
- rhdr.count = 0;
- off = thdr.offset;
- cnt = thdr.count;
- if(cnt > messagesize - IOHDRSZ)
- cnt = messagesize - IOHDRSZ;
- rhdr.data = (char*)mbuf;
- if(f->dir == &dirs[Qdir]){
- n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
- rhdr.count = n;
- return nil;
- }
- if(f->dir == &dirs[Qvolume]){
- p = buf;
- n = sizeof buf;
- for (rec = 0; rec < 2; rec++){
- c = &controls[rec][Volume_control];
- if (c->readable){
- i = snprint(p, n, "audio %s %ld\n",
- rec? "in": "out", (c->min != Undef?
- 100*(c->value[0]-c->min)/(c->max-c->min):
- c->value[0]));
- p += i;
- n -= i;
- }
- c = &controls[rec][Treble_control];
- if (c->readable){
- i = snprint(p, n, "treb %s %ld\n",
- rec? "in": "out", (c->min != Undef?
- 100*(c->value[0]-c->min)/(c->max-c->min):
- c->value[0]));
- p += i;
- n -= i;
- }
- c = &controls[rec][Bass_control];
- if (c->readable){
- i = snprint(p, n, "bass %s %ld\n",
- rec? "in": "out", (c->min != Undef?
- 100*(c->value[0]-c->min)/(c->max-c->min):
- c->value[0]));
- p += i;
- n -= i;
- }
- c = &controls[rec][Speed_control];
- if (c->readable){
- i = snprint(p, n, "speed %s %ld\n",
- rec? "in": "out", c->value[0]);
- p += i;
- n -= i;
- }
- }
- n = sizeof buf - n;
- if (off > n)
- rhdr.count = 0;
- else{
- rhdr.data = buf + off;
- rhdr.count = n - off;
- if (rhdr.count > cnt)
- rhdr.count = cnt;
- }
- return nil;
- }
- if(f->dir == &dirs[Qaudioctl]){
- Fcall *hdr;
- qlock(f);
- a = f->fiddata;
- if (off - a->offoff < 0){
- /* there was a seek */
- a->offoff = off;
- a->ns = 0;
- }
- do {
- if (off - a->offoff < a->ns){
- rhdr.data = a->s + (off - a->offoff);
- rhdr.count = a->ns - (off - a->offoff);
- if (rhdr.count > cnt)
- rhdr.count = cnt;
- qunlock(f);
- return nil;
- }
- if (a->offoff != off){
- a->ns = 0;
- a->offoff = off;
- rhdr.count = 0;
- qunlock(f);
- return nil;
- }
- } while (makeaudioctldata(f) != 0);
- assert(a->offoff == off);
- /* Wait for data off line */
- f->readers++;
- w = nbrecvp(procchan);
- if (w == nil){
- w = emallocz(sizeof(Worker), 1);
- w->eventc = chancreate(sizeof(ulong), 1);
- w->next = workers;
- workers = w;
- proccreate(readproc, w, 4096);
- }
- hdr = emalloc(sizeof(Fcall));
- w->fid = f;
- w->tag = thdr.tag;
- assert(w->rhdr == nil);
- w->rhdr = hdr;
- hdr->count = cnt;
- hdr->offset = off;
- hdr->type = thdr.type+1;
- hdr->fid = thdr.fid;
- hdr->tag = thdr.tag;
- sendul(w->eventc, Work);
- return (char*)~0;
- }
- return Eperm;
- }
- char*
- rwrite(Fid *f)
- {
- long cnt, value;
- char *lines[2*Ncontrol], *fields[4], *subfields[9], *err, *p;
- int nlines, i, nf, nnf, rec, ctl;
- Audiocontrol *c;
- Worker *w;
- static char buf[256];
- rhdr.count = 0;
- cnt = thdr.count;
- if(cnt > messagesize - IOHDRSZ)
- cnt = messagesize - IOHDRSZ;
- err = nil;
- if(f->dir == &dirs[Qvolume] || f->dir == &dirs[Qaudioctl]){
- thdr.data[cnt] = '\0';
- nlines = getfields(thdr.data, lines, 2*Ncontrol, 1, "\n");
- for(i = 0; i < nlines; i++){
- if (debug)
- fprint(2, "line: %s\n", lines[i]);
- nf = tokenize(lines[i], fields, 4);
- if (nf == 0)
- continue;
- if (nf == 3)
- if (strcmp(fields[1], "in") == 0 ||
- strcmp(fields[1], "record") == 0)
- rec = 1;
- else if (strcmp(fields[1], "out") == 0 ||
- strcmp(fields[1], "playback") == 0)
- rec = 0;
- else {
- if (debug)
- fprint(2, "bad1\n");
- return Ebadctl;
- }
- else if (nf == 2)
- rec = 0;
- else {
- if (debug)
- fprint(2, "bad2 %d\n", nf);
- return Ebadctl;
- }
- c = nil;
- if (strcmp(fields[0], "audio") == 0) /* special case */
- fields[0] = "volume";
- for (ctl = 0; ctl < Ncontrol; ctl++){
- c = &controls[rec][ctl];
- if (strcmp(fields[0], c->name) == 0)
- break;
- }
- if (ctl == Ncontrol){
- if (debug)
- fprint(2, "bad3\n");
- return Ebadctl;
- }
- if (f->dir == &dirs[Qvolume] && ctl != Speed_control &&
- c->min != Undef && c->max != Undef){
- nnf = tokenize(fields[nf-1], subfields,
- nelem(subfields));
- if (nnf <= 0 || nnf > 8){
- if (debug)
- fprint(2, "bad4\n");
- return Ebadctl;
- }
- p = buf;
- for (i = 0; i < nnf; i++){
- value = strtol(subfields[i], nil, 0);
- value = ((100 - value)*c->min +
- value*c->max) / 100;
- if (debug)
- if (p == buf)
- fprint(2, "rwrite: %s %s '%ld",
- c->name, rec?
- "record":
- "playback",
- value);
- else
- fprint(2, " %ld", value);
- if (p == buf)
- p = seprint(p, buf+sizeof buf,
- "0x%p %s %s '%ld",
- replchan, c->name, rec?
- "record": "playback",
- value);
- else
- p = seprint(p, buf+sizeof buf,
- " %ld", value);
- }
- if (debug)
- fprint(2, "'\n");
- seprint(p, buf+sizeof buf-1, "'");
- chanprint(controlchan, buf);
- } else {
- if (debug)
- fprint(2, "rwrite: %s %s %q", c->name,
- rec? "record": "playback",
- fields[nf-1]);
- chanprint(controlchan, "0x%p %s %s %q",
- replchan, c->name, rec? "record":
- "playback", fields[nf-1]);
- }
- p = recvp(replchan);
- if (p){
- if (strcmp(p, "ok") == 0){
- free(p);
- p = nil;
- }
- if (err == nil)
- err = p;
- }
- }
- for (w = workers; w; w = w->next)
- nbsendul(w->eventc, Qaudioctl << 16 | Check);
- rhdr.count = thdr.count;
- return err;
- }
- return Eperm;
- }
- char *
- rclunk(Fid *f)
- {
- Audioctldata *a;
- qlock(f);
- f->flags &= ~(Open|Busy);
- assert(f->readers ==0);
- if (f->fiddata){
- a = f->fiddata;
- if (a->s)
- free(a->s);
- free(a);
- f->fiddata = nil;
- }
- qunlock(f);
- return 0;
- }
- char *
- rremove(Fid *)
- {
- return Eperm;
- }
- char *
- rstat(Fid *f)
- {
- Audioctldata *a;
- if (f->dir == &dirs[Qaudio] && endpt[Play] < 0)
- return Enotexist;
- if (f->dir == &dirs[Qaudioin] && endpt[Record] < 0)
- return Enotexist;
- if (f->dir == &dirs[Qaudioctl]){
- qlock(f);
- if (f->fiddata == nil)
- f->fiddata = allocaudioctldata();
- a = f->fiddata;
- if (a->ns == 0)
- makeaudioctldata(f);
- f->dir->length = a->offoff + a->ns;
- qunlock(f);
- }
- rhdr.nstat = convD2M(f->dir, mbuf, messagesize - IOHDRSZ);
- rhdr.stat = mbuf;
- return 0;
- }
- char *
- rwstat(Fid*)
- {
- return Eperm;
- }
- Fid *
- newfid(int fid)
- {
- Fid *f, *ff;
- ff = nil;
- for(f = fids; f; f = f->next)
- if(f->fid == fid)
- return f;
- else if(ff == nil && (f->flags & Busy) == 0)
- ff = f;
- if(ff == nil){
- ff = emallocz(sizeof *ff, 1);
- ff->next = fids;
- fids = ff;
- }
- ff->fid = fid;
- ff->flags &= ~(Busy|Open);
- ff->dir = nil;
- return ff;
- }
- void
- io(void *)
- {
- char *err, e[32];
- int n;
- close(p[1]);
- procchan = chancreate(sizeof(Channel*), 8);
- replchan = chancreate(sizeof(char*), 0);
- for(;;){
- /*
- * reading from a pipe or a network device
- * will give an error after a few eof reads
- * however, we cannot tell the difference
- * between a zero-length read and an interrupt
- * on the processes writing to us,
- * so we wait for the error
- */
- n = read9pmsg(mfd[0], mdata, messagesize);
- if(n == 0)
- continue;
- if(n < 0){
- rerrstr(e, sizeof e);
- if (strcmp(e, "interrupted") == 0){
- if (debug)
- fprint(2, "read9pmsg interrupted\n");
- continue;
- }
- return;
- }
- if(convM2S(mdata, n, &thdr) == 0)
- continue;
- if(debug & Dbgfs)
- fprint(2, "io:<-%F\n", &thdr);
- rhdr.data = (char*)mdata + messagesize;
- if(!fcalls[thdr.type])
- err = "bad fcall type";
- else
- err = (*fcalls[thdr.type])(newfid(thdr.fid));
- if (err == (char*)~0)
- continue; /* handled off line */
- if(err){
- rhdr.type = Rerror;
- rhdr.ename = err;
- }else{
- rhdr.type = thdr.type + 1;
- rhdr.fid = thdr.fid;
- }
- rhdr.tag = thdr.tag;
- if(debug & Dbgfs)
- fprint(2, "io:->%F\n", &rhdr);
- n = convS2M(&rhdr, mdata, messagesize);
- if(write(mfd[1], mdata, n) != n)
- sysfatal("mount write");
- }
- }
- int
- newid(void)
- {
- int rv;
- static int id;
- static Lock idlock;
- lock(&idlock);
- rv = ++id;
- unlock(&idlock);
- return rv;
- }
- void
- ctlevent(void)
- {
- Worker *w;
- for (w = workers; w; w = w->next)
- nbsendul(w->eventc, Qaudioctl << 16 | Check);
- }
|