audiofs.c 18 KB

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