17f0337cdSDavid du Colombier #include <u.h>
27f0337cdSDavid du Colombier #include <libc.h>
37f0337cdSDavid du Colombier #include <thread.h>
47f0337cdSDavid du Colombier #include <auth.h>
57f0337cdSDavid du Colombier #include <fcall.h>
67f0337cdSDavid du Colombier #include <libsec.h>
77f0337cdSDavid du Colombier #include "usb.h"
8906943f9SDavid du Colombier #include "audio.h"
9906943f9SDavid du Colombier #include "audioctl.h"
107f0337cdSDavid du Colombier
115ab4dd4cSDavid du Colombier int attachok;
125ab4dd4cSDavid du Colombier
137f0337cdSDavid du Colombier #define STACKSIZE 16*1024
147f0337cdSDavid du Colombier
157f0337cdSDavid du Colombier enum
167f0337cdSDavid du Colombier {
172ddf2468SDavid du Colombier OPERM = 0x3, /* mask of all permission types in open mode */
187f0337cdSDavid du Colombier };
197f0337cdSDavid du Colombier
207f0337cdSDavid du Colombier typedef struct Fid Fid;
217f0337cdSDavid du Colombier typedef struct Audioctldata Audioctldata;
227f0337cdSDavid du Colombier typedef struct Worker Worker;
237f0337cdSDavid du Colombier
247f0337cdSDavid du Colombier struct Audioctldata
257f0337cdSDavid du Colombier {
262ddf2468SDavid du Colombier long offoff; /* offset of the offset for audioctl */
272ddf2468SDavid du Colombier long values[2][Ncontrol][8]; /* last values transmitted */
287f0337cdSDavid du Colombier char *s;
297f0337cdSDavid du Colombier int ns;
307f0337cdSDavid du Colombier };
317f0337cdSDavid du Colombier
327f0337cdSDavid du Colombier enum {
337f0337cdSDavid du Colombier Busy = 0x01,
347f0337cdSDavid du Colombier Open = 0x02,
357f0337cdSDavid du Colombier Eof = 0x04,
367f0337cdSDavid du Colombier };
377f0337cdSDavid du Colombier
387f0337cdSDavid du Colombier struct Fid
397f0337cdSDavid du Colombier {
407f0337cdSDavid du Colombier QLock;
417f0337cdSDavid du Colombier int fid;
427f0337cdSDavid du Colombier Dir *dir;
437f0337cdSDavid du Colombier ushort flags;
447f0337cdSDavid du Colombier short readers;
452ddf2468SDavid du Colombier void *fiddata; /* file specific per-fid data (used for audioctl) */
467f0337cdSDavid du Colombier Fid *next;
477f0337cdSDavid du Colombier };
487f0337cdSDavid du Colombier
497f0337cdSDavid du Colombier struct Worker
507f0337cdSDavid du Colombier {
517f0337cdSDavid du Colombier Fid *fid;
527f0337cdSDavid du Colombier ushort tag;
537f0337cdSDavid du Colombier Fcall *rhdr;
547f0337cdSDavid du Colombier Dir *dir;
557f0337cdSDavid du Colombier Channel *eventc;
567f0337cdSDavid du Colombier Worker *next;
577f0337cdSDavid du Colombier };
587f0337cdSDavid du Colombier
597f0337cdSDavid du Colombier enum {
602ddf2468SDavid du Colombier /* Event channel messages for worker */
617f0337cdSDavid du Colombier Work = 0x01,
627f0337cdSDavid du Colombier Check = 0x02,
637f0337cdSDavid du Colombier Flush = 0x03,
647f0337cdSDavid du Colombier };
657f0337cdSDavid du Colombier
667f0337cdSDavid du Colombier enum {
677f0337cdSDavid du Colombier Qdir,
687f0337cdSDavid du Colombier Qvolume,
697f0337cdSDavid du Colombier Qaudioctl,
707f0337cdSDavid du Colombier Qaudiostat,
717f0337cdSDavid du Colombier Nqid,
727f0337cdSDavid du Colombier };
737f0337cdSDavid du Colombier
747f0337cdSDavid du Colombier Dir dirs[] = {
757f0337cdSDavid du Colombier [Qdir] = {0,0,{Qdir, 0,QTDIR},0555|DMDIR,0,0,0, ".", nil,nil,nil},
767f0337cdSDavid du Colombier [Qvolume] = {0,0,{Qvolume, 0,QTFILE},0666,0,0,0, "volume", nil,nil,nil},
777f0337cdSDavid du Colombier [Qaudioctl] = {0,0,{Qaudioctl, 0,QTFILE},0666,0,0,0, "audioctl",nil,nil,nil},
787f0337cdSDavid du Colombier [Qaudiostat] = {0,0,{Qaudiostat,0,QTFILE},0666,0,0,0, "audiostat",nil,nil,nil},
797f0337cdSDavid du Colombier };
807f0337cdSDavid du Colombier
817f0337cdSDavid du Colombier int messagesize = 4*1024+IOHDRSZ;
827f0337cdSDavid du Colombier uchar mdata[8*1024+IOHDRSZ];
837f0337cdSDavid du Colombier uchar mbuf[8*1024+IOHDRSZ];
847f0337cdSDavid du Colombier
857f0337cdSDavid du Colombier Fcall thdr;
867f0337cdSDavid du Colombier Fcall rhdr;
877f0337cdSDavid du Colombier Worker *workers;
887f0337cdSDavid du Colombier
897f0337cdSDavid du Colombier char srvfile[64], mntdir[64], epdata[64], audiofile[64];
907f0337cdSDavid du Colombier int mfd[2], p[2];
917f0337cdSDavid du Colombier char user[32];
927f0337cdSDavid du Colombier char *srvpost;
937f0337cdSDavid du Colombier
947f0337cdSDavid du Colombier Channel *procchan;
957f0337cdSDavid du Colombier Channel *replchan;
967f0337cdSDavid du Colombier
977f0337cdSDavid du Colombier Fid *fids;
987f0337cdSDavid du Colombier
997f0337cdSDavid du Colombier Fid* newfid(int);
1007f0337cdSDavid du Colombier void io(void *);
1017f0337cdSDavid du Colombier void usage(void);
1027f0337cdSDavid du Colombier
1037f0337cdSDavid du Colombier extern char *mntpt;
1047f0337cdSDavid du Colombier
1057f0337cdSDavid du Colombier char *rflush(Fid*), *rauth(Fid*),
1067f0337cdSDavid du Colombier *rattach(Fid*), *rwalk(Fid*),
1077f0337cdSDavid du Colombier *ropen(Fid*), *rcreate(Fid*),
1087f0337cdSDavid du Colombier *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
1097f0337cdSDavid du Colombier *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
1107f0337cdSDavid du Colombier *rversion(Fid*);
1117f0337cdSDavid du Colombier
1127f0337cdSDavid du Colombier char *(*fcalls[])(Fid*) = {
1137f0337cdSDavid du Colombier [Tflush] rflush,
1147f0337cdSDavid du Colombier [Tversion] rversion,
1157f0337cdSDavid du Colombier [Tauth] rauth,
1167f0337cdSDavid du Colombier [Tattach] rattach,
1177f0337cdSDavid du Colombier [Twalk] rwalk,
1187f0337cdSDavid du Colombier [Topen] ropen,
1197f0337cdSDavid du Colombier [Tcreate] rcreate,
1207f0337cdSDavid du Colombier [Tread] rread,
1217f0337cdSDavid du Colombier [Twrite] rwrite,
1227f0337cdSDavid du Colombier [Tclunk] rclunk,
1237f0337cdSDavid du Colombier [Tremove] rremove,
1247f0337cdSDavid du Colombier [Tstat] rstat,
1257f0337cdSDavid du Colombier [Twstat] rwstat,
1267f0337cdSDavid du Colombier };
1277f0337cdSDavid du Colombier
1287f0337cdSDavid du Colombier char Eperm[] = "permission denied";
1297f0337cdSDavid du Colombier char Enotdir[] = "not a directory";
1307f0337cdSDavid du Colombier char Enoauth[] = "no authentication in ramfs";
1317f0337cdSDavid du Colombier char Enotexist[] = "file does not exist";
1327f0337cdSDavid du Colombier char Einuse[] = "file in use";
1337f0337cdSDavid du Colombier char Eexist[] = "file exists";
1347f0337cdSDavid du Colombier char Enotowner[] = "not owner";
1357f0337cdSDavid du Colombier char Eisopen[] = "file already open for I/O";
1367f0337cdSDavid du Colombier char Excl[] = "exclusive use file already open";
1377f0337cdSDavid du Colombier char Ename[] = "illegal name";
1387f0337cdSDavid du Colombier char Ebadctl[] = "unknown control message";
1397f0337cdSDavid du Colombier
1407f0337cdSDavid du Colombier int
notifyf(void *,char * s)1417f0337cdSDavid du Colombier notifyf(void *, char *s)
1427f0337cdSDavid du Colombier {
1437f0337cdSDavid du Colombier if(strncmp(s, "interrupt", 9) == 0)
1447f0337cdSDavid du Colombier return 1;
1457f0337cdSDavid du Colombier return 0;
1467f0337cdSDavid du Colombier }
1477f0337cdSDavid du Colombier
1487f0337cdSDavid du Colombier void
post(char * name,char * envname,int srvfd)1497f0337cdSDavid du Colombier post(char *name, char *envname, int srvfd)
1507f0337cdSDavid du Colombier {
1517f0337cdSDavid du Colombier int fd;
1527f0337cdSDavid du Colombier char buf[32];
1537f0337cdSDavid du Colombier
1545ab4dd4cSDavid du Colombier fd = create(name, OWRITE, attachok?0666:0600);
1557f0337cdSDavid du Colombier if(fd < 0)
1567f0337cdSDavid du Colombier return;
157*e9b54818SDavid du Colombier snprint(buf, sizeof buf, "%d", srvfd);
1587f0337cdSDavid du Colombier if(write(fd, buf, strlen(buf)) != strlen(buf))
1597f0337cdSDavid du Colombier sysfatal("srv write");
1607f0337cdSDavid du Colombier close(fd);
1617f0337cdSDavid du Colombier putenv(envname, name);
1627f0337cdSDavid du Colombier }
1637f0337cdSDavid du Colombier
164906943f9SDavid du Colombier /*
165906943f9SDavid du Colombier * BUG: If audio is later used on a different name space, the
166906943f9SDavid du Colombier * audio/audioin files are not there because of the bind trick.
167906943f9SDavid du Colombier * We should actually implement those files despite the binds.
168906943f9SDavid du Colombier * If audio is used from within the same ns nothing would change,
169906943f9SDavid du Colombier * otherwise, whoever would mount the audio files could still
170906943f9SDavid du Colombier * play/record audio (unlike now).
171906943f9SDavid du Colombier */
1727f0337cdSDavid du Colombier void
serve(void *)1737f0337cdSDavid du Colombier serve(void *)
1747f0337cdSDavid du Colombier {
1757f0337cdSDavid du Colombier int i;
1767f0337cdSDavid du Colombier ulong t;
1777f0337cdSDavid du Colombier
1787f0337cdSDavid du Colombier if(pipe(p) < 0)
1797f0337cdSDavid du Colombier sysfatal("pipe failed");
1807f0337cdSDavid du Colombier mfd[0] = p[0];
1817f0337cdSDavid du Colombier mfd[1] = p[0];
1827f0337cdSDavid du Colombier
1837f0337cdSDavid du Colombier atnotify(notifyf, 1);
1847f0337cdSDavid du Colombier strcpy(user, getuser());
1857f0337cdSDavid du Colombier t = time(nil);
1867f0337cdSDavid du Colombier for(i = 0; i < Nqid; i++){
1877f0337cdSDavid du Colombier dirs[i].uid = user;
1887f0337cdSDavid du Colombier dirs[i].gid = user;
1897f0337cdSDavid du Colombier dirs[i].muid = user;
1907f0337cdSDavid du Colombier dirs[i].atime = t;
1917f0337cdSDavid du Colombier dirs[i].mtime = t;
1927f0337cdSDavid du Colombier }
1937f0337cdSDavid du Colombier if(mntpt == nil){
1947f0337cdSDavid du Colombier snprint(mntdir, sizeof(mntdir), "/dev");
1957f0337cdSDavid du Colombier mntpt = mntdir;
1967f0337cdSDavid du Colombier }
1977f0337cdSDavid du Colombier
198906943f9SDavid du Colombier if(usbdebug)
1997f0337cdSDavid du Colombier fmtinstall('F', fcallfmt);
2007f0337cdSDavid du Colombier
2017f0337cdSDavid du Colombier procrfork(io, nil, STACKSIZE, RFFDG|RFNAMEG);
2027f0337cdSDavid du Colombier
2037f0337cdSDavid du Colombier close(p[0]); /* don't deadlock if child fails */
2047f0337cdSDavid du Colombier if(srvpost){
205*e9b54818SDavid du Colombier snprint(srvfile, sizeof srvfile, "/srv/%s", srvpost);
2067f0337cdSDavid du Colombier remove(srvfile);
2077f0337cdSDavid du Colombier post(srvfile, "usbaudio", p[1]);
2087f0337cdSDavid du Colombier }
2097f0337cdSDavid du Colombier if(mount(p[1], -1, mntpt, MBEFORE, "") < 0)
2107f0337cdSDavid du Colombier sysfatal("mount failed");
211906943f9SDavid du Colombier if(endpt[Play] >= 0 && devctl(epdev[Play], "name audio") < 0)
212906943f9SDavid du Colombier fprint(2, "audio: name audio: %r\n");
213906943f9SDavid du Colombier if(endpt[Record] >= 0 && devctl(epdev[Record], "name audioin") < 0)
214906943f9SDavid du Colombier fprint(2, "audio: name audioin: %r\n");
2157f0337cdSDavid du Colombier threadexits(nil);
2167f0337cdSDavid du Colombier }
2177f0337cdSDavid du Colombier
2187f0337cdSDavid du Colombier char*
rversion(Fid *)2197f0337cdSDavid du Colombier rversion(Fid*)
2207f0337cdSDavid du Colombier {
2217f0337cdSDavid du Colombier Fid *f;
2227f0337cdSDavid du Colombier
2237f0337cdSDavid du Colombier if(thdr.msize < 256)
2247f0337cdSDavid du Colombier return "max messagesize too small";
2257f0337cdSDavid du Colombier if(thdr.msize < messagesize)
2267f0337cdSDavid du Colombier messagesize = thdr.msize;
2277f0337cdSDavid du Colombier rhdr.msize = messagesize;
2287f0337cdSDavid du Colombier if(strncmp(thdr.version, "9P2000", 6) != 0)
2297f0337cdSDavid du Colombier return "unknown 9P version";
2307f0337cdSDavid du Colombier else
2317f0337cdSDavid du Colombier rhdr.version = "9P2000";
2327f0337cdSDavid du Colombier for(f = fids; f; f = f->next)
2337f0337cdSDavid du Colombier if(f->flags & Busy)
2347f0337cdSDavid du Colombier rclunk(f);
2357f0337cdSDavid du Colombier return nil;
2367f0337cdSDavid du Colombier }
2377f0337cdSDavid du Colombier
2387f0337cdSDavid du Colombier char*
rauth(Fid *)2397f0337cdSDavid du Colombier rauth(Fid*)
2407f0337cdSDavid du Colombier {
2417f0337cdSDavid du Colombier return "usbaudio: no authentication required";
2427f0337cdSDavid du Colombier }
2437f0337cdSDavid du Colombier
2447f0337cdSDavid du Colombier char*
rflush(Fid *)2457f0337cdSDavid du Colombier rflush(Fid *)
2467f0337cdSDavid du Colombier {
2477f0337cdSDavid du Colombier Worker *w;
2487f0337cdSDavid du Colombier int waitflush;
2497f0337cdSDavid du Colombier
2507f0337cdSDavid du Colombier do {
2517f0337cdSDavid du Colombier waitflush = 0;
2527f0337cdSDavid du Colombier for(w = workers; w; w = w->next)
2537f0337cdSDavid du Colombier if(w->tag == thdr.oldtag){
2547f0337cdSDavid du Colombier waitflush++;
2557f0337cdSDavid du Colombier nbsendul(w->eventc, thdr.oldtag << 16 | Flush);
2567f0337cdSDavid du Colombier }
2577f0337cdSDavid du Colombier if(waitflush)
2587f0337cdSDavid du Colombier sleep(50);
2597f0337cdSDavid du Colombier } while(waitflush);
260906943f9SDavid du Colombier dprint(2, "flush done on tag %d\n", thdr.oldtag);
2617f0337cdSDavid du Colombier return 0;
2627f0337cdSDavid du Colombier }
2637f0337cdSDavid du Colombier
2647f0337cdSDavid du Colombier char*
rattach(Fid * f)2657f0337cdSDavid du Colombier rattach(Fid *f)
2667f0337cdSDavid du Colombier {
2677f0337cdSDavid du Colombier f->flags |= Busy;
2687f0337cdSDavid du Colombier f->dir = &dirs[Qdir];
2697f0337cdSDavid du Colombier rhdr.qid = f->dir->qid;
2705ab4dd4cSDavid du Colombier if(attachok == 0 && strcmp(thdr.uname, user) != 0)
2717f0337cdSDavid du Colombier return Eperm;
2727f0337cdSDavid du Colombier return 0;
2737f0337cdSDavid du Colombier }
2747f0337cdSDavid du Colombier
2757f0337cdSDavid du Colombier static Fid*
doclone(Fid * f,int nfid)2767f0337cdSDavid du Colombier doclone(Fid *f, int nfid)
2777f0337cdSDavid du Colombier {
2787f0337cdSDavid du Colombier Fid *nf;
2797f0337cdSDavid du Colombier
2807f0337cdSDavid du Colombier nf = newfid(nfid);
2817f0337cdSDavid du Colombier if(nf->flags & Busy)
2827f0337cdSDavid du Colombier return nil;
2837f0337cdSDavid du Colombier nf->flags |= Busy;
2847f0337cdSDavid du Colombier nf->flags &= ~Open;
2857f0337cdSDavid du Colombier nf->dir = f->dir;
2867f0337cdSDavid du Colombier return nf;
2877f0337cdSDavid du Colombier }
2887f0337cdSDavid du Colombier
2897f0337cdSDavid du Colombier char*
dowalk(Fid * f,char * name)2907f0337cdSDavid du Colombier dowalk(Fid *f, char *name)
2917f0337cdSDavid du Colombier {
2927f0337cdSDavid du Colombier int t;
2937f0337cdSDavid du Colombier
2947f0337cdSDavid du Colombier if(strcmp(name, ".") == 0)
2957f0337cdSDavid du Colombier return nil;
2967f0337cdSDavid du Colombier if(strcmp(name, "..") == 0){
2977f0337cdSDavid du Colombier f->dir = &dirs[Qdir];
2987f0337cdSDavid du Colombier return nil;
2997f0337cdSDavid du Colombier }
3007f0337cdSDavid du Colombier if(f->dir != &dirs[Qdir])
3017f0337cdSDavid du Colombier return Enotexist;
3027f0337cdSDavid du Colombier for(t = 1; t < Nqid; t++){
3037f0337cdSDavid du Colombier if(strcmp(name, dirs[t].name) == 0){
3047f0337cdSDavid du Colombier f->dir = &dirs[t];
3057f0337cdSDavid du Colombier return nil;
3067f0337cdSDavid du Colombier }
3077f0337cdSDavid du Colombier }
3087f0337cdSDavid du Colombier return Enotexist;
3097f0337cdSDavid du Colombier }
3107f0337cdSDavid du Colombier
3117f0337cdSDavid du Colombier char*
rwalk(Fid * f)3127f0337cdSDavid du Colombier rwalk(Fid *f)
3137f0337cdSDavid du Colombier {
3147f0337cdSDavid du Colombier Fid *nf;
3157f0337cdSDavid du Colombier char *rv;
3167f0337cdSDavid du Colombier int i;
3177f0337cdSDavid du Colombier Dir *savedir;
3187f0337cdSDavid du Colombier
3197f0337cdSDavid du Colombier if(f->flags & Open)
3207f0337cdSDavid du Colombier return Eisopen;
3217f0337cdSDavid du Colombier
3227f0337cdSDavid du Colombier rhdr.nwqid = 0;
3237f0337cdSDavid du Colombier nf = nil;
3247f0337cdSDavid du Colombier savedir = f->dir;
3257f0337cdSDavid du Colombier /* clone if requested */
3267f0337cdSDavid du Colombier if(thdr.newfid != thdr.fid){
3277f0337cdSDavid du Colombier nf = doclone(f, thdr.newfid);
3287f0337cdSDavid du Colombier if(nf == nil)
3297f0337cdSDavid du Colombier return "new fid in use";
3307f0337cdSDavid du Colombier f = nf;
3317f0337cdSDavid du Colombier }
3327f0337cdSDavid du Colombier
3337f0337cdSDavid du Colombier /* if it's just a clone, return */
3347f0337cdSDavid du Colombier if(thdr.nwname == 0 && nf != nil)
3357f0337cdSDavid du Colombier return nil;
3367f0337cdSDavid du Colombier
3377f0337cdSDavid du Colombier /* walk each element */
3387f0337cdSDavid du Colombier rv = nil;
3397f0337cdSDavid du Colombier for(i = 0; i < thdr.nwname; i++){
3407f0337cdSDavid du Colombier rv = dowalk(f, thdr.wname[i]);
3417f0337cdSDavid du Colombier if(rv != nil){
3427f0337cdSDavid du Colombier if(nf != nil)
3437f0337cdSDavid du Colombier rclunk(nf);
3447f0337cdSDavid du Colombier else
3457f0337cdSDavid du Colombier f->dir = savedir;
3467f0337cdSDavid du Colombier break;
3477f0337cdSDavid du Colombier }
3487f0337cdSDavid du Colombier rhdr.wqid[i] = f->dir->qid;
3497f0337cdSDavid du Colombier }
3507f0337cdSDavid du Colombier rhdr.nwqid = i;
3517f0337cdSDavid du Colombier
3527f0337cdSDavid du Colombier /* we only error out if no walk */
3537f0337cdSDavid du Colombier if(i > 0)
3547f0337cdSDavid du Colombier rv = nil;
3557f0337cdSDavid du Colombier
3567f0337cdSDavid du Colombier return rv;
3577f0337cdSDavid du Colombier }
3587f0337cdSDavid du Colombier
3597f0337cdSDavid du Colombier Audioctldata *
allocaudioctldata(void)3607f0337cdSDavid du Colombier allocaudioctldata(void)
3617f0337cdSDavid du Colombier {
3627f0337cdSDavid du Colombier int i, j, k;
3637f0337cdSDavid du Colombier Audioctldata *a;
3647f0337cdSDavid du Colombier
3657f0337cdSDavid du Colombier a = emallocz(sizeof(Audioctldata), 1);
3667f0337cdSDavid du Colombier for(i = 0; i < 2; i++)
3677f0337cdSDavid du Colombier for(j=0; j < Ncontrol; j++)
368ce31847cSDavid du Colombier for(k=0; k < 8; k++)
3697f0337cdSDavid du Colombier a->values[i][j][k] = Undef;
3707f0337cdSDavid du Colombier return a;
3717f0337cdSDavid du Colombier }
3727f0337cdSDavid du Colombier
3737f0337cdSDavid du Colombier char *
ropen(Fid * f)3747f0337cdSDavid du Colombier ropen(Fid *f)
3757f0337cdSDavid du Colombier {
3767f0337cdSDavid du Colombier if(f->flags & Open)
3777f0337cdSDavid du Colombier return Eisopen;
3787f0337cdSDavid du Colombier
3795ab4dd4cSDavid du Colombier if(thdr.mode != OREAD && (f->dir->mode & 0x2) == 0)
3807f0337cdSDavid du Colombier return Eperm;
3817f0337cdSDavid du Colombier qlock(f);
3827f0337cdSDavid du Colombier if(f->dir == &dirs[Qaudioctl] && f->fiddata == nil)
3837f0337cdSDavid du Colombier f->fiddata = allocaudioctldata();
3847f0337cdSDavid du Colombier qunlock(f);
3857f0337cdSDavid du Colombier rhdr.iounit = 0;
3867f0337cdSDavid du Colombier rhdr.qid = f->dir->qid;
3877f0337cdSDavid du Colombier f->flags |= Open;
3887f0337cdSDavid du Colombier return nil;
3897f0337cdSDavid du Colombier }
3907f0337cdSDavid du Colombier
3917f0337cdSDavid du Colombier char *
rcreate(Fid *)3927f0337cdSDavid du Colombier rcreate(Fid*)
3937f0337cdSDavid du Colombier {
3947f0337cdSDavid du Colombier return Eperm;
3957f0337cdSDavid du Colombier }
3967f0337cdSDavid du Colombier
3977f0337cdSDavid du Colombier int
readtopdir(Fid *,uchar * buf,long off,int cnt,int blen)3987f0337cdSDavid du Colombier readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
3997f0337cdSDavid du Colombier {
4007f0337cdSDavid du Colombier int i, m, n;
4017f0337cdSDavid du Colombier long pos;
4027f0337cdSDavid du Colombier
4037f0337cdSDavid du Colombier n = 0;
4047f0337cdSDavid du Colombier pos = 0;
4057f0337cdSDavid du Colombier for(i = 1; i < Nqid; i++){
4067f0337cdSDavid du Colombier m = convD2M(&dirs[i], &buf[n], blen-n);
4077f0337cdSDavid du Colombier if(off <= pos){
4087f0337cdSDavid du Colombier if(m <= BIT16SZ || m > cnt)
4097f0337cdSDavid du Colombier break;
4107f0337cdSDavid du Colombier n += m;
4117f0337cdSDavid du Colombier cnt -= m;
4127f0337cdSDavid du Colombier }
4137f0337cdSDavid du Colombier pos += m;
4147f0337cdSDavid du Colombier }
4157f0337cdSDavid du Colombier return n;
4167f0337cdSDavid du Colombier }
4177f0337cdSDavid du Colombier
4182ddf2468SDavid du Colombier enum { Chunk = 1024, };
4192ddf2468SDavid du Colombier
4207f0337cdSDavid du Colombier int
makeaudioctldata(Fid * f)4217f0337cdSDavid du Colombier makeaudioctldata(Fid *f)
4227f0337cdSDavid du Colombier {
4232ddf2468SDavid du Colombier int rec, ctl, i, diff;
4242ddf2468SDavid du Colombier long *actls; /* 8 of them */
4257f0337cdSDavid du Colombier char *p, *e;
4267f0337cdSDavid du Colombier Audiocontrol *c;
4277f0337cdSDavid du Colombier Audioctldata *a;
4287f0337cdSDavid du Colombier
4297f0337cdSDavid du Colombier if((a = f->fiddata) == nil)
4307f0337cdSDavid du Colombier sysfatal("fiddata");
4312ddf2468SDavid du Colombier if((p = a->s) == nil)
432906943f9SDavid du Colombier a->s = p = emallocz(Chunk, 0);
4332ddf2468SDavid du Colombier e = p + Chunk - 1; /* e must point *at* last byte, not *after* */
4347f0337cdSDavid du Colombier for(rec = 0; rec < 2; rec++)
4357f0337cdSDavid du Colombier for(ctl = 0; ctl < Ncontrol; ctl++){
4367f0337cdSDavid du Colombier c = &controls[rec][ctl];
4372ddf2468SDavid du Colombier actls = a->values[rec][ctl];
4382ddf2468SDavid du Colombier diff = 0;
4397f0337cdSDavid du Colombier if(c->chans){
440ce31847cSDavid du Colombier for(i = 1; i < 8; i++)
4412ddf2468SDavid du Colombier if((c->chans & 1<<i) &&
4422ddf2468SDavid du Colombier c->value[i] != actls[i])
4432ddf2468SDavid du Colombier diff = 1;
4447f0337cdSDavid du Colombier }else
4452ddf2468SDavid du Colombier if(c->value[0] != actls[0])
4462ddf2468SDavid du Colombier diff = 1;
4472ddf2468SDavid du Colombier if(diff){
4482ddf2468SDavid du Colombier p = seprint(p, e, "%s %s %A", c->name,
4492ddf2468SDavid du Colombier rec? "in": "out", c);
4502ddf2468SDavid du Colombier memmove(actls, c->value, sizeof c->value);
4517f0337cdSDavid du Colombier if(c->min != Undef){
4522ddf2468SDavid du Colombier p = seprint(p, e, " %ld %ld", c->min,
4532ddf2468SDavid du Colombier c->max);
4547f0337cdSDavid du Colombier if(c->step != Undef)
4552ddf2468SDavid du Colombier p = seprint(p, e, " %ld",
4562ddf2468SDavid du Colombier c->step);
4577f0337cdSDavid du Colombier }
4587f0337cdSDavid du Colombier p = seprint(p, e, "\n");
4597f0337cdSDavid du Colombier }
4607f0337cdSDavid du Colombier }
4612ddf2468SDavid du Colombier assert(strlen(a->s) < Chunk);
4627f0337cdSDavid du Colombier a->ns = p - a->s;
4637f0337cdSDavid du Colombier return a->ns;
4647f0337cdSDavid du Colombier }
4657f0337cdSDavid du Colombier
4667f0337cdSDavid du Colombier void
readproc(void * x)4677f0337cdSDavid du Colombier readproc(void *x)
4687f0337cdSDavid du Colombier {
4697f0337cdSDavid du Colombier int n, cnt;
4707f0337cdSDavid du Colombier ulong event;
4712ddf2468SDavid du Colombier vlong off;
4722ddf2468SDavid du Colombier uchar *mdata;
4732ddf2468SDavid du Colombier Audioctldata *a;
4742ddf2468SDavid du Colombier Fcall *rhdr;
4752ddf2468SDavid du Colombier Fid *f;
4762ddf2468SDavid du Colombier Worker *w;
4777f0337cdSDavid du Colombier
4787f0337cdSDavid du Colombier w = x;
479906943f9SDavid du Colombier mdata = emallocz(8*1024+IOHDRSZ, 0);
4807f0337cdSDavid du Colombier while(event = recvul(w->eventc)){
4817f0337cdSDavid du Colombier if(event != Work)
4827f0337cdSDavid du Colombier continue;
4837f0337cdSDavid du Colombier f = w->fid;
4847f0337cdSDavid du Colombier rhdr = w->rhdr;
4857f0337cdSDavid du Colombier a = f->fiddata;
4867f0337cdSDavid du Colombier off = rhdr->offset;
4877f0337cdSDavid du Colombier cnt = rhdr->count;
4887f0337cdSDavid du Colombier assert(a->offoff == off);
4897f0337cdSDavid du Colombier /* f is already locked */
4907f0337cdSDavid du Colombier for(;;){
4917f0337cdSDavid du Colombier qunlock(f);
4927f0337cdSDavid du Colombier event = recvul(w->eventc);
4937f0337cdSDavid du Colombier qlock(f);
494906943f9SDavid du Colombier ddprint(2, "readproc unblocked fid %d %lld\n",
4952ddf2468SDavid du Colombier f->fid, f->dir->qid.path);
4967f0337cdSDavid du Colombier switch (event & 0xffff){
4977f0337cdSDavid du Colombier case Work:
4987f0337cdSDavid du Colombier sysfatal("readproc phase error");
4997f0337cdSDavid du Colombier case Check:
5007f0337cdSDavid du Colombier if(f->fiddata && makeaudioctldata(f) == 0)
5017f0337cdSDavid du Colombier continue;
5027f0337cdSDavid du Colombier break;
5037f0337cdSDavid du Colombier case Flush:
5047f0337cdSDavid du Colombier if((event >> 16) == rhdr->tag){
505906943f9SDavid du Colombier ddprint(2, "readproc flushing fid %d, tag %d\n",
5062ddf2468SDavid du Colombier f->fid, rhdr->tag);
5077f0337cdSDavid du Colombier goto flush;
5087f0337cdSDavid du Colombier }
5097f0337cdSDavid du Colombier continue;
5107f0337cdSDavid du Colombier }
5117f0337cdSDavid du Colombier if(f->fiddata){
5127f0337cdSDavid du Colombier rhdr->data = a->s;
5137f0337cdSDavid du Colombier rhdr->count = a->ns;
5147f0337cdSDavid du Colombier break;
5157f0337cdSDavid du Colombier }
5167f0337cdSDavid du Colombier yield();
5177f0337cdSDavid du Colombier }
5187f0337cdSDavid du Colombier if(rhdr->count > cnt)
5197f0337cdSDavid du Colombier rhdr->count = cnt;
5207f0337cdSDavid du Colombier if(rhdr->count)
5217f0337cdSDavid du Colombier f->flags &= ~Eof;
522906943f9SDavid du Colombier ddprint(2, "readproc:->%F\n", rhdr);
5237f0337cdSDavid du Colombier n = convS2M(rhdr, mdata, messagesize);
5247f0337cdSDavid du Colombier if(write(mfd[1], mdata, n) != n)
5257f0337cdSDavid du Colombier sysfatal("mount write");
5267f0337cdSDavid du Colombier flush:
5277f0337cdSDavid du Colombier w->tag = NOTAG;
5287f0337cdSDavid du Colombier f->readers--;
5297f0337cdSDavid du Colombier assert(f->readers == 0);
5307f0337cdSDavid du Colombier free(rhdr);
5317f0337cdSDavid du Colombier w->rhdr = nil;
5327f0337cdSDavid du Colombier qunlock(f);
5337f0337cdSDavid du Colombier sendp(procchan, w);
5347f0337cdSDavid du Colombier }
5357f0337cdSDavid du Colombier threadexits(nil);
5367f0337cdSDavid du Colombier }
5377f0337cdSDavid du Colombier
5387f0337cdSDavid du Colombier char*
rread(Fid * f)5397f0337cdSDavid du Colombier rread(Fid *f)
5407f0337cdSDavid du Colombier {
54145d5944cSDavid du Colombier int i, n, cnt, rec, div;
5422ddf2468SDavid du Colombier vlong off;
5437f0337cdSDavid du Colombier char *p;
5447f0337cdSDavid du Colombier Audiocontrol *c;
5457f0337cdSDavid du Colombier Audioctldata *a;
5467f0337cdSDavid du Colombier Worker *w;
5472ddf2468SDavid du Colombier static char buf[1024];
5487f0337cdSDavid du Colombier
5497f0337cdSDavid du Colombier rhdr.count = 0;
5507f0337cdSDavid du Colombier off = thdr.offset;
5517f0337cdSDavid du Colombier cnt = thdr.count;
5527f0337cdSDavid du Colombier
5537f0337cdSDavid du Colombier if(cnt > messagesize - IOHDRSZ)
5547f0337cdSDavid du Colombier cnt = messagesize - IOHDRSZ;
5557f0337cdSDavid du Colombier
5567f0337cdSDavid du Colombier rhdr.data = (char*)mbuf;
5577f0337cdSDavid du Colombier
5587f0337cdSDavid du Colombier if(f->dir == &dirs[Qdir]){
5597f0337cdSDavid du Colombier n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
5607f0337cdSDavid du Colombier rhdr.count = n;
5617f0337cdSDavid du Colombier return nil;
5627f0337cdSDavid du Colombier }
5637f0337cdSDavid du Colombier
5647f0337cdSDavid du Colombier if(f->dir == &dirs[Qvolume]){
5657f0337cdSDavid du Colombier p = buf;
5667f0337cdSDavid du Colombier n = sizeof buf;
5677f0337cdSDavid du Colombier for(rec = 0; rec < 2; rec++){
5687f0337cdSDavid du Colombier c = &controls[rec][Volume_control];
5697f0337cdSDavid du Colombier if(c->readable){
57045d5944cSDavid du Colombier div = c->max - c->min;
5712ddf2468SDavid du Colombier i = snprint(p, n, "audio %s %ld\n",
5722ddf2468SDavid du Colombier rec? "in": "out", (c->min != Undef?
57345d5944cSDavid du Colombier 100*(c->value[0]-c->min)/(div? div: 1):
5742ddf2468SDavid du Colombier c->value[0]));
5752ddf2468SDavid du Colombier p += i;
5762ddf2468SDavid du Colombier n -= i;
5777f0337cdSDavid du Colombier }
5787f0337cdSDavid du Colombier c = &controls[rec][Treble_control];
5797f0337cdSDavid du Colombier if(c->readable){
58045d5944cSDavid du Colombier div = c->max - c->min;
5812ddf2468SDavid du Colombier i = snprint(p, n, "treb %s %ld\n",
5822ddf2468SDavid du Colombier rec? "in": "out", (c->min != Undef?
58345d5944cSDavid du Colombier 100*(c->value[0]-c->min)/(div? div: 1):
5842ddf2468SDavid du Colombier c->value[0]));
5852ddf2468SDavid du Colombier p += i;
5862ddf2468SDavid du Colombier n -= i;
5877f0337cdSDavid du Colombier }
5887f0337cdSDavid du Colombier c = &controls[rec][Bass_control];
5897f0337cdSDavid du Colombier if(c->readable){
59045d5944cSDavid du Colombier div = c->max - c->min;
5912ddf2468SDavid du Colombier i = snprint(p, n, "bass %s %ld\n",
5922ddf2468SDavid du Colombier rec? "in": "out", (c->min != Undef?
59345d5944cSDavid du Colombier 100*(c->value[0]-c->min)/(div? div: 1):
5942ddf2468SDavid du Colombier c->value[0]));
5952ddf2468SDavid du Colombier p += i;
5962ddf2468SDavid du Colombier n -= i;
5977f0337cdSDavid du Colombier }
5987f0337cdSDavid du Colombier c = &controls[rec][Speed_control];
5997f0337cdSDavid du Colombier if(c->readable){
6002ddf2468SDavid du Colombier i = snprint(p, n, "speed %s %ld\n",
6012ddf2468SDavid du Colombier rec? "in": "out", c->value[0]);
6022ddf2468SDavid du Colombier p += i;
6032ddf2468SDavid du Colombier n -= i;
6047f0337cdSDavid du Colombier }
6057f0337cdSDavid du Colombier }
6067f0337cdSDavid du Colombier n = sizeof buf - n;
6077f0337cdSDavid du Colombier if(off > n)
6087f0337cdSDavid du Colombier rhdr.count = 0;
6097f0337cdSDavid du Colombier else{
6107f0337cdSDavid du Colombier rhdr.data = buf + off;
6117f0337cdSDavid du Colombier rhdr.count = n - off;
6127f0337cdSDavid du Colombier if(rhdr.count > cnt)
6137f0337cdSDavid du Colombier rhdr.count = cnt;
6147f0337cdSDavid du Colombier }
6157f0337cdSDavid du Colombier return nil;
6167f0337cdSDavid du Colombier }
6177f0337cdSDavid du Colombier
6187f0337cdSDavid du Colombier if(f->dir == &dirs[Qaudioctl]){
6197f0337cdSDavid du Colombier Fcall *hdr;
6207f0337cdSDavid du Colombier
6217f0337cdSDavid du Colombier qlock(f);
6227f0337cdSDavid du Colombier a = f->fiddata;
6237f0337cdSDavid du Colombier if(off - a->offoff < 0){
6247f0337cdSDavid du Colombier /* there was a seek */
6257f0337cdSDavid du Colombier a->offoff = off;
6267f0337cdSDavid du Colombier a->ns = 0;
6277f0337cdSDavid du Colombier }
6287f0337cdSDavid du Colombier do {
6297f0337cdSDavid du Colombier if(off - a->offoff < a->ns){
6307f0337cdSDavid du Colombier rhdr.data = a->s + (off - a->offoff);
6317f0337cdSDavid du Colombier rhdr.count = a->ns - (off - a->offoff);
6327f0337cdSDavid du Colombier if(rhdr.count > cnt)
6337f0337cdSDavid du Colombier rhdr.count = cnt;
6347f0337cdSDavid du Colombier qunlock(f);
6357f0337cdSDavid du Colombier return nil;
6367f0337cdSDavid du Colombier }
6377f0337cdSDavid du Colombier if(a->offoff != off){
6387f0337cdSDavid du Colombier a->ns = 0;
6397f0337cdSDavid du Colombier a->offoff = off;
6407f0337cdSDavid du Colombier rhdr.count = 0;
6417f0337cdSDavid du Colombier qunlock(f);
6427f0337cdSDavid du Colombier return nil;
6437f0337cdSDavid du Colombier }
6447f0337cdSDavid du Colombier } while(makeaudioctldata(f) != 0);
6457f0337cdSDavid du Colombier
6467f0337cdSDavid du Colombier assert(a->offoff == off);
6477f0337cdSDavid du Colombier /* Wait for data off line */
6487f0337cdSDavid du Colombier f->readers++;
6497f0337cdSDavid du Colombier w = nbrecvp(procchan);
6507f0337cdSDavid du Colombier if(w == nil){
6517f0337cdSDavid du Colombier w = emallocz(sizeof(Worker), 1);
6527f0337cdSDavid du Colombier w->eventc = chancreate(sizeof(ulong), 1);
6537f0337cdSDavid du Colombier w->next = workers;
6547f0337cdSDavid du Colombier workers = w;
6557f0337cdSDavid du Colombier proccreate(readproc, w, 4096);
6567f0337cdSDavid du Colombier }
657906943f9SDavid du Colombier hdr = emallocz(sizeof(Fcall), 0);
6587f0337cdSDavid du Colombier w->fid = f;
6597f0337cdSDavid du Colombier w->tag = thdr.tag;
6607f0337cdSDavid du Colombier assert(w->rhdr == nil);
6617f0337cdSDavid du Colombier w->rhdr = hdr;
6627f0337cdSDavid du Colombier hdr->count = cnt;
6637f0337cdSDavid du Colombier hdr->offset = off;
6647f0337cdSDavid du Colombier hdr->type = thdr.type+1;
6657f0337cdSDavid du Colombier hdr->fid = thdr.fid;
6667f0337cdSDavid du Colombier hdr->tag = thdr.tag;
6677f0337cdSDavid du Colombier sendul(w->eventc, Work);
6687f0337cdSDavid du Colombier return (char*)~0;
6697f0337cdSDavid du Colombier }
6707f0337cdSDavid du Colombier
6717f0337cdSDavid du Colombier return Eperm;
6727f0337cdSDavid du Colombier }
6737f0337cdSDavid du Colombier
6747f0337cdSDavid du Colombier char*
rwrite(Fid * f)6757f0337cdSDavid du Colombier rwrite(Fid *f)
6767f0337cdSDavid du Colombier {
6777f0337cdSDavid du Colombier long cnt, value;
6787f0337cdSDavid du Colombier char *lines[2*Ncontrol], *fields[4], *subfields[9], *err, *p;
6797f0337cdSDavid du Colombier int nlines, i, nf, nnf, rec, ctl;
6807f0337cdSDavid du Colombier Audiocontrol *c;
6817f0337cdSDavid du Colombier Worker *w;
6827f0337cdSDavid du Colombier static char buf[256];
6837f0337cdSDavid du Colombier
6847f0337cdSDavid du Colombier rhdr.count = 0;
6857f0337cdSDavid du Colombier cnt = thdr.count;
6867f0337cdSDavid du Colombier
6877f0337cdSDavid du Colombier if(cnt > messagesize - IOHDRSZ)
6887f0337cdSDavid du Colombier cnt = messagesize - IOHDRSZ;
6897f0337cdSDavid du Colombier
6907f0337cdSDavid du Colombier err = nil;
6917f0337cdSDavid du Colombier if(f->dir == &dirs[Qvolume] || f->dir == &dirs[Qaudioctl]){
6927f0337cdSDavid du Colombier thdr.data[cnt] = '\0';
6937f0337cdSDavid du Colombier nlines = getfields(thdr.data, lines, 2*Ncontrol, 1, "\n");
6947f0337cdSDavid du Colombier for(i = 0; i < nlines; i++){
695906943f9SDavid du Colombier dprint(2, "line: %s\n", lines[i]);
6967f0337cdSDavid du Colombier nf = tokenize(lines[i], fields, 4);
6977f0337cdSDavid du Colombier if(nf == 0)
6987f0337cdSDavid du Colombier continue;
6992ddf2468SDavid du Colombier if(nf == 3)
7002ddf2468SDavid du Colombier if(strcmp(fields[1], "in") == 0 ||
7012ddf2468SDavid du Colombier strcmp(fields[1], "record") == 0)
7027f0337cdSDavid du Colombier rec = 1;
7032ddf2468SDavid du Colombier else if(strcmp(fields[1], "out") == 0 ||
7042ddf2468SDavid du Colombier strcmp(fields[1], "playback") == 0)
7057f0337cdSDavid du Colombier rec = 0;
7067f0337cdSDavid du Colombier else{
707906943f9SDavid du Colombier dprint(2, "bad1\n");
7087f0337cdSDavid du Colombier return Ebadctl;
7097f0337cdSDavid du Colombier }
7102ddf2468SDavid du Colombier else if(nf == 2)
7117f0337cdSDavid du Colombier rec = 0;
7127f0337cdSDavid du Colombier else{
713906943f9SDavid du Colombier dprint(2, "bad2 %d\n", nf);
7147f0337cdSDavid du Colombier return Ebadctl;
7157f0337cdSDavid du Colombier }
7167f0337cdSDavid du Colombier c = nil;
7177f0337cdSDavid du Colombier if(strcmp(fields[0], "audio") == 0) /* special case */
7187f0337cdSDavid du Colombier fields[0] = "volume";
7197f0337cdSDavid du Colombier for(ctl = 0; ctl < Ncontrol; ctl++){
7207f0337cdSDavid du Colombier c = &controls[rec][ctl];
7217f0337cdSDavid du Colombier if(strcmp(fields[0], c->name) == 0)
7227f0337cdSDavid du Colombier break;
7237f0337cdSDavid du Colombier }
7247f0337cdSDavid du Colombier if(ctl == Ncontrol){
725906943f9SDavid du Colombier dprint(2, "bad3\n");
7267f0337cdSDavid du Colombier return Ebadctl;
7277f0337cdSDavid du Colombier }
7282ddf2468SDavid du Colombier if(f->dir == &dirs[Qvolume] && ctl != Speed_control &&
7292ddf2468SDavid du Colombier c->min != Undef && c->max != Undef){
7302ddf2468SDavid du Colombier nnf = tokenize(fields[nf-1], subfields,
7312ddf2468SDavid du Colombier nelem(subfields));
7327f0337cdSDavid du Colombier if(nnf <= 0 || nnf > 8){
733906943f9SDavid du Colombier dprint(2, "bad4\n");
7347f0337cdSDavid du Colombier return Ebadctl;
7357f0337cdSDavid du Colombier }
7367f0337cdSDavid du Colombier p = buf;
7377f0337cdSDavid du Colombier for(i = 0; i < nnf; i++){
7387f0337cdSDavid du Colombier value = strtol(subfields[i], nil, 0);
7392ddf2468SDavid du Colombier value = ((100 - value)*c->min +
7402ddf2468SDavid du Colombier value*c->max) / 100;
741906943f9SDavid du Colombier if(p == buf){
742906943f9SDavid du Colombier dprint(2, "rwrite: %s %s '%ld",
7432ddf2468SDavid du Colombier c->name, rec?
7442ddf2468SDavid du Colombier "record":
7452ddf2468SDavid du Colombier "playback",
7462ddf2468SDavid du Colombier value);
747906943f9SDavid du Colombier }else
748906943f9SDavid du Colombier dprint(2, " %ld", value);
7497f0337cdSDavid du Colombier if(p == buf)
7502ddf2468SDavid du Colombier p = seprint(p, buf+sizeof buf,
7512ddf2468SDavid du Colombier "0x%p %s %s '%ld",
7522ddf2468SDavid du Colombier replchan, c->name, rec?
7532ddf2468SDavid du Colombier "record": "playback",
7542ddf2468SDavid du Colombier value);
7557f0337cdSDavid du Colombier else
7562ddf2468SDavid du Colombier p = seprint(p, buf+sizeof buf,
7572ddf2468SDavid du Colombier " %ld", value);
7587f0337cdSDavid du Colombier }
759906943f9SDavid du Colombier dprint(2, "'\n");
7602ddf2468SDavid du Colombier seprint(p, buf+sizeof buf-1, "'");
7617f0337cdSDavid du Colombier chanprint(controlchan, buf);
7627f0337cdSDavid du Colombier }else{
763906943f9SDavid du Colombier dprint(2, "rwrite: %s %s %q", c->name,
7642ddf2468SDavid du Colombier rec? "record": "playback",
7652ddf2468SDavid du Colombier fields[nf-1]);
7662ddf2468SDavid du Colombier chanprint(controlchan, "0x%p %s %s %q",
7672ddf2468SDavid du Colombier replchan, c->name, rec? "record":
7682ddf2468SDavid du Colombier "playback", fields[nf-1]);
7697f0337cdSDavid du Colombier }
7707f0337cdSDavid du Colombier p = recvp(replchan);
7717f0337cdSDavid du Colombier if(p){
7727f0337cdSDavid du Colombier if(strcmp(p, "ok") == 0){
7737f0337cdSDavid du Colombier free(p);
7747f0337cdSDavid du Colombier p = nil;
7757f0337cdSDavid du Colombier }
7767f0337cdSDavid du Colombier if(err == nil)
7777f0337cdSDavid du Colombier err = p;
7787f0337cdSDavid du Colombier }
7797f0337cdSDavid du Colombier }
7807f0337cdSDavid du Colombier for(w = workers; w; w = w->next)
7817f0337cdSDavid du Colombier nbsendul(w->eventc, Qaudioctl << 16 | Check);
7827f0337cdSDavid du Colombier rhdr.count = thdr.count;
7837f0337cdSDavid du Colombier return err;
7847f0337cdSDavid du Colombier }
7857f0337cdSDavid du Colombier return Eperm;
7867f0337cdSDavid du Colombier }
7877f0337cdSDavid du Colombier
7887f0337cdSDavid du Colombier char *
rclunk(Fid * f)7897f0337cdSDavid du Colombier rclunk(Fid *f)
7907f0337cdSDavid du Colombier {
7917f0337cdSDavid du Colombier Audioctldata *a;
7927f0337cdSDavid du Colombier
7937f0337cdSDavid du Colombier qlock(f);
7947f0337cdSDavid du Colombier f->flags &= ~(Open|Busy);
7957f0337cdSDavid du Colombier assert(f->readers ==0);
7967f0337cdSDavid du Colombier if(f->fiddata){
7977f0337cdSDavid du Colombier a = f->fiddata;
7987f0337cdSDavid du Colombier if(a->s)
7997f0337cdSDavid du Colombier free(a->s);
8007f0337cdSDavid du Colombier free(a);
8017f0337cdSDavid du Colombier f->fiddata = nil;
8027f0337cdSDavid du Colombier }
8037f0337cdSDavid du Colombier qunlock(f);
8047f0337cdSDavid du Colombier return 0;
8057f0337cdSDavid du Colombier }
8067f0337cdSDavid du Colombier
8077f0337cdSDavid du Colombier char *
rremove(Fid *)8087f0337cdSDavid du Colombier rremove(Fid *)
8097f0337cdSDavid du Colombier {
8107f0337cdSDavid du Colombier return Eperm;
8117f0337cdSDavid du Colombier }
8127f0337cdSDavid du Colombier
8137f0337cdSDavid du Colombier char *
rstat(Fid * f)8147f0337cdSDavid du Colombier rstat(Fid *f)
8157f0337cdSDavid du Colombier {
8167f0337cdSDavid du Colombier Audioctldata *a;
8177f0337cdSDavid du Colombier
8187f0337cdSDavid du Colombier if(f->dir == &dirs[Qaudioctl]){
8197f0337cdSDavid du Colombier qlock(f);
8207f0337cdSDavid du Colombier if(f->fiddata == nil)
8217f0337cdSDavid du Colombier f->fiddata = allocaudioctldata();
8227f0337cdSDavid du Colombier a = f->fiddata;
8237f0337cdSDavid du Colombier if(a->ns == 0)
8247f0337cdSDavid du Colombier makeaudioctldata(f);
8257f0337cdSDavid du Colombier f->dir->length = a->offoff + a->ns;
8267f0337cdSDavid du Colombier qunlock(f);
8277f0337cdSDavid du Colombier }
8287f0337cdSDavid du Colombier rhdr.nstat = convD2M(f->dir, mbuf, messagesize - IOHDRSZ);
8297f0337cdSDavid du Colombier rhdr.stat = mbuf;
8307f0337cdSDavid du Colombier return 0;
8317f0337cdSDavid du Colombier }
8327f0337cdSDavid du Colombier
8337f0337cdSDavid du Colombier char *
rwstat(Fid *)8347f0337cdSDavid du Colombier rwstat(Fid*)
8357f0337cdSDavid du Colombier {
8367f0337cdSDavid du Colombier return Eperm;
8377f0337cdSDavid du Colombier }
8387f0337cdSDavid du Colombier
8397f0337cdSDavid du Colombier Fid *
newfid(int fid)8407f0337cdSDavid du Colombier newfid(int fid)
8417f0337cdSDavid du Colombier {
8427f0337cdSDavid du Colombier Fid *f, *ff;
8437f0337cdSDavid du Colombier
8447f0337cdSDavid du Colombier ff = nil;
8457f0337cdSDavid du Colombier for(f = fids; f; f = f->next)
8462ddf2468SDavid du Colombier if(f->fid == fid)
8477f0337cdSDavid du Colombier return f;
8482ddf2468SDavid du Colombier else if(ff == nil && (f->flags & Busy) == 0)
8497f0337cdSDavid du Colombier ff = f;
8507f0337cdSDavid du Colombier if(ff == nil){
8517f0337cdSDavid du Colombier ff = emallocz(sizeof *ff, 1);
8527f0337cdSDavid du Colombier ff->next = fids;
8537f0337cdSDavid du Colombier fids = ff;
8547f0337cdSDavid du Colombier }
8557f0337cdSDavid du Colombier ff->fid = fid;
8567f0337cdSDavid du Colombier ff->flags &= ~(Busy|Open);
8577f0337cdSDavid du Colombier ff->dir = nil;
8587f0337cdSDavid du Colombier return ff;
8597f0337cdSDavid du Colombier }
8607f0337cdSDavid du Colombier
8617f0337cdSDavid du Colombier void
io(void *)8627f0337cdSDavid du Colombier io(void *)
8637f0337cdSDavid du Colombier {
8647f0337cdSDavid du Colombier char *err, e[32];
8657f0337cdSDavid du Colombier int n;
8667f0337cdSDavid du Colombier
8677f0337cdSDavid du Colombier close(p[1]);
8687f0337cdSDavid du Colombier
8697f0337cdSDavid du Colombier procchan = chancreate(sizeof(Channel*), 8);
8707f0337cdSDavid du Colombier replchan = chancreate(sizeof(char*), 0);
8717f0337cdSDavid du Colombier for(;;){
8727f0337cdSDavid du Colombier /*
8737f0337cdSDavid du Colombier * reading from a pipe or a network device
8747f0337cdSDavid du Colombier * will give an error after a few eof reads
8757f0337cdSDavid du Colombier * however, we cannot tell the difference
8767f0337cdSDavid du Colombier * between a zero-length read and an interrupt
8777f0337cdSDavid du Colombier * on the processes writing to us,
8787f0337cdSDavid du Colombier * so we wait for the error
8797f0337cdSDavid du Colombier */
8807f0337cdSDavid du Colombier n = read9pmsg(mfd[0], mdata, messagesize);
8817f0337cdSDavid du Colombier if(n == 0)
8827f0337cdSDavid du Colombier continue;
8837f0337cdSDavid du Colombier if(n < 0){
8847f0337cdSDavid du Colombier rerrstr(e, sizeof e);
8857f0337cdSDavid du Colombier if(strcmp(e, "interrupted") == 0){
886906943f9SDavid du Colombier dprint(2, "read9pmsg interrupted\n");
8877f0337cdSDavid du Colombier continue;
8887f0337cdSDavid du Colombier }
8897f0337cdSDavid du Colombier return;
8907f0337cdSDavid du Colombier }
8917f0337cdSDavid du Colombier if(convM2S(mdata, n, &thdr) == 0)
8927f0337cdSDavid du Colombier continue;
8937f0337cdSDavid du Colombier
894906943f9SDavid du Colombier ddprint(2, "io:<-%F\n", &thdr);
8957f0337cdSDavid du Colombier
8967f0337cdSDavid du Colombier rhdr.data = (char*)mdata + messagesize;
8977f0337cdSDavid du Colombier if(!fcalls[thdr.type])
8987f0337cdSDavid du Colombier err = "bad fcall type";
8997f0337cdSDavid du Colombier else
9007f0337cdSDavid du Colombier err = (*fcalls[thdr.type])(newfid(thdr.fid));
9017f0337cdSDavid du Colombier if(err == (char*)~0)
9027f0337cdSDavid du Colombier continue; /* handled off line */
9037f0337cdSDavid du Colombier if(err){
9047f0337cdSDavid du Colombier rhdr.type = Rerror;
9057f0337cdSDavid du Colombier rhdr.ename = err;
9067f0337cdSDavid du Colombier }else{
9077f0337cdSDavid du Colombier rhdr.type = thdr.type + 1;
9087f0337cdSDavid du Colombier rhdr.fid = thdr.fid;
9097f0337cdSDavid du Colombier }
9107f0337cdSDavid du Colombier rhdr.tag = thdr.tag;
911906943f9SDavid du Colombier ddprint(2, "io:->%F\n", &rhdr);
9127f0337cdSDavid du Colombier n = convS2M(&rhdr, mdata, messagesize);
9137f0337cdSDavid du Colombier if(write(mfd[1], mdata, n) != n)
9147f0337cdSDavid du Colombier sysfatal("mount write");
9157f0337cdSDavid du Colombier }
9167f0337cdSDavid du Colombier }
9177f0337cdSDavid du Colombier
9187f0337cdSDavid du Colombier int
newid(void)9197f0337cdSDavid du Colombier newid(void)
9207f0337cdSDavid du Colombier {
9217f0337cdSDavid du Colombier int rv;
9227f0337cdSDavid du Colombier static int id;
9237f0337cdSDavid du Colombier static Lock idlock;
9247f0337cdSDavid du Colombier
9257f0337cdSDavid du Colombier lock(&idlock);
9267f0337cdSDavid du Colombier rv = ++id;
9277f0337cdSDavid du Colombier unlock(&idlock);
9287f0337cdSDavid du Colombier
9297f0337cdSDavid du Colombier return rv;
9307f0337cdSDavid du Colombier }
9317f0337cdSDavid du Colombier
9327f0337cdSDavid du Colombier void
ctlevent(void)9337f0337cdSDavid du Colombier ctlevent(void)
9347f0337cdSDavid du Colombier {
9357f0337cdSDavid du Colombier Worker *w;
9367f0337cdSDavid du Colombier
9377f0337cdSDavid du Colombier for(w = workers; w; w = w->next)
9387f0337cdSDavid du Colombier nbsendul(w->eventc, Qaudioctl << 16 | Check);
9397f0337cdSDavid du Colombier }
940