📄 audiofs.c
字号:
#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*1024enum{ 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";intnotifyf(void *, char *s){ if(strncmp(s, "interrupt", 9) == 0) return 1; return 0;}voidpost(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);}voidserve(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;}intreadtopdir(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;}intmakeaudioctldata(Fid *f){ int rec, ctl, i, different; char *p, *e; Audiocontrol *c; Audioctldata *a; if ((a = f->fiddata) == nil) sysfatal("fiddata"); if ((p = a->s) == nil){ p = emalloc(1024); a->s = p; } e = p + 1024; for (rec = 0; rec < 2; rec++) for (ctl = 0; ctl < Ncontrol; ctl++) { c = &controls[rec][ctl]; different = 0; if (c->chans){ for (i = 1; i < 8; i++) if ((c->chans & 1<<i) && c->value[i] != a->values[rec][ctl][i]) different = 1; }else if (c->value[0] != a->values[rec][ctl][0]) different = 1; if (different){ p = seprint(p, e, "%s %s %A", c->name, rec?"in":"out", c); memmove(a->values[rec][ctl], c->value, sizeof c->value); if (c->min != Undef){ p = seprint(p, e, " %ld %ld", c->min, c->max); if (c->step != Undef)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -