[BACK]Return to sock.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

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: }