audiofs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  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. int attachok;
  11. #define STACKSIZE 16*1024
  12. enum
  13. {
  14. OPERM = 0x3, // mask of all permission types in open mode
  15. };
  16. typedef struct Fid Fid;
  17. typedef struct Audioctldata Audioctldata;
  18. typedef struct Worker Worker;
  19. struct Audioctldata
  20. {
  21. long offoff; // offset of the offset for audioctl
  22. long values[2][Ncontrol][8]; // last values transmitted
  23. char * s;
  24. int ns;
  25. };
  26. enum {
  27. Busy = 0x01,
  28. Open = 0x02,
  29. Eof = 0x04,
  30. };
  31. struct Fid
  32. {
  33. QLock;
  34. int fid;
  35. Dir * dir;
  36. ushort flags;
  37. short readers;
  38. void * fiddata; // file specific per-fid data (used for audioctl)
  39. Fid * next;
  40. };
  41. struct Worker
  42. {
  43. Fid *fid;
  44. ushort tag;
  45. Fcall *rhdr;
  46. Dir *dir;
  47. Channel *eventc;
  48. Worker *next;
  49. };
  50. enum {
  51. // Event channel messages for worker
  52. Work = 0x01,
  53. Check = 0x02,
  54. Flush = 0x03,
  55. };
  56. enum {
  57. Qdir,
  58. Qvolume,
  59. Qaudioctl,
  60. Qaudiostat,
  61. Qaudio,
  62. Qaudioin,
  63. Nqid,
  64. };
  65. Dir dirs[] = {
  66. /* Note: Qaudio{in} used as mount point for /dev/usb/%d/ep%ddata only */
  67. [Qdir] = {0,0,{Qdir, 0,QTDIR},0555|DMDIR,0,0,0, ".", nil,nil,nil},
  68. [Qvolume] = {0,0,{Qvolume, 0,QTFILE},0666,0,0,0, "volume", nil,nil,nil},
  69. [Qaudioctl] = {0,0,{Qaudioctl, 0,QTFILE},0666,0,0,0, "audioctl",nil,nil,nil},
  70. [Qaudiostat] = {0,0,{Qaudiostat, 0,QTFILE},0666,0,0,0, "audiostat",nil,nil,nil},
  71. [Qaudio] = {0,0,{Qaudio, 0,QTFILE},0222,0,0,0, "audio", nil,nil,nil},
  72. [Qaudioin] = {0,0,{Qaudioin, 0,QTFILE},0444,0,0,0, "audioin", nil,nil,nil},
  73. };
  74. int messagesize = 4*1024+IOHDRSZ;
  75. uchar mdata[8*1024+IOHDRSZ];
  76. uchar mbuf[8*1024+IOHDRSZ];
  77. Fcall thdr;
  78. Fcall rhdr;
  79. Worker *workers;
  80. char srvfile[64], mntdir[64], epdata[64], audiofile[64];
  81. int mfd[2], p[2];
  82. char user[32];
  83. char *srvpost;
  84. Channel *procchan;
  85. Channel *replchan;
  86. Fid *fids;
  87. Fid* newfid(int);
  88. void io(void *);
  89. void usage(void);
  90. extern char *mntpt;
  91. char *rflush(Fid*), *rauth(Fid*),
  92. *rattach(Fid*), *rwalk(Fid*),
  93. *ropen(Fid*), *rcreate(Fid*),
  94. *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
  95. *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
  96. *rversion(Fid*);
  97. char *(*fcalls[])(Fid*) = {
  98. [Tflush] rflush,
  99. [Tversion] rversion,
  100. [Tauth] rauth,
  101. [Tattach] rattach,
  102. [Twalk] rwalk,
  103. [Topen] ropen,
  104. [Tcreate] rcreate,
  105. [Tread] rread,
  106. [Twrite] rwrite,
  107. [Tclunk] rclunk,
  108. [Tremove] rremove,
  109. [Tstat] rstat,
  110. [Twstat] rwstat,
  111. };
  112. char Eperm[] = "permission denied";
  113. char Enotdir[] = "not a directory";
  114. char Enoauth[] = "no authentication in ramfs";
  115. char Enotexist[] = "file does not exist";
  116. char Einuse[] = "file in use";
  117. char Eexist[] = "file exists";
  118. char Enotowner[] = "not owner";
  119. char Eisopen[] = "file already open for I/O";
  120. char Excl[] = "exclusive use file already open";
  121. char Ename[] = "illegal name";
  122. char Ebadctl[] = "unknown control message";
  123. int
  124. notifyf(void *, char *s)
  125. {
  126. if(strncmp(s, "interrupt", 9) == 0)
  127. return 1;
  128. return 0;
  129. }
  130. void
  131. post(char *name, char *envname, int srvfd)
  132. {
  133. int fd;
  134. char buf[32];
  135. fd = create(name, OWRITE, attachok?0666:0600);
  136. if(fd < 0)
  137. return;
  138. sprint(buf, "%d",srvfd);
  139. if(write(fd, buf, strlen(buf)) != strlen(buf))
  140. sysfatal("srv write");
  141. close(fd);
  142. putenv(envname, name);
  143. }
  144. void
  145. serve(void *)
  146. {
  147. int i;
  148. ulong t;
  149. if(pipe(p) < 0)
  150. sysfatal("pipe failed");
  151. mfd[0] = p[0];
  152. mfd[1] = p[0];
  153. atnotify(notifyf, 1);
  154. strcpy(user, getuser());
  155. t = time(nil);
  156. for (i = 0; i < Nqid; i++){
  157. dirs[i].uid = user;
  158. dirs[i].gid = user;
  159. dirs[i].muid = user;
  160. dirs[i].atime = t;
  161. dirs[i].mtime = t;
  162. }
  163. if(mntpt == nil){
  164. snprint(mntdir, sizeof(mntdir), "/dev");
  165. mntpt = mntdir;
  166. }
  167. if(debug)
  168. fmtinstall('F', fcallfmt);
  169. procrfork(io, nil, STACKSIZE, RFFDG|RFNAMEG);
  170. close(p[0]); /* don't deadlock if child fails */
  171. if(srvpost){
  172. sprint(srvfile, "/srv/%s", srvpost);
  173. remove(srvfile);
  174. post(srvfile, "usbaudio", p[1]);
  175. }
  176. if(mount(p[1], -1, mntpt, MBEFORE, "") < 0)
  177. sysfatal("mount failed");
  178. if (endpt[Play] >= 0){
  179. sprint(epdata, "#U/usb%d/%d/ep%ddata", ad->ctlrno, ad->id, endpt[Play]);
  180. sprint(audiofile, "%s/audio", mntpt);
  181. if(bind(epdata, audiofile, MREPL) < 0)
  182. sysfatal("bind failed");
  183. }
  184. if (endpt[Record] >= 0){
  185. sprint(epdata, "#U/usb%d/%d/ep%ddata", ad->ctlrno, ad->id, endpt[Record]);
  186. sprint(audiofile, "%s/audioin", mntpt);
  187. if(bind(epdata, audiofile, MREPL) < 0)
  188. sysfatal("bind failed");
  189. }
  190. threadexits(nil);
  191. }
  192. char*
  193. rversion(Fid*)
  194. {
  195. Fid *f;
  196. if(thdr.msize < 256)
  197. return "max messagesize too small";
  198. if(thdr.msize < messagesize)
  199. messagesize = thdr.msize;
  200. rhdr.msize = messagesize;
  201. if(strncmp(thdr.version, "9P2000", 6) != 0)
  202. return "unknown 9P version";
  203. else
  204. rhdr.version = "9P2000";
  205. for(f = fids; f; f = f->next)
  206. if(f->flags & Busy)
  207. rclunk(f);
  208. return nil;
  209. }
  210. char*
  211. rauth(Fid*)
  212. {
  213. return "usbaudio: no authentication required";
  214. }
  215. char*
  216. rflush(Fid *)
  217. {
  218. Worker *w;
  219. int waitflush;
  220. do {
  221. waitflush = 0;
  222. for (w = workers; w; w = w->next)
  223. if (w->tag == thdr.oldtag){
  224. waitflush++;
  225. nbsendul(w->eventc, thdr.oldtag << 16 | Flush);
  226. }
  227. if (waitflush)
  228. sleep(50);
  229. } while(waitflush);
  230. if (debug & Dbgproc)
  231. fprint(2, "flush done on tag %d\n", thdr.oldtag);
  232. return 0;
  233. }
  234. char*
  235. rattach(Fid *f)
  236. {
  237. f->flags |= Busy;
  238. f->dir = &dirs[Qdir];
  239. rhdr.qid = f->dir->qid;
  240. if(attachok == 0 && strcmp(thdr.uname, user) != 0)
  241. return Eperm;
  242. return 0;
  243. }
  244. static Fid*
  245. doclone(Fid *f, int nfid)
  246. {
  247. Fid *nf;
  248. nf = newfid(nfid);
  249. if(nf->flags & Busy)
  250. return nil;
  251. nf->flags |= Busy;
  252. nf->flags &= ~Open;
  253. nf->dir = f->dir;
  254. return nf;
  255. }
  256. char*
  257. dowalk(Fid *f, char *name)
  258. {
  259. int t;
  260. if (strcmp(name, ".") == 0)
  261. return nil;
  262. if (strcmp(name, "..") == 0){
  263. f->dir = &dirs[Qdir];
  264. return nil;
  265. }
  266. if(f->dir != &dirs[Qdir])
  267. return Enotexist;
  268. for (t = 1; t < Nqid; t++){
  269. if (t == Qaudio && endpt[Play] < 0)
  270. continue;
  271. if (t == Qaudioin && endpt[Record] < 0)
  272. continue;
  273. if(strcmp(name, dirs[t].name) == 0){
  274. f->dir = &dirs[t];
  275. return nil;
  276. }
  277. }
  278. return Enotexist;
  279. }
  280. char*
  281. rwalk(Fid *f)
  282. {
  283. Fid *nf;
  284. char *rv;
  285. int i;
  286. Dir *savedir;
  287. if(f->flags & Open)
  288. return Eisopen;
  289. rhdr.nwqid = 0;
  290. nf = nil;
  291. savedir = f->dir;
  292. /* clone if requested */
  293. if(thdr.newfid != thdr.fid){
  294. nf = doclone(f, thdr.newfid);
  295. if(nf == nil)
  296. return "new fid in use";
  297. f = nf;
  298. }
  299. /* if it's just a clone, return */
  300. if(thdr.nwname == 0 && nf != nil)
  301. return nil;
  302. /* walk each element */
  303. rv = nil;
  304. for(i = 0; i < thdr.nwname; i++){
  305. rv = dowalk(f, thdr.wname[i]);
  306. if(rv != nil){
  307. if(nf != nil)
  308. rclunk(nf);
  309. else
  310. f->dir = savedir;
  311. break;
  312. }
  313. rhdr.wqid[i] = f->dir->qid;
  314. }
  315. rhdr.nwqid = i;
  316. /* we only error out if no walk */
  317. if(i > 0)
  318. rv = nil;
  319. return rv;
  320. }
  321. Audioctldata *
  322. allocaudioctldata(void)
  323. {
  324. int i, j, k;
  325. Audioctldata *a;
  326. a = emallocz(sizeof(Audioctldata), 1);
  327. for (i = 0; i < 2; i++)
  328. for(j=0; j < Ncontrol; j++)
  329. for(k=0; k < 8; k++)
  330. a->values[i][j][k] = Undef;
  331. return a;
  332. }
  333. char *
  334. ropen(Fid *f)
  335. {
  336. if(f->flags & Open)
  337. return Eisopen;
  338. if(f->dir == &dirs[Qaudio] || f->dir == &dirs[Qaudioin])
  339. return Eperm;
  340. if(thdr.mode != OREAD && (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 < 8; i++)
  399. if ((c->chans & 1<<i) && c->value[i] != a->values[rec][ctl][i])
  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. }