audiofs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  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,
  180. endpt[Play]);
  181. sprint(audiofile, "%s/audio", mntpt);
  182. if(bind(epdata, audiofile, MREPL) < 0)
  183. sysfatal("bind failed");
  184. }
  185. if (endpt[Record] >= 0){
  186. sprint(epdata, "#U/usb%d/%d/ep%ddata", ad->ctlrno, ad->id,
  187. endpt[Record]);
  188. sprint(audiofile, "%s/audioin", mntpt);
  189. if(bind(epdata, audiofile, MREPL) < 0)
  190. sysfatal("bind failed");
  191. }
  192. threadexits(nil);
  193. }
  194. char*
  195. rversion(Fid*)
  196. {
  197. Fid *f;
  198. if(thdr.msize < 256)
  199. return "max messagesize too small";
  200. if(thdr.msize < messagesize)
  201. messagesize = thdr.msize;
  202. rhdr.msize = messagesize;
  203. if(strncmp(thdr.version, "9P2000", 6) != 0)
  204. return "unknown 9P version";
  205. else
  206. rhdr.version = "9P2000";
  207. for(f = fids; f; f = f->next)
  208. if(f->flags & Busy)
  209. rclunk(f);
  210. return nil;
  211. }
  212. char*
  213. rauth(Fid*)
  214. {
  215. return "usbaudio: no authentication required";
  216. }
  217. char*
  218. rflush(Fid *)
  219. {
  220. Worker *w;
  221. int waitflush;
  222. do {
  223. waitflush = 0;
  224. for (w = workers; w; w = w->next)
  225. if (w->tag == thdr.oldtag){
  226. waitflush++;
  227. nbsendul(w->eventc, thdr.oldtag << 16 | Flush);
  228. }
  229. if (waitflush)
  230. sleep(50);
  231. } while(waitflush);
  232. if (debug & Dbgproc)
  233. fprint(2, "flush done on tag %d\n", thdr.oldtag);
  234. return 0;
  235. }
  236. char*
  237. rattach(Fid *f)
  238. {
  239. f->flags |= Busy;
  240. f->dir = &dirs[Qdir];
  241. rhdr.qid = f->dir->qid;
  242. if(attachok == 0 && strcmp(thdr.uname, user) != 0)
  243. return Eperm;
  244. return 0;
  245. }
  246. static Fid*
  247. doclone(Fid *f, int nfid)
  248. {
  249. Fid *nf;
  250. nf = newfid(nfid);
  251. if(nf->flags & Busy)
  252. return nil;
  253. nf->flags |= Busy;
  254. nf->flags &= ~Open;
  255. nf->dir = f->dir;
  256. return nf;
  257. }
  258. char*
  259. dowalk(Fid *f, char *name)
  260. {
  261. int t;
  262. if (strcmp(name, ".") == 0)
  263. return nil;
  264. if (strcmp(name, "..") == 0){
  265. f->dir = &dirs[Qdir];
  266. return nil;
  267. }
  268. if(f->dir != &dirs[Qdir])
  269. return Enotexist;
  270. for (t = 1; t < Nqid; t++){
  271. if (t == Qaudio && endpt[Play] < 0)
  272. continue;
  273. if (t == Qaudioin && endpt[Record] < 0)
  274. continue;
  275. if(strcmp(name, dirs[t].name) == 0){
  276. f->dir = &dirs[t];
  277. return nil;
  278. }
  279. }
  280. return Enotexist;
  281. }
  282. char*
  283. rwalk(Fid *f)
  284. {
  285. Fid *nf;
  286. char *rv;
  287. int i;
  288. Dir *savedir;
  289. if(f->flags & Open)
  290. return Eisopen;
  291. rhdr.nwqid = 0;
  292. nf = nil;
  293. savedir = f->dir;
  294. /* clone if requested */
  295. if(thdr.newfid != thdr.fid){
  296. nf = doclone(f, thdr.newfid);
  297. if(nf == nil)
  298. return "new fid in use";
  299. f = nf;
  300. }
  301. /* if it's just a clone, return */
  302. if(thdr.nwname == 0 && nf != nil)
  303. return nil;
  304. /* walk each element */
  305. rv = nil;
  306. for(i = 0; i < thdr.nwname; i++){
  307. rv = dowalk(f, thdr.wname[i]);
  308. if(rv != nil){
  309. if(nf != nil)
  310. rclunk(nf);
  311. else
  312. f->dir = savedir;
  313. break;
  314. }
  315. rhdr.wqid[i] = f->dir->qid;
  316. }
  317. rhdr.nwqid = i;
  318. /* we only error out if no walk */
  319. if(i > 0)
  320. rv = nil;
  321. return rv;
  322. }
  323. Audioctldata *
  324. allocaudioctldata(void)
  325. {
  326. int i, j, k;
  327. Audioctldata *a;
  328. a = emallocz(sizeof(Audioctldata), 1);
  329. for (i = 0; i < 2; i++)
  330. for(j=0; j < Ncontrol; j++)
  331. for(k=0; k < 8; k++)
  332. a->values[i][j][k] = Undef;
  333. return a;
  334. }
  335. char *
  336. ropen(Fid *f)
  337. {
  338. if(f->flags & Open)
  339. return Eisopen;
  340. if(f->dir == &dirs[Qaudio] || f->dir == &dirs[Qaudioin])
  341. return Eperm;
  342. if(thdr.mode != OREAD && (f->dir->mode & 0x2) == 0)
  343. return Eperm;
  344. qlock(f);
  345. if(f->dir == &dirs[Qaudioctl] && f->fiddata == nil)
  346. f->fiddata = allocaudioctldata();
  347. qunlock(f);
  348. rhdr.iounit = 0;
  349. rhdr.qid = f->dir->qid;
  350. f->flags |= Open;
  351. return nil;
  352. }
  353. char *
  354. rcreate(Fid*)
  355. {
  356. return Eperm;
  357. }
  358. int
  359. readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
  360. {
  361. int i, m, n;
  362. long pos;
  363. n = 0;
  364. pos = 0;
  365. for (i = 1; i < Nqid; i++){
  366. if (endpt[Play] < 0 && i == Qaudio)
  367. continue;
  368. if (endpt[Record] < 0 && i == Qaudioin)
  369. continue;
  370. m = convD2M(&dirs[i], &buf[n], blen-n);
  371. if(off <= pos){
  372. if(m <= BIT16SZ || m > cnt)
  373. break;
  374. n += m;
  375. cnt -= m;
  376. }
  377. pos += m;
  378. }
  379. return n;
  380. }
  381. enum { Chunk = 1024, };
  382. int
  383. makeaudioctldata(Fid *f)
  384. {
  385. int rec, ctl, i, diff;
  386. long *actls; /* 8 of them */
  387. char *p, *e;
  388. Audiocontrol *c;
  389. Audioctldata *a;
  390. if ((a = f->fiddata) == nil)
  391. sysfatal("fiddata");
  392. if ((p = a->s) == nil)
  393. a->s = p = emalloc(Chunk);
  394. e = p + Chunk - 1; /* e must point *at* last byte, not *after* */
  395. for (rec = 0; rec < 2; rec++)
  396. for (ctl = 0; ctl < Ncontrol; ctl++) {
  397. c = &controls[rec][ctl];
  398. actls = a->values[rec][ctl];
  399. diff = 0;
  400. if (c->chans){
  401. for (i = 1; i < 8; i++)
  402. if ((c->chans & 1<<i) &&
  403. c->value[i] != actls[i])
  404. diff = 1;
  405. }else
  406. if (c->value[0] != actls[0])
  407. diff = 1;
  408. if (diff){
  409. p = seprint(p, e, "%s %s %A", c->name,
  410. rec? "in": "out", c);
  411. memmove(actls, c->value, sizeof c->value);
  412. if (c->min != Undef){
  413. p = seprint(p, e, " %ld %ld", c->min,
  414. c->max);
  415. if (c->step != Undef)
  416. p = seprint(p, e, " %ld",
  417. c->step);
  418. }
  419. p = seprint(p, e, "\n");
  420. }
  421. }
  422. assert(strlen(a->s) < Chunk);
  423. a->ns = p - a->s;
  424. return a->ns;
  425. }
  426. void
  427. readproc(void *x)
  428. {
  429. int n, cnt;
  430. ulong event;
  431. vlong off;
  432. uchar *mdata;
  433. Audioctldata *a;
  434. Fcall *rhdr;
  435. Fid *f;
  436. Worker *w;
  437. w = x;
  438. mdata = emalloc(8*1024+IOHDRSZ);
  439. while(event = recvul(w->eventc)){
  440. if (event != Work)
  441. continue;
  442. f = w->fid;
  443. rhdr = w->rhdr;
  444. a = f->fiddata;
  445. off = rhdr->offset;
  446. cnt = rhdr->count;
  447. assert(a->offoff == off);
  448. /* f is already locked */
  449. for(;;){
  450. qunlock(f);
  451. event = recvul(w->eventc);
  452. qlock(f);
  453. if (debug & Dbgproc)
  454. fprint(2, "readproc unblocked fid %d %lld\n",
  455. f->fid, f->dir->qid.path);
  456. switch (event & 0xffff) {
  457. case Work:
  458. sysfatal("readproc phase error");
  459. case Check:
  460. if (f->fiddata && makeaudioctldata(f) == 0)
  461. continue;
  462. break;
  463. case Flush:
  464. if ((event >> 16) == rhdr->tag) {
  465. if (debug & Dbgproc)
  466. fprint(2, "readproc flushing fid %d, tag %d\n",
  467. f->fid, rhdr->tag);
  468. goto flush;
  469. }
  470. continue;
  471. }
  472. if (f->fiddata){
  473. rhdr->data = a->s;
  474. rhdr->count = a->ns;
  475. break;
  476. }
  477. yield();
  478. }
  479. if (rhdr->count > cnt)
  480. rhdr->count = cnt;
  481. if (rhdr->count)
  482. f->flags &= ~Eof;
  483. if(debug & (Dbgproc|Dbgfs))
  484. fprint(2, "readproc:->%F\n", rhdr);
  485. n = convS2M(rhdr, mdata, messagesize);
  486. if(write(mfd[1], mdata, n) != n)
  487. sysfatal("mount write");
  488. flush:
  489. w->tag = NOTAG;
  490. f->readers--;
  491. assert(f->readers == 0);
  492. free(rhdr);
  493. w->rhdr = nil;
  494. qunlock(f);
  495. sendp(procchan, w);
  496. }
  497. threadexits(nil);
  498. }
  499. char*
  500. rread(Fid *f)
  501. {
  502. int i, n, cnt, rec;
  503. vlong off;
  504. char *p;
  505. Audiocontrol *c;
  506. Audioctldata *a;
  507. Worker *w;
  508. static char buf[1024];
  509. rhdr.count = 0;
  510. off = thdr.offset;
  511. cnt = thdr.count;
  512. if(cnt > messagesize - IOHDRSZ)
  513. cnt = messagesize - IOHDRSZ;
  514. rhdr.data = (char*)mbuf;
  515. if(f->dir == &dirs[Qdir]){
  516. n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
  517. rhdr.count = n;
  518. return nil;
  519. }
  520. if(f->dir == &dirs[Qvolume]){
  521. p = buf;
  522. n = sizeof buf;
  523. for (rec = 0; rec < 2; rec++){
  524. c = &controls[rec][Volume_control];
  525. if (c->readable){
  526. i = snprint(p, n, "audio %s %ld\n",
  527. rec? "in": "out", (c->min != Undef?
  528. 100*(c->value[0]-c->min)/(c->max-c->min):
  529. c->value[0]));
  530. p += i;
  531. n -= i;
  532. }
  533. c = &controls[rec][Treble_control];
  534. if (c->readable){
  535. i = snprint(p, n, "treb %s %ld\n",
  536. rec? "in": "out", (c->min != Undef?
  537. 100*(c->value[0]-c->min)/(c->max-c->min):
  538. c->value[0]));
  539. p += i;
  540. n -= i;
  541. }
  542. c = &controls[rec][Bass_control];
  543. if (c->readable){
  544. i = snprint(p, n, "bass %s %ld\n",
  545. rec? "in": "out", (c->min != Undef?
  546. 100*(c->value[0]-c->min)/(c->max-c->min):
  547. c->value[0]));
  548. p += i;
  549. n -= i;
  550. }
  551. c = &controls[rec][Speed_control];
  552. if (c->readable){
  553. i = snprint(p, n, "speed %s %ld\n",
  554. rec? "in": "out", c->value[0]);
  555. p += i;
  556. n -= i;
  557. }
  558. }
  559. n = sizeof buf - n;
  560. if (off > n)
  561. rhdr.count = 0;
  562. else{
  563. rhdr.data = buf + off;
  564. rhdr.count = n - off;
  565. if (rhdr.count > cnt)
  566. rhdr.count = cnt;
  567. }
  568. return nil;
  569. }
  570. if(f->dir == &dirs[Qaudioctl]){
  571. Fcall *hdr;
  572. qlock(f);
  573. a = f->fiddata;
  574. if (off - a->offoff < 0){
  575. /* there was a seek */
  576. a->offoff = off;
  577. a->ns = 0;
  578. }
  579. do {
  580. if (off - a->offoff < a->ns){
  581. rhdr.data = a->s + (off - a->offoff);
  582. rhdr.count = a->ns - (off - a->offoff);
  583. if (rhdr.count > cnt)
  584. rhdr.count = cnt;
  585. qunlock(f);
  586. return nil;
  587. }
  588. if (a->offoff != off){
  589. a->ns = 0;
  590. a->offoff = off;
  591. rhdr.count = 0;
  592. qunlock(f);
  593. return nil;
  594. }
  595. } while (makeaudioctldata(f) != 0);
  596. assert(a->offoff == off);
  597. /* Wait for data off line */
  598. f->readers++;
  599. w = nbrecvp(procchan);
  600. if (w == nil){
  601. w = emallocz(sizeof(Worker), 1);
  602. w->eventc = chancreate(sizeof(ulong), 1);
  603. w->next = workers;
  604. workers = w;
  605. proccreate(readproc, w, 4096);
  606. }
  607. hdr = emalloc(sizeof(Fcall));
  608. w->fid = f;
  609. w->tag = thdr.tag;
  610. assert(w->rhdr == nil);
  611. w->rhdr = hdr;
  612. hdr->count = cnt;
  613. hdr->offset = off;
  614. hdr->type = thdr.type+1;
  615. hdr->fid = thdr.fid;
  616. hdr->tag = thdr.tag;
  617. sendul(w->eventc, Work);
  618. return (char*)~0;
  619. }
  620. return Eperm;
  621. }
  622. char*
  623. rwrite(Fid *f)
  624. {
  625. long cnt, value;
  626. char *lines[2*Ncontrol], *fields[4], *subfields[9], *err, *p;
  627. int nlines, i, nf, nnf, rec, ctl;
  628. Audiocontrol *c;
  629. Worker *w;
  630. static char buf[256];
  631. rhdr.count = 0;
  632. cnt = thdr.count;
  633. if(cnt > messagesize - IOHDRSZ)
  634. cnt = messagesize - IOHDRSZ;
  635. err = nil;
  636. if(f->dir == &dirs[Qvolume] || f->dir == &dirs[Qaudioctl]){
  637. thdr.data[cnt] = '\0';
  638. nlines = getfields(thdr.data, lines, 2*Ncontrol, 1, "\n");
  639. for(i = 0; i < nlines; i++){
  640. if (debug)
  641. fprint(2, "line: %s\n", lines[i]);
  642. nf = tokenize(lines[i], fields, 4);
  643. if (nf == 0)
  644. continue;
  645. if (nf == 3)
  646. if (strcmp(fields[1], "in") == 0 ||
  647. strcmp(fields[1], "record") == 0)
  648. rec = 1;
  649. else if (strcmp(fields[1], "out") == 0 ||
  650. strcmp(fields[1], "playback") == 0)
  651. rec = 0;
  652. else {
  653. if (debug)
  654. fprint(2, "bad1\n");
  655. return Ebadctl;
  656. }
  657. else if (nf == 2)
  658. rec = 0;
  659. else {
  660. if (debug)
  661. fprint(2, "bad2 %d\n", nf);
  662. return Ebadctl;
  663. }
  664. c = nil;
  665. if (strcmp(fields[0], "audio") == 0) /* special case */
  666. fields[0] = "volume";
  667. for (ctl = 0; ctl < Ncontrol; ctl++){
  668. c = &controls[rec][ctl];
  669. if (strcmp(fields[0], c->name) == 0)
  670. break;
  671. }
  672. if (ctl == Ncontrol){
  673. if (debug)
  674. fprint(2, "bad3\n");
  675. return Ebadctl;
  676. }
  677. if (f->dir == &dirs[Qvolume] && ctl != Speed_control &&
  678. c->min != Undef && c->max != Undef){
  679. nnf = tokenize(fields[nf-1], subfields,
  680. nelem(subfields));
  681. if (nnf <= 0 || nnf > 8){
  682. if (debug)
  683. fprint(2, "bad4\n");
  684. return Ebadctl;
  685. }
  686. p = buf;
  687. for (i = 0; i < nnf; i++){
  688. value = strtol(subfields[i], nil, 0);
  689. value = ((100 - value)*c->min +
  690. value*c->max) / 100;
  691. if (debug)
  692. if (p == buf)
  693. fprint(2, "rwrite: %s %s '%ld",
  694. c->name, rec?
  695. "record":
  696. "playback",
  697. value);
  698. else
  699. fprint(2, " %ld", value);
  700. if (p == buf)
  701. p = seprint(p, buf+sizeof buf,
  702. "0x%p %s %s '%ld",
  703. replchan, c->name, rec?
  704. "record": "playback",
  705. value);
  706. else
  707. p = seprint(p, buf+sizeof buf,
  708. " %ld", value);
  709. }
  710. if (debug)
  711. fprint(2, "'\n");
  712. seprint(p, buf+sizeof buf-1, "'");
  713. chanprint(controlchan, buf);
  714. } else {
  715. if (debug)
  716. fprint(2, "rwrite: %s %s %q", c->name,
  717. rec? "record": "playback",
  718. fields[nf-1]);
  719. chanprint(controlchan, "0x%p %s %s %q",
  720. replchan, c->name, rec? "record":
  721. "playback", fields[nf-1]);
  722. }
  723. p = recvp(replchan);
  724. if (p){
  725. if (strcmp(p, "ok") == 0){
  726. free(p);
  727. p = nil;
  728. }
  729. if (err == nil)
  730. err = p;
  731. }
  732. }
  733. for (w = workers; w; w = w->next)
  734. nbsendul(w->eventc, Qaudioctl << 16 | Check);
  735. rhdr.count = thdr.count;
  736. return err;
  737. }
  738. return Eperm;
  739. }
  740. char *
  741. rclunk(Fid *f)
  742. {
  743. Audioctldata *a;
  744. qlock(f);
  745. f->flags &= ~(Open|Busy);
  746. assert(f->readers ==0);
  747. if (f->fiddata){
  748. a = f->fiddata;
  749. if (a->s)
  750. free(a->s);
  751. free(a);
  752. f->fiddata = nil;
  753. }
  754. qunlock(f);
  755. return 0;
  756. }
  757. char *
  758. rremove(Fid *)
  759. {
  760. return Eperm;
  761. }
  762. char *
  763. rstat(Fid *f)
  764. {
  765. Audioctldata *a;
  766. if (f->dir == &dirs[Qaudio] && endpt[Play] < 0)
  767. return Enotexist;
  768. if (f->dir == &dirs[Qaudioin] && endpt[Record] < 0)
  769. return Enotexist;
  770. if (f->dir == &dirs[Qaudioctl]){
  771. qlock(f);
  772. if (f->fiddata == nil)
  773. f->fiddata = allocaudioctldata();
  774. a = f->fiddata;
  775. if (a->ns == 0)
  776. makeaudioctldata(f);
  777. f->dir->length = a->offoff + a->ns;
  778. qunlock(f);
  779. }
  780. rhdr.nstat = convD2M(f->dir, mbuf, messagesize - IOHDRSZ);
  781. rhdr.stat = mbuf;
  782. return 0;
  783. }
  784. char *
  785. rwstat(Fid*)
  786. {
  787. return Eperm;
  788. }
  789. Fid *
  790. newfid(int fid)
  791. {
  792. Fid *f, *ff;
  793. ff = nil;
  794. for(f = fids; f; f = f->next)
  795. if(f->fid == fid)
  796. return f;
  797. else if(ff == nil && (f->flags & Busy) == 0)
  798. ff = f;
  799. if(ff == nil){
  800. ff = emallocz(sizeof *ff, 1);
  801. ff->next = fids;
  802. fids = ff;
  803. }
  804. ff->fid = fid;
  805. ff->flags &= ~(Busy|Open);
  806. ff->dir = nil;
  807. return ff;
  808. }
  809. void
  810. io(void *)
  811. {
  812. char *err, e[32];
  813. int n;
  814. close(p[1]);
  815. procchan = chancreate(sizeof(Channel*), 8);
  816. replchan = chancreate(sizeof(char*), 0);
  817. for(;;){
  818. /*
  819. * reading from a pipe or a network device
  820. * will give an error after a few eof reads
  821. * however, we cannot tell the difference
  822. * between a zero-length read and an interrupt
  823. * on the processes writing to us,
  824. * so we wait for the error
  825. */
  826. n = read9pmsg(mfd[0], mdata, messagesize);
  827. if(n == 0)
  828. continue;
  829. if(n < 0){
  830. rerrstr(e, sizeof e);
  831. if (strcmp(e, "interrupted") == 0){
  832. if (debug)
  833. fprint(2, "read9pmsg interrupted\n");
  834. continue;
  835. }
  836. return;
  837. }
  838. if(convM2S(mdata, n, &thdr) == 0)
  839. continue;
  840. if(debug & Dbgfs)
  841. fprint(2, "io:<-%F\n", &thdr);
  842. rhdr.data = (char*)mdata + messagesize;
  843. if(!fcalls[thdr.type])
  844. err = "bad fcall type";
  845. else
  846. err = (*fcalls[thdr.type])(newfid(thdr.fid));
  847. if (err == (char*)~0)
  848. continue; /* handled off line */
  849. if(err){
  850. rhdr.type = Rerror;
  851. rhdr.ename = err;
  852. }else{
  853. rhdr.type = thdr.type + 1;
  854. rhdr.fid = thdr.fid;
  855. }
  856. rhdr.tag = thdr.tag;
  857. if(debug & Dbgfs)
  858. fprint(2, "io:->%F\n", &rhdr);
  859. n = convS2M(&rhdr, mdata, messagesize);
  860. if(write(mfd[1], mdata, n) != n)
  861. sysfatal("mount write");
  862. }
  863. }
  864. int
  865. newid(void)
  866. {
  867. int rv;
  868. static int id;
  869. static Lock idlock;
  870. lock(&idlock);
  871. rv = ++id;
  872. unlock(&idlock);
  873. return rv;
  874. }
  875. void
  876. ctlevent(void)
  877. {
  878. Worker *w;
  879. for (w = workers; w; w = w->next)
  880. nbsendul(w->eventc, Qaudioctl << 16 | Check);
  881. }