Annotation of src/usr.bin/aucat/sock.c, Revision 1.35
1.35 ! ratchov 1: /* $OpenBSD: sock.c,v 1.34 2009/10/27 22:41:03 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: /*
18: * TODO:
19: *
20: * change f->bufsz to contain only socket-side buffer,
21: * because it's less error prone
22: */
23:
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
1.20 ratchov 27:
28: #include "abuf.h"
1.1 ratchov 29: #include "aproc.h"
1.20 ratchov 30: #include "conf.h"
1.1 ratchov 31: #include "dev.h"
1.19 ratchov 32: #include "midi.h"
33: #include "opt.h"
1.20 ratchov 34: #include "sock.h"
1.1 ratchov 35:
36: int sock_attach(struct sock *, int);
37: int sock_read(struct sock *);
38: int sock_write(struct sock *);
39: int sock_execmsg(struct sock *);
40: void sock_reset(struct sock *);
41:
42: struct fileops sock_ops = {
43: "sock",
44: sizeof(struct sock),
45: pipe_close,
46: pipe_read,
47: pipe_write,
48: NULL, /* start */
49: NULL, /* stop */
50: pipe_nfds,
51: pipe_pollfd,
52: pipe_revents
53: };
1.30 ratchov 54:
1.1 ratchov 55:
1.34 ratchov 56: void sock_setvol(void *, unsigned);
1.35 ! ratchov 57: void sock_startreq(void *);
1.34 ratchov 58:
59: struct ctl_ops ctl_sockops = {
60: sock_setvol,
1.35 ! ratchov 61: sock_startreq
1.34 ratchov 62: };
63:
1.1 ratchov 64: void
65: rsock_done(struct aproc *p)
66: {
67: struct sock *f = (struct sock *)p->u.io.file;
68:
1.11 ratchov 69: if (f == NULL)
70: return;
1.1 ratchov 71: sock_reset(f);
72: f->pipe.file.rproc = NULL;
73: if (f->pipe.file.wproc) {
1.34 ratchov 74: if (f->slot >= 0)
1.24 ratchov 75: ctl_slotdel(dev_midi, f->slot);
1.1 ratchov 76: aproc_del(f->pipe.file.wproc);
77: file_del(&f->pipe.file);
78: }
1.11 ratchov 79: p->u.io.file = NULL;
1.1 ratchov 80: }
81:
82: int
83: rsock_in(struct aproc *p, struct abuf *ibuf_dummy)
84: {
85: struct sock *f = (struct sock *)p->u.io.file;
86: struct abuf *obuf;
87:
88: if (!sock_read(f))
89: return 0;
90: obuf = LIST_FIRST(&p->obuflist);
1.34 ratchov 91: if (obuf && f->pstate >= SOCK_RUN) {
1.1 ratchov 92: if (!abuf_flush(obuf))
93: return 0;
94: }
95: return 1;
96: }
97:
98: int
99: rsock_out(struct aproc *p, struct abuf *obuf)
100: {
101: struct sock *f = (struct sock *)p->u.io.file;
102:
1.19 ratchov 103: if (f->pipe.file.state & FILE_RINUSE)
1.1 ratchov 104: return 0;
105:
1.12 ratchov 106: /*
1.20 ratchov 107: * When calling sock_read(), we may receive a ``STOP'' command,
1.1 ratchov 108: * and detach ``obuf''. In this case, there's no more caller and
1.20 ratchov 109: * we'll stop processing further messages, resulting in a deadlock.
1.1 ratchov 110: * The solution is to iterate over sock_read() in order to
111: * consume all messages().
112: */
113: for (;;) {
114: if (!sock_read(f))
1.12 ratchov 115: return 0;
1.1 ratchov 116: }
117: return 1;
118: }
119:
120: void
121: rsock_eof(struct aproc *p, struct abuf *ibuf_dummy)
122: {
123: aproc_del(p);
124: }
125:
126: void
127: rsock_hup(struct aproc *p, struct abuf *ibuf)
128: {
129: aproc_del(p);
130: }
131:
132: void
133: rsock_opos(struct aproc *p, struct abuf *obuf, int delta)
134: {
135: struct sock *f = (struct sock *)p->u.io.file;
136:
1.15 ratchov 137: if (f->mode & AMSG_REC)
1.14 ratchov 138: return;
139:
140: f->delta += delta;
141: f->tickpending++;
1.1 ratchov 142: for (;;) {
143: if (!sock_write(f))
144: break;
145: }
146: }
147:
148: struct aproc_ops rsock_ops = {
149: "rsock",
150: rsock_in,
151: rsock_out,
152: rsock_eof,
153: rsock_hup,
154: NULL, /* newin */
155: NULL, /* newout */
156: NULL, /* ipos */
157: rsock_opos,
158: rsock_done
159: };
160:
161: void
162: wsock_done(struct aproc *p)
163: {
164: struct sock *f = (struct sock *)p->u.io.file;
165:
1.11 ratchov 166: if (f == NULL)
167: return;
1.1 ratchov 168: sock_reset(f);
169: f->pipe.file.wproc = NULL;
170: if (f->pipe.file.rproc) {
1.34 ratchov 171: if (f->slot >= 0)
1.24 ratchov 172: ctl_slotdel(dev_midi, f->slot);
1.1 ratchov 173: aproc_del(f->pipe.file.rproc);
174: file_del(&f->pipe.file);
175: }
1.11 ratchov 176: p->u.io.file = NULL;
1.1 ratchov 177: }
178:
179: int
180: wsock_in(struct aproc *p, struct abuf *ibuf)
181: {
182: struct sock *f = (struct sock *)p->u.io.file;
183:
1.19 ratchov 184: if (f->pipe.file.state & FILE_WINUSE)
1.1 ratchov 185: return 0;
186: /*
1.20 ratchov 187: * See remark in rsock_out().
1.1 ratchov 188: */
189: for (;;) {
190: if (!sock_write(f))
191: return 0;
192: }
193: return 1;
194: }
195:
196: int
197: wsock_out(struct aproc *p, struct abuf *obuf_dummy)
198: {
199: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
200: struct sock *f = (struct sock *)p->u.io.file;
201:
202: if (ibuf) {
203: if (!abuf_fill(ibuf))
204: return 0;
205: }
206: if (!sock_write(f))
207: return 0;
208: return 1;
209: }
210:
211: void
212: wsock_eof(struct aproc *p, struct abuf *obuf)
213: {
214: aproc_del(p);
215: }
216:
217: void
218: wsock_hup(struct aproc *p, struct abuf *obuf_dummy)
219: {
220: aproc_del(p);
221: }
222:
223: void
224: wsock_ipos(struct aproc *p, struct abuf *obuf, int delta)
225: {
226: struct sock *f = (struct sock *)p->u.io.file;
227:
1.14 ratchov 228: if (!(f->mode & AMSG_REC))
229: return;
1.1 ratchov 230:
1.14 ratchov 231: f->delta += delta;
1.33 ratchov 232: f->tickpending++;
1.1 ratchov 233: for (;;) {
234: if (!sock_write(f))
235: break;
236: }
237: }
238:
239: struct aproc_ops wsock_ops = {
240: "wsock",
241: wsock_in,
242: wsock_out,
243: wsock_eof,
244: wsock_hup,
245: NULL, /* newin */
246: NULL, /* newout */
247: wsock_ipos,
248: NULL, /* opos */
249: wsock_done
250: };
251:
252: /*
1.20 ratchov 253: * Initialise socket in the SOCK_HELLO state with default
254: * parameters.
1.1 ratchov 255: */
256: struct sock *
1.19 ratchov 257: sock_new(struct fileops *ops, int fd)
1.1 ratchov 258: {
259: struct aproc *rproc, *wproc;
260: struct sock *f;
261:
1.19 ratchov 262: f = (struct sock *)pipe_new(ops, fd, "sock");
1.13 ratchov 263: if (f == NULL)
264: return NULL;
1.18 ratchov 265: f->pstate = SOCK_HELLO;
1.1 ratchov 266: f->mode = 0;
1.19 ratchov 267: f->opt = opt_byname("default");
268: if (f->opt) {
1.31 ratchov 269: if (dev_sub)
1.19 ratchov 270: f->wpar = f->opt->wpar;
1.31 ratchov 271: if (dev_mix)
1.19 ratchov 272: f->rpar = f->opt->rpar;
1.1 ratchov 273: }
274: f->xrun = AMSG_IGNORE;
1.10 ratchov 275: f->bufsz = dev_bufsz;
1.1 ratchov 276: f->round = dev_round;
1.14 ratchov 277: f->delta = 0;
278: f->tickpending = 0;
1.25 ratchov 279: f->vol = f->lastvol = MIDI_MAXCTL;
1.24 ratchov 280: f->slot = -1;
1.1 ratchov 281:
1.19 ratchov 282: wproc = aproc_new(&wsock_ops, f->pipe.file.name);
1.1 ratchov 283: wproc->u.io.file = &f->pipe.file;
284: f->pipe.file.wproc = wproc;
285: f->wstate = SOCK_WIDLE;
286: f->wtodo = 0xdeadbeef;
287:
1.19 ratchov 288: rproc = aproc_new(&rsock_ops, f->pipe.file.name);
1.1 ratchov 289: rproc->u.io.file = &f->pipe.file;
290: f->pipe.file.rproc = rproc;
291: f->rstate = SOCK_RMSG;
292: f->rtodo = sizeof(struct amsg);
293: return f;
294: }
295:
296: /*
1.20 ratchov 297: * Free buffers.
1.1 ratchov 298: */
299: void
300: sock_freebuf(struct sock *f)
301: {
302: struct abuf *rbuf, *wbuf;
1.12 ratchov 303:
1.1 ratchov 304: f->pstate = SOCK_INIT;
1.35 ! ratchov 305: wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
1.1 ratchov 306: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
1.35 ! ratchov 307: if (rbuf || wbuf)
! 308: ctl_slotstop(dev_midi, f->slot);
1.1 ratchov 309: if (rbuf)
310: abuf_eof(rbuf);
311: if (wbuf)
312: abuf_hup(wbuf);
1.32 ratchov 313: f->tickpending = 0;
1.1 ratchov 314: }
315:
316: /*
1.20 ratchov 317: * Allocate buffers, so client can start filling write-end.
1.1 ratchov 318: */
319: void
320: sock_allocbuf(struct sock *f)
321: {
322: struct abuf *rbuf = NULL, *wbuf = NULL;
323:
324: if (f->mode & AMSG_PLAY) {
1.10 ratchov 325: rbuf = abuf_new(f->bufsz, &f->rpar);
1.1 ratchov 326: aproc_setout(f->pipe.file.rproc, rbuf);
327: }
328: if (f->mode & AMSG_REC) {
1.10 ratchov 329: wbuf = abuf_new(f->bufsz, &f->wpar);
1.1 ratchov 330: aproc_setin(f->pipe.file.wproc, wbuf);
331: }
1.14 ratchov 332: f->delta = 0;
333: f->tickpending = 0;
1.1 ratchov 334: f->pstate = SOCK_START;
1.35 ! ratchov 335: if (!(f->mode & AMSG_PLAY) && ctl_slotstart(dev_midi, f->slot))
1.1 ratchov 336: (void)sock_attach(f, 0);
337: }
338:
339: /*
1.25 ratchov 340: * Set volume. Callback invoked when volume is modified externally
1.3 ratchov 341: */
342: void
1.25 ratchov 343: sock_setvol(void *arg, unsigned vol)
1.3 ratchov 344: {
1.25 ratchov 345: struct sock *f = (struct sock *)arg;
1.3 ratchov 346: struct abuf *rbuf;
1.12 ratchov 347:
1.3 ratchov 348: f->vol = vol;
1.12 ratchov 349: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
1.3 ratchov 350: if (!rbuf) {
351: return;
352: }
1.25 ratchov 353: dev_setvol(rbuf, MIDI_TO_ADATA(vol));
1.3 ratchov 354: }
355:
356: /*
1.35 ! ratchov 357: * Attach the stream. Callback invoked when MMC start
! 358: */
! 359: void
! 360: sock_startreq(void *arg)
! 361: {
! 362: struct sock *f = (struct sock *)arg;
! 363:
! 364: (void)sock_attach(f, 0);
! 365: }
! 366:
! 367: /*
1.20 ratchov 368: * Attach play and/or record buffers to dev_mix and/or dev_sub.
1.1 ratchov 369: */
370: int
371: sock_attach(struct sock *f, int force)
372: {
373: struct abuf *rbuf, *wbuf;
374:
375: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
376: wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
377:
378: /*
1.20 ratchov 379: * If in SOCK_START state, dont attach until
380: * the buffer isn't completely filled.
1.1 ratchov 381: */
382: if (!force && rbuf && ABUF_WOK(rbuf))
383: return 0;
1.12 ratchov 384:
1.1 ratchov 385: f->pstate = SOCK_RUN;
386:
387: /*
1.20 ratchov 388: * Attach them to the device.
1.1 ratchov 389: */
390: dev_attach(f->pipe.file.name,
391: (f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun,
1.4 ratchov 392: (f->mode & AMSG_REC) ? wbuf : NULL, &f->wpar, f->xrun,
1.19 ratchov 393: f->opt->maxweight);
1.3 ratchov 394: if (f->mode & AMSG_PLAY)
1.25 ratchov 395: dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
1.3 ratchov 396:
1.1 ratchov 397: /*
1.20 ratchov 398: * Send the initial position, if needed.
1.1 ratchov 399: */
400: for (;;) {
401: if (!sock_write(f))
402: break;
403: }
404: return 1;
405: }
406:
407: void
408: sock_reset(struct sock *f)
409: {
410: switch (f->pstate) {
411: case SOCK_START:
1.35 ! ratchov 412: if (ctl_slotstart(dev_midi, f->slot)) {
! 413: (void)sock_attach(f, 1);
! 414: f->pstate = SOCK_RUN;
! 415: }
1.1 ratchov 416: /* PASSTHROUGH */
417: case SOCK_RUN:
418: sock_freebuf(f);
419: f->pstate = SOCK_INIT;
420: /* PASSTHROUGH */
421: case SOCK_INIT:
422: /* nothing yet */
423: break;
424: }
425: }
426:
427: /*
1.20 ratchov 428: * Read a message from the file descriptor, return 1 if done, 0
429: * otherwise. The message is stored in f->rmsg.
1.1 ratchov 430: */
431: int
432: sock_rmsg(struct sock *f)
433: {
434: unsigned count;
435: unsigned char *data;
436:
437: while (f->rtodo > 0) {
438: if (!(f->pipe.file.state & FILE_ROK)) {
439: return 0;
440: }
441: data = (unsigned char *)&f->rmsg;
442: data += sizeof(struct amsg) - f->rtodo;
443: count = file_read(&f->pipe.file, data, f->rtodo);
444: if (count == 0)
445: return 0;
446: f->rtodo -= count;
447: }
448: return 1;
449: }
450:
451: /*
1.20 ratchov 452: * Write a message to the file descriptor, return 1 if done, 0
1.1 ratchov 453: * otherwise. The "m" argument is f->rmsg or f->wmsg, and the "ptodo"
454: * points to the f->rtodo or f->wtodo respectively.
455: */
456: int
457: sock_wmsg(struct sock *f, struct amsg *m, unsigned *ptodo)
458: {
459: unsigned count;
460: unsigned char *data;
461:
462: while (*ptodo > 0) {
463: if (!(f->pipe.file.state & FILE_WOK)) {
464: return 0;
465: }
466: data = (unsigned char *)m;
467: data += sizeof(struct amsg) - *ptodo;
468: count = file_write(&f->pipe.file, data, *ptodo);
469: if (count == 0)
470: return 0;
471: *ptodo -= count;
472: }
473: return 1;
474: }
475:
476: /*
1.20 ratchov 477: * Read data chunk from the file descriptor, return 1 if at least one
1.1 ratchov 478: * byte was read, 0 if the file blocked.
479: */
480: int
481: sock_rdata(struct sock *f)
482: {
483: struct aproc *p;
484: struct abuf *obuf;
485: unsigned char *data;
486: unsigned count, n;
487:
488: p = f->pipe.file.rproc;
489: obuf = LIST_FIRST(&p->obuflist);
1.19 ratchov 490: if (obuf == NULL)
491: return 0;
1.1 ratchov 492: if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK))
493: return 0;
494: data = abuf_wgetblk(obuf, &count, 0);
1.19 ratchov 495: if (f->pstate != SOCK_MIDI && count > f->rtodo)
1.1 ratchov 496: count = f->rtodo;
497: n = file_read(&f->pipe.file, data, count);
498: if (n == 0)
499: return 0;
500: abuf_wcommit(obuf, n);
1.19 ratchov 501: if (f->pstate != SOCK_MIDI)
502: f->rtodo -= n;
1.1 ratchov 503: return 1;
504: }
505:
506: /*
1.20 ratchov 507: * Write data chunk to the file descriptor, return 1 if at least one
1.1 ratchov 508: * byte was written, 0 if the file blocked.
509: */
510: int
511: sock_wdata(struct sock *f)
512: {
513: struct aproc *p;
514: struct abuf *ibuf;
515: unsigned char *data;
516: unsigned count, n;
517: #define ZERO_MAX 0x1000
518: static char zero[ZERO_MAX];
519:
520: if (!(f->pipe.file.state & FILE_WOK))
521: return 0;
522: p = f->pipe.file.wproc;
523: ibuf = LIST_FIRST(&p->ibuflist);
524: if (ibuf) {
525: if (ABUF_EMPTY(ibuf))
526: return 0;
527: data = abuf_rgetblk(ibuf, &count, 0);
1.19 ratchov 528: if (f->pstate != SOCK_MIDI && count > f->wtodo)
1.1 ratchov 529: count = f->wtodo;
530: n = file_write(&f->pipe.file, data, count);
531: if (n == 0)
532: return 0;
533: abuf_rdiscard(ibuf, n);
1.19 ratchov 534: if (f->pstate != SOCK_MIDI)
535: f->wtodo -= n;
1.1 ratchov 536: } else {
1.19 ratchov 537: if (f->pstate == SOCK_MIDI)
538: return 0;
1.1 ratchov 539: /*
1.20 ratchov 540: * There's no dev_detach() routine yet,
1.1 ratchov 541: * so now we abruptly destroy the buffer.
542: * Until we implement dev_detach, complete
543: * the packet with zeros...
544: */
545: count = ZERO_MAX;
546: if (count > f->wtodo)
547: count = f->wtodo;
548: n = file_write(&f->pipe.file, zero, count);
549: if (n == 0)
550: return 0;
551: f->wtodo -= n;
1.12 ratchov 552: }
1.1 ratchov 553: return 1;
554: }
555:
556: int
557: sock_setpar(struct sock *f)
558: {
559: struct amsg_par *p = &f->rmsg.u.par;
1.9 ratchov 560: unsigned min, max, rate;
1.12 ratchov 561:
1.1 ratchov 562: if (AMSG_ISSET(p->bits)) {
563: if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
564: return 0;
565: }
566: if (AMSG_ISSET(p->bps)) {
567: if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
568: return 0;
569: }
570: } else
571: p->bps = APARAMS_BPS(p->bits);
572: f->rpar.bits = f->wpar.bits = p->bits;
573: f->rpar.bps = f->wpar.bps = p->bps;
574: }
575: if (AMSG_ISSET(p->sig))
576: f->rpar.sig = f->wpar.sig = p->sig ? 1 : 0;
577: if (AMSG_ISSET(p->le))
578: f->rpar.le = f->wpar.le = p->le ? 1 : 0;
579: if (AMSG_ISSET(p->msb))
580: f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
581: if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_REC)) {
582: if (p->rchan < 1)
583: p->rchan = 1;
1.6 ratchov 584: if (p->rchan > NCHAN_MAX)
585: p->rchan = NCHAN_MAX;
1.19 ratchov 586: f->wpar.cmin = f->opt->wpar.cmin;
587: f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
588: if (f->wpar.cmax > f->opt->wpar.cmax)
589: f->wpar.cmax = f->opt->wpar.cmax;
1.1 ratchov 590: }
591: if (AMSG_ISSET(p->pchan) && (f->mode & AMSG_PLAY)) {
592: if (p->pchan < 1)
593: p->pchan = 1;
1.6 ratchov 594: if (p->pchan > NCHAN_MAX)
595: p->pchan = NCHAN_MAX;
1.19 ratchov 596: f->rpar.cmin = f->opt->rpar.cmin;
597: f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
598: if (f->rpar.cmax > f->opt->rpar.cmax)
599: f->rpar.cmax = f->opt->rpar.cmax;
1.1 ratchov 600: }
601: if (AMSG_ISSET(p->rate)) {
602: if (p->rate < RATE_MIN)
603: p->rate = RATE_MIN;
604: if (p->rate > RATE_MAX)
605: p->rate = RATE_MAX;
1.9 ratchov 606: f->round = dev_roundof(p->rate);
1.1 ratchov 607: f->rpar.rate = f->wpar.rate = p->rate;
1.10 ratchov 608: if (!AMSG_ISSET(p->appbufsz)) {
609: p->appbufsz = dev_bufsz / dev_round * f->round;
610: }
1.1 ratchov 611: }
612: if (AMSG_ISSET(p->xrun)) {
613: if (p->xrun != AMSG_IGNORE &&
614: p->xrun != AMSG_SYNC &&
615: p->xrun != AMSG_ERROR) {
616: return 0;
617: }
618: f->xrun = p->xrun;
1.35 ! ratchov 619: if (f->opt->mmc && f->xrun == AMSG_IGNORE)
! 620: f->xrun = AMSG_SYNC;
1.1 ratchov 621: }
622: if (AMSG_ISSET(p->bufsz)) {
1.10 ratchov 623: /*
624: * XXX: bufsz will become read-only, but for now
625: * allow old library to properly work
626: */
627: min = (dev_bufsz / dev_round) * f->round;
628: if (p->bufsz < min)
629: p->bufsz = min;
630: p->appbufsz = p->bufsz - min;
631: }
632: if (AMSG_ISSET(p->appbufsz)) {
1.9 ratchov 633: rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
1.10 ratchov 634: min = 1;
635: max = 1 + rate / dev_round;
1.9 ratchov 636: min *= f->round;
637: max *= f->round;
1.10 ratchov 638: p->appbufsz += f->round - 1;
639: p->appbufsz -= p->appbufsz % f->round;
640: if (p->appbufsz < min)
641: p->appbufsz = min;
642: if (p->appbufsz > max)
643: p->appbufsz = max;
644: f->bufsz = p->appbufsz;
1.1 ratchov 645: }
646: return 1;
647: }
648:
1.19 ratchov 649: /*
650: * allocate buffers, so client can start filling write-end.
651: */
652: void
653: sock_midiattach(struct sock *f, unsigned mode)
654: {
655: struct abuf *rbuf = NULL, *wbuf = NULL;
656:
657: if (mode & AMSG_MIDIOUT) {
1.22 ratchov 658: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 659: aproc_setout(f->pipe.file.rproc, rbuf);
660: }
661: if (mode & AMSG_MIDIIN) {
1.22 ratchov 662: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 663: aproc_setin(f->pipe.file.wproc, wbuf);
664: }
1.23 ratchov 665: dev_midiattach(rbuf, wbuf);
1.19 ratchov 666: }
667:
1.17 ratchov 668: int
669: sock_hello(struct sock *f)
670: {
671: struct amsg_hello *p = &f->rmsg.u.hello;
672:
1.33 ratchov 673: if (p->version != AMSG_VERSION) {
674: return 0;
675: }
676: /*
677: * XXX : dev_midi can no longer be NULL, right ?
678: */
1.23 ratchov 679: if (dev_midi && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
1.19 ratchov 680: if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
681: return 0;
682: }
683: f->mode = p->proto;
684: f->pstate = SOCK_MIDI;
685: sock_midiattach(f, p->proto);
686: return 1;
687: }
688: f->opt = opt_byname(p->opt);
689: if (f->opt == NULL)
690: return 0;
1.31 ratchov 691: if (dev_sub)
1.19 ratchov 692: f->wpar = f->opt->wpar;
1.31 ratchov 693: if (dev_mix)
1.19 ratchov 694: f->rpar = f->opt->rpar;
1.35 ! ratchov 695: if (f->opt->mmc)
! 696: f->xrun = AMSG_SYNC;
1.18 ratchov 697: if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
698: (p->proto & (AMSG_PLAY | AMSG_REC)) == 0) {
1.17 ratchov 699: return 0;
700: }
1.18 ratchov 701: f->mode = 0;
702: if (p->proto & AMSG_PLAY) {
703: if (!dev_mix) {
704: return 0;
705: }
706: f->mode |= AMSG_PLAY;
1.17 ratchov 707: }
1.18 ratchov 708: if (p->proto & AMSG_REC) {
709: if (!dev_sub) {
710: return 0;
711: }
712: f->mode |= AMSG_REC;
1.17 ratchov 713: }
1.24 ratchov 714: if (dev_midi) {
1.35 ! ratchov 715: f->slot = ctl_slotnew(dev_midi,
! 716: p->who, &ctl_sockops, f,
! 717: f->opt->mmc);
1.24 ratchov 718: if (f->slot < 0) {
719: return 0;
720: }
721: }
1.18 ratchov 722: f->pstate = SOCK_INIT;
1.17 ratchov 723: return 1;
724: }
725:
1.1 ratchov 726: /*
1.20 ratchov 727: * Execute message in f->rmsg and change the state accordingly; return 1
1.1 ratchov 728: * on success, and 0 on failure, in which case the socket is destroyed.
729: */
730: int
731: sock_execmsg(struct sock *f)
732: {
733: struct amsg *m = &f->rmsg;
734:
735: switch (m->cmd) {
736: case AMSG_DATA:
737: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
1.8 ratchov 738: aproc_del(f->pipe.file.rproc);
739: return 0;
740: }
741: if (!(f->mode & AMSG_PLAY)) {
1.1 ratchov 742: aproc_del(f->pipe.file.rproc);
743: return 0;
744: }
1.34 ratchov 745: if (f->pstate == SOCK_START &&
746: ABUF_FULL(LIST_FIRST(&f->pipe.file.rproc->obuflist))) {
747: aproc_del(f->pipe.file.rproc);
748: return 0;
749: }
1.1 ratchov 750: f->rstate = SOCK_RDATA;
751: f->rtodo = m->u.data.size;
752: if (f->rtodo == 0) {
753: aproc_del(f->pipe.file.rproc);
754: return 0;
755: }
756: break;
757: case AMSG_START:
758: if (f->pstate != SOCK_INIT) {
759: aproc_del(f->pipe.file.rproc);
760: return 0;
761: }
762: sock_allocbuf(f);
763: f->rstate = SOCK_RMSG;
764: f->rtodo = sizeof(struct amsg);
765: break;
766: case AMSG_STOP:
767: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
768: aproc_del(f->pipe.file.rproc);
769: return 0;
770: }
1.35 ! ratchov 771: if (f->pstate == SOCK_START &&
! 772: ctl_slotstart(dev_midi, f->slot))
1.1 ratchov 773: (void)sock_attach(f, 1);
774: sock_freebuf(f);
775: AMSG_INIT(m);
776: m->cmd = AMSG_ACK;
777: f->rstate = SOCK_RRET;
778: f->rtodo = sizeof(struct amsg);
779: break;
780: case AMSG_SETPAR:
781: if (f->pstate != SOCK_INIT) {
782: aproc_del(f->pipe.file.rproc);
783: return 0;
784: }
785: if (!sock_setpar(f)) {
786: aproc_del(f->pipe.file.rproc);
787: return 0;
788: }
789: f->rtodo = sizeof(struct amsg);
790: f->rstate = SOCK_RMSG;
791: break;
792: case AMSG_GETPAR:
793: if (f->pstate != SOCK_INIT) {
794: aproc_del(f->pipe.file.rproc);
795: return 0;
796: }
797: AMSG_INIT(m);
798: m->cmd = AMSG_GETPAR;
1.18 ratchov 799: m->u.par.legacy_mode = f->mode;
1.1 ratchov 800: m->u.par.bits = f->rpar.bits;
801: m->u.par.bps = f->rpar.bps;
802: m->u.par.sig = f->rpar.sig;
803: m->u.par.le = f->rpar.le;
804: m->u.par.msb = f->rpar.msb;
805: m->u.par.rate = f->rpar.rate;
806: m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
807: m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
1.10 ratchov 808: m->u.par.appbufsz = f->bufsz;
1.12 ratchov 809: m->u.par.bufsz =
1.10 ratchov 810: f->bufsz + (dev_bufsz / dev_round) * f->round;
1.1 ratchov 811: m->u.par.round = f->round;
812: f->rstate = SOCK_RRET;
813: f->rtodo = sizeof(struct amsg);
814: break;
815: case AMSG_GETCAP:
816: if (f->pstate != SOCK_INIT) {
817: aproc_del(f->pipe.file.rproc);
818: return 0;
819: }
820: AMSG_INIT(m);
821: m->cmd = AMSG_GETCAP;
822: m->u.cap.rate = dev_rate;
1.6 ratchov 823: m->u.cap.pchan = dev_mix ?
1.19 ratchov 824: (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
1.6 ratchov 825: m->u.cap.rchan = dev_sub ?
1.19 ratchov 826: (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
1.1 ratchov 827: m->u.cap.bits = sizeof(short) * 8;
828: m->u.cap.bps = sizeof(short);
829: f->rstate = SOCK_RRET;
830: f->rtodo = sizeof(struct amsg);
1.3 ratchov 831: break;
832: case AMSG_SETVOL:
833: if (f->pstate != SOCK_RUN &&
834: f->pstate != SOCK_START && f->pstate != SOCK_INIT) {
835: aproc_del(f->pipe.file.rproc);
836: return 0;
837: }
838: if (m->u.vol.ctl > MIDI_MAXCTL) {
839: aproc_del(f->pipe.file.rproc);
840: return 0;
841: }
1.25 ratchov 842: sock_setvol(f, m->u.vol.ctl);
1.34 ratchov 843: if (f->slot >= 0)
1.24 ratchov 844: ctl_slotvol(dev_midi, f->slot, m->u.vol.ctl);
1.3 ratchov 845: f->rtodo = sizeof(struct amsg);
846: f->rstate = SOCK_RMSG;
1.17 ratchov 847: break;
848: case AMSG_HELLO:
1.18 ratchov 849: if (f->pstate != SOCK_HELLO) {
1.17 ratchov 850: aproc_del(f->pipe.file.rproc);
851: return 0;
852: }
853: if (!sock_hello(f)) {
854: aproc_del(f->pipe.file.rproc);
855: return 0;
856: }
857: AMSG_INIT(m);
858: m->cmd = AMSG_ACK;
859: f->rstate = SOCK_RRET;
860: f->rtodo = sizeof(struct amsg);
1.1 ratchov 861: break;
1.28 ratchov 862: case AMSG_BYE:
1.29 ratchov 863: if (f->pstate != SOCK_INIT) {
864: }
1.28 ratchov 865: aproc_del(f->pipe.file.rproc);
866: return 0;
1.1 ratchov 867: default:
868: aproc_del(f->pipe.file.rproc);
869: return 0;
870: }
871: if (f->rstate == SOCK_RRET) {
872: if (f->wstate != SOCK_WIDLE ||
873: !sock_wmsg(f, &f->rmsg, &f->rtodo))
874: return 0;
1.19 ratchov 875: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
876: f->rstate = SOCK_RDATA;
877: f->rtodo = 0;
878: } else {
879: f->rstate = SOCK_RMSG;
880: f->rtodo = sizeof(struct amsg);
881: }
1.1 ratchov 882: }
883: return 1;
884: }
885:
886: /*
1.20 ratchov 887: * Create a new data/pos message.
1.1 ratchov 888: */
889: int
890: sock_buildmsg(struct sock *f)
891: {
892: struct aproc *p;
893: struct abuf *ibuf;
1.12 ratchov 894:
1.19 ratchov 895: if (f->pstate == SOCK_MIDI) {
896: f->wstate = SOCK_WDATA;
897: f->wtodo = 0;
898: return 1;
899: }
900:
1.1 ratchov 901: /*
1.20 ratchov 902: * If pos changed, build a MOVE message.
1.1 ratchov 903: */
1.33 ratchov 904: if (f->tickpending) {
1.1 ratchov 905: AMSG_INIT(&f->wmsg);
906: f->wmsg.cmd = AMSG_MOVE;
1.14 ratchov 907: f->wmsg.u.ts.delta = f->delta;
1.1 ratchov 908: f->wtodo = sizeof(struct amsg);
909: f->wstate = SOCK_WMSG;
1.14 ratchov 910: f->delta = 0;
911: f->tickpending = 0;
1.25 ratchov 912: return 1;
913: }
914:
915: /*
916: * if volume changed build a SETVOL message
917: */
1.27 ratchov 918: if (f->pstate >= SOCK_START && f->vol != f->lastvol) {
1.25 ratchov 919: AMSG_INIT(&f->wmsg);
920: f->wmsg.cmd = AMSG_SETVOL;
921: f->wmsg.u.vol.ctl = f->vol;
922: f->wtodo = sizeof(struct amsg);
923: f->wstate = SOCK_WMSG;
924: f->lastvol = f->vol;
1.1 ratchov 925: return 1;
926: }
927:
928: /*
1.20 ratchov 929: * If data available, build a DATA message.
1.1 ratchov 930: */
931: p = f->pipe.file.wproc;
932: ibuf = LIST_FIRST(&p->ibuflist);
933: if (ibuf && ABUF_ROK(ibuf)) {
934: AMSG_INIT(&f->wmsg);
935: f->wmsg.cmd = AMSG_DATA;
936: f->wmsg.u.data.size = ibuf->used - (ibuf->used % ibuf->bpf);
937: if (f->wmsg.u.data.size > AMSG_DATAMAX)
938: f->wmsg.u.data.size =
939: AMSG_DATAMAX - (AMSG_DATAMAX % ibuf->bpf);
940: f->wtodo = sizeof(struct amsg);
941: f->wstate = SOCK_WMSG;
942: return 1;
943: }
944: f->wstate = SOCK_WIDLE;
945: return 0;
946: }
947:
948: /*
1.20 ratchov 949: * Read from the socket file descriptor, fill input buffer and update
1.1 ratchov 950: * the state. Return 1 if at least one message or 1 data byte was
951: * processed, 0 if something blocked.
952: */
953: int
954: sock_read(struct sock *f)
955: {
956: switch (f->rstate) {
957: case SOCK_RMSG:
958: if (!sock_rmsg(f))
959: return 0;
960: if (!sock_execmsg(f))
961: return 0;
962: break;
963: case SOCK_RDATA:
964: if (!sock_rdata(f))
965: return 0;
1.19 ratchov 966: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1 ratchov 967: f->rstate = SOCK_RMSG;
968: f->rtodo = sizeof(struct amsg);
969: }
1.35 ! ratchov 970: /*
! 971: * XXX: have to way that the buffer is full before starting
! 972: */
! 973: if (f->pstate == SOCK_START && ctl_slotstart(dev_midi, f->slot))
1.1 ratchov 974: (void)sock_attach(f, 0);
975: break;
976: case SOCK_RRET:
977: return 0;
978: }
979: return 1;
980: }
981:
982: /*
1.20 ratchov 983: * Process messages to return.
1.1 ratchov 984: */
985: int
986: sock_return(struct sock *f)
987: {
988: struct aproc *rp;
989:
990: while (f->rstate == SOCK_RRET) {
991: if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
992: return 0;
1.19 ratchov 993: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
994: f->rstate = SOCK_RDATA;
995: f->rtodo = 0;
996: } else {
997: f->rstate = SOCK_RMSG;
998: f->rtodo = sizeof(struct amsg);
999: }
1000: if (f->pipe.file.state & FILE_RINUSE)
1001: break;
1002: f->pipe.file.state |= FILE_RINUSE;
1.1 ratchov 1003: for (;;) {
1004: /*
1005: * in() may trigger rsock_done and destroy the
1.20 ratchov 1006: * wsock.
1.1 ratchov 1007: */
1008: rp = f->pipe.file.rproc;
1009: if (!rp || !rp->ops->in(rp, NULL))
1010: break;
1011: }
1.19 ratchov 1012: f->pipe.file.state &= ~FILE_RINUSE;
1.1 ratchov 1013: if (f->pipe.file.wproc == NULL)
1014: return 0;
1015: }
1016: return 1;
1017: }
1018:
1019: /*
1.20 ratchov 1020: * Write messages and data on the socket file descriptor. Return 1 if
1.1 ratchov 1021: * at least one message or one data byte was processed, 0 if something
1022: * blocked.
1023: */
1024: int
1025: sock_write(struct sock *f)
1026: {
1027: switch (f->wstate) {
1028: case SOCK_WMSG:
1029: if (!sock_wmsg(f, &f->wmsg, &f->wtodo))
1030: return 0;
1031: if (f->wmsg.cmd != AMSG_DATA) {
1032: f->wstate = SOCK_WIDLE;
1033: f->wtodo = 0xdeadbeef;
1034: break;
1035: }
1036: f->wstate = SOCK_WDATA;
1037: f->wtodo = f->wmsg.u.data.size;
1038: /* PASSTHROUGH */
1039: case SOCK_WDATA:
1040: if (!sock_wdata(f))
1041: return 0;
1.19 ratchov 1042: if (f->pstate == SOCK_MIDI || f->wtodo > 0)
1.1 ratchov 1043: break;
1044: f->wstate = SOCK_WIDLE;
1045: f->wtodo = 0xdeadbeef;
1046: /* PASSTHROUGH */
1047: case SOCK_WIDLE:
1048: if (!sock_return(f))
1049: return 0;
1050: if (!sock_buildmsg(f))
1051: return 0;
1052: break;
1053: }
1054: return 1;
1055: }