fs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <thread.h>
  4. #include <auth.h>
  5. #include <fcall.h>
  6. #include <libsec.h>
  7. #include "usb.h"
  8. #include "usbproto.h"
  9. #include "dat.h"
  10. #include "fns.h"
  11. #include "audioclass.h"
  12. #define STACKSIZE 16*1024
  13. enum
  14. {
  15. OPERM = 0x3, // mask of all permission types in open mode
  16. };
  17. typedef struct Fid Fid;
  18. typedef struct Audioctldata Audioctldata;
  19. typedef struct Worker Worker;
  20. struct Audioctldata
  21. {
  22. long offoff; // offset of the offset for audioctl
  23. long values[2][Ncontrol][8]; // last values transmitted
  24. char * s;
  25. int ns;
  26. };
  27. enum {
  28. Busy = 0x01,
  29. Open = 0x02,
  30. Eof = 0x04,
  31. };
  32. struct Fid
  33. {
  34. QLock;
  35. int fid;
  36. Dir * dir;
  37. ushort flags;
  38. short readers;
  39. void * fiddata; // file specific per-fid data (used for audioctl)
  40. Fid * next;
  41. };
  42. struct Worker
  43. {
  44. Fid *fid;
  45. ushort tag;
  46. Fcall *rhdr;
  47. Dir *dir;
  48. Channel *eventc;
  49. Worker *next;
  50. };
  51. enum {
  52. // Event channel messages for worker
  53. Work = 0x01,
  54. Check = 0x02,
  55. Flush = 0x03,
  56. };
  57. enum {
  58. Qdir,
  59. Qvolume,
  60. Qaudioctl,
  61. Qaudiostat,
  62. Qaudio,
  63. Qaudioin,
  64. Nqid,
  65. };
  66. Dir dirs[] = {
  67. /* Note: Qaudio{in} used as mount point for /dev/usb/%d/ep%ddata only */
  68. [Qdir] = {0,0,{Qdir, 0,QTDIR},0555|DMDIR,0,0,0, ".", nil,nil,nil},
  69. [Qvolume] = {0,0,{Qvolume, 0,QTFILE},0666,0,0,0, "volume", nil,nil,nil},
  70. [Qaudioctl] = {0,0,{Qaudioctl, 0,QTFILE},0666,0,0,0, "audioctl",nil,nil,nil},
  71. [Qaudiostat] = {0,0,{Qaudiostat, 0,QTFILE},0666,0,0,0, "audiostat",nil,nil,nil},
  72. [Qaudio] = {0,0,{Qaudio, 0,QTFILE},0222,0,0,0, "audio", nil,nil,nil},
  73. [Qaudioin] = {0,0,{Qaudioin, 0,QTFILE},0444,0,0,0, "audioin", nil,nil,nil},
  74. };
  75. int messagesize = 4*1024+IOHDRSZ;
  76. uchar mdata[8*1024+IOHDRSZ];
  77. uchar mbuf[8*1024+IOHDRSZ];
  78. Fcall thdr;
  79. Fcall rhdr;
  80. Worker *workers;
  81. char srvfile[64], mntdir[64];
  82. int mfd[2], p[2];
  83. char user[32];
  84. char *srvpost;
  85. Channel *procchan;
  86. Channel *replchan;
  87. Fid *fids;
  88. Fid* newfid(int);
  89. void io(void *);
  90. void usage(void);
  91. extern char *mntpt;
  92. char *rflush(Fid*), *rauth(Fid*),
  93. *rattach(Fid*), *rwalk(Fid*),
  94. *ropen(Fid*), *rcreate(Fid*),
  95. *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
  96. *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
  97. *rversion(Fid*);
  98. char *(*fcalls[])(Fid*) = {
  99. [Tflush] rflush,
  100. [Tversion] rversion,
  101. [Tauth] rauth,
  102. [Tattach] rattach,
  103. [Twalk] rwalk,
  104. [Topen] ropen,
  105. [Tcreate] rcreate,
  106. [Tread] rread,
  107. [Twrite] rwrite,
  108. [Tclunk] rclunk,
  109. [Tremove] rremove,
  110. [Tstat] rstat,
  111. [Twstat] rwstat,
  112. };
  113. char Eperm[] = "permission denied";
  114. char Enotdir[] = "not a directory";
  115. char Enoauth[] = "usbaudio: authentication not required";
  116. char Enotexist[] = "file does not exist";
  117. char Einuse[] = "file in use";
  118. char Eexist[] = "file exists";
  119. char Enotowner[] = "not owner";
  120. char Eisopen[] = "file already open for I/O";
  121. char Excl[] = "exclusive use file already open";
  122. char Ename[] = "illegal name";
  123. char Ebadctl[] = "unknown control message";
  124. int
  125. notifyf(void *, char *s)
  126. {
  127. if(strncmp(s, "interrupt", 9) == 0)
  128. return 1;
  129. return 0;
  130. }
  131. void
  132. post(char *name, char *envname, int srvfd)
  133. {
  134. int fd;
  135. char buf[32];
  136. fd = create(name, OWRITE, 0600);
  137. if(fd < 0)
  138. return;
  139. sprint(buf, "%d",srvfd);
  140. if(write(fd, buf, strlen(buf)) != strlen(buf))
  141. sysfatal("srv write");
  142. close(fd);
  143. putenv(envname, name);
  144. }
  145. static void
  146. dobind(Nexus *nx, char *mntpt, char *file)
  147. {
  148. Stream *s;
  149. Device *d;
  150. Endpt *ep;
  151. Streamalt *sa;
  152. char epdata[64], audiofile[64];
  153. if(nx == nil)
  154. return;
  155. s = nx->s;
  156. d = s->intf->d;
  157. for(sa = s->salt; sa != nil; sa = sa->next) {
  158. if(sa->dalt->npt != 0)
  159. break;
  160. }
  161. ep = &sa->dalt->ep[0];
  162. sprint(epdata, "#U/usb%d/%d/ep%ddata", d->ctlrno, d->id, ep->addr);
  163. sprint(audiofile, "%s/%s", mntpt, file);
  164. if(bind(epdata, audiofile, MREPL) < 0)
  165. sysfatal("bind failed");
  166. }
  167. void
  168. serve(void *)
  169. {
  170. int i;
  171. ulong t;
  172. if(pipe(p) < 0)
  173. sysfatal("pipe failed");
  174. mfd[0] = p[0];
  175. mfd[1] = p[0];
  176. atnotify(notifyf, 1);
  177. strcpy(user, getuser());
  178. t = time(nil);
  179. for (i = 0; i < Nqid; i++){
  180. dirs[i].uid = user;
  181. dirs[i].gid = user;
  182. dirs[i].muid = user;
  183. dirs[i].atime = t;
  184. dirs[i].mtime = t;
  185. }
  186. if(mntpt == nil){
  187. snprint(mntdir, sizeof(mntdir), "/dev");
  188. mntpt = mntdir;
  189. }
  190. if(debug)
  191. fmtinstall('F', fcallfmt);
  192. procrfork(io, nil, STACKSIZE, RFFDG|RFNAMEG);
  193. close(p[0]); /* don't deadlock if child fails */
  194. if(srvpost){
  195. sprint(srvfile, "/srv/%s", srvpost);
  196. remove(srvfile);
  197. post(srvfile, "usbaudio", p[1]);
  198. }
  199. if(mount(p[1], -1, mntpt, MBEFORE, "") < 0)
  200. sysfatal("mount failed");
  201. dobind(nexus[Play], mntpt, "audio");
  202. dobind(nexus[Record], mntpt, "audioin");
  203. threadexits(nil);
  204. }
  205. char*
  206. rversion(Fid*)
  207. {
  208. Fid *f;
  209. if(thdr.msize < 256)
  210. return "max messagesize too small";
  211. if(thdr.msize < messagesize)
  212. messagesize = thdr.msize;
  213. rhdr.msize = messagesize;
  214. if(strncmp(thdr.version, "9P2000", 6) != 0)
  215. return "unknown 9P version";
  216. else
  217. rhdr.version = "9P2000";
  218. for(f = fids; f; f = f->next)
  219. if(f->flags & Busy)
  220. rclunk(f);
  221. return nil;
  222. }
  223. char*
  224. rauth(Fid*)
  225. {
  226. return Enoauth;
  227. }
  228. char*
  229. rflush(Fid *)
  230. {
  231. Worker *w;
  232. int waitflush;
  233. do {
  234. waitflush = 0;
  235. for (w = workers; w; w = w->next)
  236. if (w->tag == thdr.oldtag){
  237. waitflush++;
  238. nbsendul(w->eventc, thdr.oldtag << 16 | Flush);
  239. }
  240. if (waitflush)
  241. sleep(50);
  242. } while(waitflush);
  243. if (debug & Dbgproc)
  244. fprint(2, "flush done on tag %d\n", thdr.oldtag);
  245. return 0;
  246. }
  247. char*
  248. rattach(Fid *f)
  249. {
  250. f->flags |= Busy;
  251. f->dir = &dirs[Qdir];
  252. rhdr.qid = f->dir->qid;
  253. if(strcmp(thdr.uname, user) != 0)
  254. return Eperm;
  255. return 0;
  256. }
  257. static Fid*
  258. doclone(Fid *f, int nfid)
  259. {
  260. Fid *nf;
  261. nf = newfid(nfid);
  262. if(nf->flags & Busy)
  263. return nil;
  264. nf->flags |= Busy;
  265. nf->flags &= ~Open;
  266. nf->dir = f->dir;
  267. return nf;
  268. }
  269. char*
  270. dowalk(Fid *f, char *name)
  271. {
  272. int t;
  273. if (strcmp(name, ".") == 0)
  274. return nil;
  275. if (strcmp(name, "..") == 0){
  276. f->dir = &dirs[Qdir];
  277. return nil;
  278. }
  279. if(f->dir != &dirs[Qdir])
  280. return Enotexist;
  281. for (t = 1; t < Nqid; t++){
  282. if (t == Qaudio && nexus[Play] == nil)
  283. continue;
  284. if (t == Qaudioin && nexus[Record] == nil)
  285. continue;
  286. if(strcmp(name, dirs[t].name) == 0){
  287. f->dir = &dirs[t];
  288. return nil;
  289. }
  290. }
  291. return Enotexist;
  292. }
  293. char*
  294. rwalk(Fid *f)
  295. {
  296. Fid *nf;
  297. char *rv;
  298. int i;
  299. Dir *savedir;
  300. if(f->flags & Open)
  301. return Eisopen;
  302. rhdr.nwqid = 0;
  303. nf = nil;
  304. savedir = f->dir;
  305. /* clone if requested */
  306. if(thdr.newfid != thdr.fid){
  307. nf = doclone(f, thdr.newfid);
  308. if(nf == nil)
  309. return "new fid in use";
  310. f = nf;
  311. }
  312. /* if it's just a clone, return */
  313. if(thdr.nwname == 0 && nf != nil)
  314. return nil;
  315. /* walk each element */
  316. rv = nil;
  317. for(i = 0; i < thdr.nwname; i++){
  318. rv = dowalk(f, thdr.wname[i]);
  319. if(rv != nil){
  320. if(nf != nil)
  321. rclunk(nf);
  322. else
  323. f->dir = savedir;
  324. break;
  325. }
  326. rhdr.wqid[i] = f->dir->qid;
  327. }
  328. rhdr.nwqid = i;
  329. /* we only error out if no walk */
  330. if(i > 0)
  331. rv = nil;
  332. return rv;
  333. }
  334. Audioctldata *
  335. allocaudioctldata(void)
  336. {
  337. int i, j, k;
  338. Audioctldata *a;
  339. a = emallocz(sizeof(Audioctldata), 1);
  340. for (i = 0; i < 2; i++)
  341. for(j=0; j < Ncontrol; j++)
  342. for(k=0; k < 8; k++)
  343. a->values[i][j][k] = Undef;
  344. return a;
  345. }
  346. char *
  347. ropen(Fid *f)
  348. {
  349. if(f->flags & Open)
  350. return Eisopen;
  351. if(f->dir == &dirs[Qaudio] || f->dir == &dirs[Qaudioin])
  352. return Eperm;
  353. if(thdr.mode != OREAD)
  354. if((f->dir->mode & 0x2) == 0)
  355. return Eperm;
  356. qlock(f);
  357. if(f->dir == &dirs[Qaudioctl] && f->fiddata == nil)
  358. f->fiddata = allocaudioctldata();
  359. qunlock(f);
  360. rhdr.iounit = 0;
  361. rhdr.qid = f->dir->qid;
  362. f->flags |= Open;
  363. return nil;
  364. }
  365. char *
  366. rcreate(Fid*)
  367. {
  368. return Eperm;
  369. }
  370. int
  371. readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
  372. {
  373. int i, m, n;
  374. long pos;
  375. n = 0;
  376. pos = 0;
  377. for (i = 1; i < Nqid; i++){
  378. if (nexus[Play] == nil && i == Qaudio)
  379. continue;
  380. if (nexus[Record] == nil && i == Qaudioin)
  381. continue;
  382. m = convD2M(&dirs[i], &buf[n], blen-n);
  383. if(off <= pos){
  384. if(m <= BIT16SZ || m > cnt)
  385. break;
  386. n += m;
  387. cnt -= m;
  388. }
  389. pos += m;
  390. }
  391. return n;
  392. }
  393. int
  394. makeaudioctldata(Fid *f)
  395. {
  396. int rec, ctl, i, different;
  397. char *p, *e;
  398. Audiocontrol *c;
  399. Audioctldata *a;
  400. Nexus *nx;
  401. if ((a = f->fiddata) == nil)
  402. sysfatal("fiddata");
  403. if ((p = a->s) == nil){
  404. p = emalloc(1024);
  405. a->s = p;
  406. }
  407. e = p + 1024;
  408. for(rec = 0; rec < 2; rec++) {
  409. nx = nexus[rec];
  410. if(nx == nil)
  411. continue;
  412. for(ctl = 0; ctl < Ncontrol; ctl++) {
  413. c = &nx->control[ctl];
  414. different = 0;
  415. if (c->chans){
  416. for (i = 1; i < 8; i++)
  417. if ((c->chans & 1<<i) && c->value[i] != a->values[rec][ctl][i])
  418. different = 1;
  419. }else
  420. if (c->value[0] != a->values[rec][ctl][0])
  421. different = 1;
  422. if (different){
  423. p = seprint(p, e, "%s %s %A", controlname[ctl], rec?"in":"out", c);
  424. memmove(a->values[rec][ctl], c->value, sizeof c->value);
  425. if (c->min != Undef){
  426. p = seprint(p, e, " %ld %ld", c->min, c->max);
  427. if (c->step != Undef)
  428. p = seprint(p, e, " %ld", c->step);
  429. }
  430. p = seprint(p, e, "\n");
  431. }
  432. }
  433. }
  434. assert(strlen(a->s) < 1024);
  435. a->ns = p - a->s;
  436. return a->ns;
  437. }
  438. void
  439. readproc(void *x)
  440. {
  441. Fcall *rhdr;
  442. Audioctldata *a;
  443. Fid *f;
  444. uchar *mdata;
  445. int n, cnt;
  446. long off;
  447. Worker *w;
  448. ulong event;
  449. w = x;
  450. mdata = emalloc(8*1024+IOHDRSZ);
  451. while(event = recvul(w->eventc)){
  452. if (event != Work)
  453. continue;
  454. f = w->fid;
  455. rhdr = w->rhdr;
  456. a = f->fiddata;
  457. off = rhdr->offset;
  458. cnt = rhdr->count;
  459. assert(a->offoff == off);
  460. /* f is already locked */
  461. for(;;){
  462. qunlock(f);
  463. event = recvul(w->eventc);
  464. qlock(f);
  465. if (debug & Dbgproc)
  466. fprint(2, "readproc unblocked fid %d %lld\n", f->fid, f->dir->qid.path);
  467. switch (event & 0xffff) {
  468. case Work:
  469. sysfatal("readproc phase error");
  470. case Check:
  471. if (f->fiddata && makeaudioctldata(f) == 0)
  472. continue;
  473. break;
  474. case Flush:
  475. if ((event >> 16) == rhdr->tag) {
  476. if (debug & Dbgproc)
  477. fprint(2, "readproc flushing fid %d, tag %d\n", f->fid, rhdr->tag);
  478. goto flush;
  479. }
  480. continue;
  481. }
  482. if (f->fiddata){
  483. rhdr->data = a->s;
  484. rhdr->count = a->ns;
  485. break;
  486. }
  487. yield();
  488. }
  489. if (rhdr->count > cnt)
  490. rhdr->count = cnt;
  491. if (rhdr->count)
  492. f->flags &= ~Eof;
  493. if(debug & (Dbgproc|Dbgfs))
  494. fprint(2, "readproc:->%F\n", rhdr);
  495. n = convS2M(rhdr, mdata, messagesize);
  496. if(write(mfd[1], mdata, n) != n)
  497. sysfatal("mount write");
  498. flush:
  499. w->tag = NOTAG;
  500. f->readers--;
  501. assert(f->readers == 0);
  502. free(rhdr);
  503. w->rhdr = nil;
  504. qunlock(f);
  505. sendp(procchan, w);
  506. }
  507. threadexits(nil);
  508. }
  509. char*
  510. rread(Fid *f)
  511. {
  512. long off;
  513. int i, n, cnt, rec;
  514. char *p;
  515. static char buf[1024];
  516. Audiocontrol *c;
  517. Audioctldata *a;
  518. Worker *w;
  519. Nexus *nx;
  520. rhdr.count = 0;
  521. off = thdr.offset;
  522. cnt = thdr.count;
  523. if(cnt > messagesize - IOHDRSZ)
  524. cnt = messagesize - IOHDRSZ;
  525. rhdr.data = (char*)mbuf;
  526. if(f->dir == &dirs[Qdir]){
  527. n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
  528. rhdr.count = n;
  529. return nil;
  530. }
  531. if(f->dir == &dirs[Qvolume]){
  532. p = buf;
  533. n = sizeof buf;
  534. for (rec = 0; rec < 2; rec++) {
  535. nx = nexus[rec];
  536. if(nx == nil)
  537. continue;
  538. c = &nx->control[Volume_control];
  539. if (c->readable){
  540. i = snprint(p, n, "audio %s %ld\n", rec?"in":"out", (c->min != Undef) ?
  541. 100*(c->value[0]-c->min)/(c->max-c->min) : c->value[0]);
  542. p+=i; n-=i;
  543. }
  544. c = &nx->control[Mixer_control];
  545. if (c->readable){
  546. i = snprint(p, n, "mixer %s %ld\n", rec?"in":"out", (c->min != Undef) ?
  547. 100*(c->value[0]-c->min)/(c->max-c->min) : c->value[0]);
  548. p+=i; n-=i;
  549. }
  550. c = &nx->control[Treble_control];
  551. if (c->readable){
  552. i = snprint(p, n, "treb %s %ld\n", rec?"in":"out", (c->min != Undef) ?
  553. 100*(c->value[0]-c->min)/(c->max-c->min) : c->value[0]);
  554. p+=i; n-=i;
  555. }
  556. c = &nx->control[Bass_control];
  557. if (c->readable){
  558. i = snprint(p, n, "bass %s %ld\n", rec?"in":"out", (c->min != Undef) ?
  559. 100*(c->value[0]-c->min)/(c->max-c->min) : c->value[0]);
  560. p+=i; n-=i;
  561. }
  562. c = &nx->control[Speed_control];
  563. if (c->readable){
  564. i = snprint(p, n, "speed %s %ld\n", rec?"in":"out", c->value[0]);
  565. p+=i; n-=i;
  566. }
  567. }
  568. n = sizeof buf - n;
  569. if (off > n)
  570. rhdr.count = 0;
  571. else{
  572. rhdr.data = buf + off;
  573. rhdr.count = n - off;
  574. if (rhdr.count > cnt)
  575. rhdr.count = cnt;
  576. }
  577. return nil;
  578. }
  579. if(f->dir == &dirs[Qaudioctl]){
  580. Fcall *hdr;
  581. qlock(f);
  582. a = f->fiddata;
  583. if (off - a->offoff < 0){
  584. /* there was a seek */
  585. a->offoff = off;
  586. a->ns = 0;
  587. }
  588. do {
  589. if (off - a->offoff < a->ns){
  590. rhdr.data = a->s + (off - a->offoff);
  591. rhdr.count = a->ns - (off - a->offoff);
  592. if (rhdr.count > cnt)
  593. rhdr.count = cnt;
  594. qunlock(f);
  595. return nil;
  596. }
  597. if (a->offoff != off){
  598. a->ns = 0;
  599. a->offoff = off;
  600. rhdr.count = 0;
  601. qunlock(f);
  602. return nil;
  603. }
  604. } while (makeaudioctldata(f) != 0);
  605. assert(a->offoff == off);
  606. /* Wait for data off line */
  607. f->readers++;
  608. w = nbrecvp(procchan);
  609. if (w == nil){
  610. w = emallocz(sizeof(Worker), 1);
  611. w->eventc = chancreate(sizeof(ulong), 1);
  612. w->next = workers;
  613. workers = w;
  614. proccreate(readproc, w, 4096);
  615. }
  616. hdr = emalloc(sizeof(Fcall));
  617. w->fid = f;
  618. w->tag = thdr.tag;
  619. assert(w->rhdr == nil);
  620. w->rhdr = hdr;
  621. hdr->count = cnt;
  622. hdr->offset = off;
  623. hdr->type = thdr.type+1;
  624. hdr->fid = thdr.fid;
  625. hdr->tag = thdr.tag;
  626. sendul(w->eventc, Work);
  627. return (char*)~0;
  628. }
  629. return Eperm;
  630. }
  631. char*
  632. rwrite(Fid *f)
  633. {
  634. long cnt, value;
  635. char *lines[2*Ncontrol], *fields[4], *subfields[9], *err, *p;
  636. int nlines, i, nf, nnf, rec;
  637. Audiocontrol *c;
  638. Worker *w;
  639. static char buf[256];
  640. rhdr.count = 0;
  641. cnt = thdr.count;
  642. if(cnt > messagesize - IOHDRSZ)
  643. cnt = messagesize - IOHDRSZ;
  644. err = nil;
  645. if(f->dir == &dirs[Qvolume] || f->dir == &dirs[Qaudioctl]){
  646. thdr.data[cnt] = '\0';
  647. nlines = getfields(thdr.data, lines, 2*Ncontrol, 1, "\n");
  648. for(i = 0; i < nlines; i++){
  649. if (debug) fprint(2, "line: %s\n", lines[i]);
  650. nf = tokenize(lines[i], fields, 4);
  651. if (nf == 0)
  652. continue;
  653. if (nf == 3){
  654. if (strcmp(fields[1], "in") == 0 || strcmp(fields[1], "record") == 0)
  655. rec = 1;
  656. else if (strcmp(fields[1], "out") == 0 || strcmp(fields[1], "playback") == 0)
  657. rec = 0;
  658. else {
  659. if (debug) fprint(2, "bad1\n");
  660. return Ebadctl;
  661. }
  662. }else if (nf == 2)
  663. rec = 0;
  664. else {
  665. if (debug) fprint(2, "bad2 %d\n", nf);
  666. return Ebadctl;
  667. }
  668. if (strcmp(fields[0], "audio") == 0) /* special case */
  669. fields[0] = "volume";
  670. c = findcontrol(nexus[rec], fields[0]);
  671. if (c == nil){
  672. if (debug) fprint(2, "bad3\n");
  673. return Ebadctl;
  674. }
  675. if (f->dir == &dirs[Qvolume] && c->min != Undef && c->max != Undef){
  676. nnf = tokenize(fields[nf-1], subfields, nelem(subfields));
  677. if (nnf <= 0 || nnf > 8){
  678. if (debug) fprint(2, "bad4\n");
  679. return Ebadctl;
  680. }
  681. p = buf;
  682. for (i = 0; i < nnf; i++){
  683. value = strtol(subfields[i], nil, 0);
  684. value = ((100 - value) * c->min + value * c->max) / 100;
  685. if (debug) {
  686. if (p == buf)
  687. fprint(2, "rwrite: %s %s '%ld",
  688. fields[0], rec?"record":"playback", value);
  689. else
  690. fprint(2, " %ld", value);
  691. }
  692. if (p == buf)
  693. p = seprint(p, buf+sizeof buf, "0x%p %s %s '%ld",
  694. replchan, fields[0], rec?"record":"playback", value);
  695. else
  696. p = seprint(p, buf+sizeof buf, " %ld", value);
  697. }
  698. if (debug) fprint(2, "'\n");
  699. seprint(p, buf+sizeof buf, "'");
  700. chanprint(controlchan, buf);
  701. } else {
  702. if (debug) fprint(2, "rwrite: %s %s %q", fields[0], rec?"record":"playback", fields[nf-1]);
  703. chanprint(controlchan, "0x%p %s %s %q", replchan, fields[0], rec?"record":"playback", fields[nf-1]);
  704. }
  705. p = recvp(replchan);
  706. if (p){
  707. if (strcmp(p, "ok") == 0){
  708. free(p);
  709. p = nil;
  710. }
  711. if (err == nil)
  712. err = p;
  713. }
  714. }
  715. for (w = workers; w; w = w->next)
  716. nbsendul(w->eventc, Qaudioctl << 16 | Check);
  717. rhdr.count = thdr.count;
  718. return err;
  719. }
  720. return Eperm;
  721. }
  722. char *
  723. rclunk(Fid *f)
  724. {
  725. Audioctldata *a;
  726. qlock(f);
  727. f->flags &= ~(Open|Busy);
  728. assert (f->readers ==0);
  729. if (f->fiddata){
  730. a = f->fiddata;
  731. if (a->s)
  732. free(a->s);
  733. free(a);
  734. f->fiddata = nil;
  735. }
  736. qunlock(f);
  737. return 0;
  738. }
  739. char *
  740. rremove(Fid *)
  741. {
  742. return Eperm;
  743. }
  744. char *
  745. rstat(Fid *f)
  746. {
  747. Audioctldata *a;
  748. if (f->dir == &dirs[Qaudio] && nexus[Play] == nil)
  749. return Enotexist;
  750. if (f->dir == &dirs[Qaudioin] && nexus[Record] == nil)
  751. return Enotexist;
  752. if (f->dir == &dirs[Qaudioctl]){
  753. qlock(f);
  754. if (f->fiddata == nil)
  755. f->fiddata = allocaudioctldata();
  756. a = f->fiddata;
  757. if (a->ns == 0)
  758. makeaudioctldata(f);
  759. f->dir->length = a->offoff + a->ns;
  760. qunlock(f);
  761. }
  762. rhdr.nstat = convD2M(f->dir, mbuf, messagesize - IOHDRSZ);
  763. rhdr.stat = mbuf;
  764. return 0;
  765. }
  766. char *
  767. rwstat(Fid*)
  768. {
  769. return Eperm;
  770. }
  771. Fid *
  772. newfid(int fid)
  773. {
  774. Fid *f, *ff;
  775. ff = nil;
  776. for(f = fids; f; f = f->next)
  777. if(f->fid == fid){
  778. return f;
  779. }else if(ff == nil && (f->flags & Busy) == 0)
  780. ff = f;
  781. if(ff == nil){
  782. ff = emallocz(sizeof *ff, 1);
  783. ff->next = fids;
  784. fids = ff;
  785. }
  786. ff->fid = fid;
  787. ff->flags &= ~(Busy|Open);
  788. ff->dir = nil;
  789. return ff;
  790. }
  791. void
  792. io(void *)
  793. {
  794. char *err, e[32];
  795. int n;
  796. close(p[1]);
  797. procchan = chancreate(sizeof(Channel*), 8);
  798. replchan = chancreate(sizeof(char*), 0);
  799. for(;;){
  800. /*
  801. * reading from a pipe or a network device
  802. * will give an error after a few eof reads
  803. * however, we cannot tell the difference
  804. * between a zero-length read and an interrupt
  805. * on the processes writing to us,
  806. * so we wait for the error
  807. */
  808. n = read9pmsg(mfd[0], mdata, messagesize);
  809. if(n == 0)
  810. continue;
  811. if(n < 0){
  812. rerrstr(e, sizeof e);
  813. if (strcmp(e, "interrupted") == 0){
  814. if (debug) fprint(2, "read9pmsg interrupted\n");
  815. continue;
  816. }
  817. return;
  818. }
  819. if(convM2S(mdata, n, &thdr) == 0)
  820. continue;
  821. if(debug & Dbgfs)
  822. fprint(2, "io:<-%F\n", &thdr);
  823. rhdr.data = (char*)mdata + messagesize;
  824. if(!fcalls[thdr.type])
  825. err = "bad fcall type";
  826. else
  827. err = (*fcalls[thdr.type])(newfid(thdr.fid));
  828. if (err == (char*)~0)
  829. continue; /* handled off line */
  830. if(err){
  831. rhdr.type = Rerror;
  832. rhdr.ename = err;
  833. }else{
  834. rhdr.type = thdr.type + 1;
  835. rhdr.fid = thdr.fid;
  836. }
  837. rhdr.tag = thdr.tag;
  838. if(debug & Dbgfs)
  839. fprint(2, "io:->%F\n", &rhdr);
  840. n = convS2M(&rhdr, mdata, messagesize);
  841. if(write(mfd[1], mdata, n) != n)
  842. sysfatal("mount write");
  843. }
  844. threadexitsall("die yankee pig dog");
  845. }
  846. int
  847. newid(void)
  848. {
  849. int rv;
  850. static int id;
  851. static Lock idlock;
  852. lock(&idlock);
  853. rv = ++id;
  854. unlock(&idlock);
  855. return rv;
  856. }
  857. void
  858. ctlevent(void)
  859. {
  860. Worker *w;
  861. for (w = workers; w; w = w->next)
  862. nbsendul(w->eventc, Qaudioctl << 16 | Check);
  863. }