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

Annotation of src/usr.bin/sndiod/midi.c, Revision 1.29

1.29    ! ratchov     1: /*     $OpenBSD: midi.c,v 1.28 2021/03/08 09:42:50 ratchov Exp $       */
1.1       ratchov     2: /*
                      3:  * Copyright (c) 2008-2012 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: #include <stdio.h>
                     18: #include <stdlib.h>
                     19: #include <string.h>
                     20:
                     21: #include "abuf.h"
                     22: #include "defs.h"
                     23: #include "dev.h"
                     24: #include "file.h"
                     25: #include "midi.h"
                     26: #include "miofile.h"
                     27: #include "sysex.h"
                     28: #include "utils.h"
                     29:
                     30: int  port_open(struct port *);
                     31: void port_imsg(void *, unsigned char *, int);
                     32: void port_omsg(void *, unsigned char *, int);
                     33: void port_fill(void *, int);
                     34: void port_exit(void *);
1.20      ratchov    35: void port_exitall(struct port *);
1.1       ratchov    36:
                     37: struct midiops port_midiops = {
                     38:        port_imsg,
                     39:        port_omsg,
                     40:        port_fill,
                     41:        port_exit
                     42: };
                     43:
                     44: #define MIDI_NEP 32
                     45: struct midi midi_ep[MIDI_NEP];
                     46: struct port *port_list = NULL;
                     47: unsigned int midi_portnum = 0;
                     48:
                     49: struct midithru {
1.2       ratchov    50:        unsigned int txmask, rxmask;
1.1       ratchov    51: #define MIDITHRU_NMAX 32
                     52: } midithru[MIDITHRU_NMAX];
                     53:
                     54: /*
                     55:  * length of voice and common messages (status byte included)
                     56:  */
1.26      naddy      57: const unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
                     58: const unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
1.1       ratchov    59:
                     60: void
                     61: midi_log(struct midi *ep)
                     62: {
                     63:        log_puts("midi");
                     64:        log_putu(ep - midi_ep);
                     65: }
                     66:
                     67: void
                     68: midi_init(void)
                     69: {
                     70: }
                     71:
                     72: void
                     73: midi_done(void)
                     74: {
                     75: }
                     76:
                     77: struct midi *
                     78: midi_new(struct midiops *ops, void *arg, int mode)
                     79: {
                     80:        int i;
                     81:        struct midi *ep;
                     82:
                     83:        for (i = 0, ep = midi_ep;; i++, ep++) {
                     84:                if (i == MIDI_NEP)
                     85:                        return NULL;
                     86:                if (ep->ops == NULL)
                     87:                        break;
                     88:        }
                     89:        ep->ops = ops;
                     90:        ep->arg = arg;
                     91:        ep->used = 0;
                     92:        ep->len = 0;
                     93:        ep->idx = 0;
                     94:        ep->st = 0;
1.23      ratchov    95:        ep->last_st = 0;
1.1       ratchov    96:        ep->txmask = 0;
1.2       ratchov    97:        ep->self = 1 << i;
                     98:        ep->tickets = 0;
1.1       ratchov    99:        ep->mode = mode;
1.2       ratchov   100:
1.1       ratchov   101:        /*
1.16      ratchov   102:         * the output buffer is the client input
1.1       ratchov   103:         */
1.2       ratchov   104:        if (ep->mode & MODE_MIDIIN)
1.1       ratchov   105:                abuf_init(&ep->obuf, MIDI_BUFSZ);
1.2       ratchov   106:        midi_tickets(ep);
1.1       ratchov   107:        return ep;
                    108: }
                    109:
                    110: void
                    111: midi_del(struct midi *ep)
                    112: {
                    113:        int i;
1.2       ratchov   114:        struct midi *peer;
1.1       ratchov   115:
1.2       ratchov   116:        ep->txmask = 0;
                    117:        for (i = 0; i < MIDI_NEP; i++) {
                    118:                peer = midi_ep + i;
                    119:                if (peer->txmask & ep->self) {
                    120:                        peer->txmask &= ~ep->self;
                    121:                        midi_tickets(peer);
                    122:                }
                    123:        }
                    124:        for (i = 0; i < MIDITHRU_NMAX; i++) {
                    125:                midithru[i].txmask &= ~ep->self;
                    126:                midithru[i].rxmask &= ~ep->self;
                    127:        }
1.1       ratchov   128:        ep->ops = NULL;
                    129:        if (ep->mode & MODE_MIDIIN) {
                    130:                abuf_done(&ep->obuf);
                    131:        }
                    132: }
                    133:
                    134: /*
1.2       ratchov   135:  * connect two midi endpoints
1.1       ratchov   136:  */
                    137: void
1.2       ratchov   138: midi_link(struct midi *ep, struct midi *peer)
1.1       ratchov   139: {
1.2       ratchov   140:        if (ep->mode & MODE_MIDIOUT) {
                    141:                ep->txmask |= peer->self;
                    142:                midi_tickets(ep);
                    143:        }
                    144:        if (ep->mode & MODE_MIDIIN) {
                    145: #ifdef DEBUG
                    146:                if (ep->obuf.used > 0) {
                    147:                        midi_log(ep);
                    148:                        log_puts(": linked with non-empty buffer\n");
                    149:                        panic();
                    150:                }
                    151: #endif
1.16      ratchov   152:                /* ep has empty buffer, so no need to call midi_tickets() */
1.2       ratchov   153:                peer->txmask |= ep->self;
1.1       ratchov   154:        }
                    155: }
                    156:
                    157: /*
1.2       ratchov   158:  * add the midi endpoint in the ``tag'' midi thru box
1.1       ratchov   159:  */
                    160: void
1.2       ratchov   161: midi_tag(struct midi *ep, unsigned int tag)
1.1       ratchov   162: {
1.2       ratchov   163:        struct midi *peer;
                    164:        struct midithru *t = midithru + tag;
1.1       ratchov   165:        int i;
                    166:
1.2       ratchov   167:        if (ep->mode & MODE_MIDIOUT) {
                    168:                ep->txmask |= t->txmask;
                    169:                midi_tickets(ep);
                    170:        }
                    171:        if (ep->mode & MODE_MIDIIN) {
                    172: #ifdef DEBUG
                    173:                if (ep->obuf.used > 0) {
                    174:                        midi_log(ep);
                    175:                        log_puts(": tagged with non-empty buffer\n");
                    176:                        panic();
                    177:                }
                    178: #endif
                    179:                for (i = 0; i < MIDI_NEP; i++) {
                    180:                        if (!(t->rxmask & (1 << i)))
                    181:                                continue;
                    182:                        peer = midi_ep + i;
                    183:                        peer->txmask |= ep->self;
                    184:                }
1.1       ratchov   185:        }
1.2       ratchov   186:        if (ep->mode & MODE_MIDIOUT)
                    187:                t->rxmask |= ep->self;
                    188:        if (ep->mode & MODE_MIDIIN)
                    189:                t->txmask |= ep->self;
1.24      ratchov   190: }
                    191:
                    192: /*
                    193:  * return the list of tags
                    194:  */
                    195: unsigned int
                    196: midi_tags(struct midi *ep)
                    197: {
                    198:        int i;
                    199:        struct midithru *t;
                    200:        unsigned int tags;
                    201:
                    202:        tags = 0;
                    203:        for (i = 0; i < MIDITHRU_NMAX; i++) {
                    204:                t = midithru + i;
                    205:                if ((t->txmask | t->rxmask) & ep->self)
                    206:                        tags |= 1 << i;
                    207:        }
                    208:        return tags;
1.1       ratchov   209: }
                    210:
                    211: /*
1.6       ratchov   212:  * broadcast the given message to other endpoints
1.1       ratchov   213:  */
                    214: void
                    215: midi_send(struct midi *iep, unsigned char *msg, int size)
                    216: {
                    217:        struct midi *oep;
                    218:        int i;
                    219:
                    220: #ifdef DEBUG
                    221:        if (log_level >= 4) {
                    222:                midi_log(iep);
                    223:                log_puts(": sending:");
                    224:                for (i = 0; i < size; i++) {
                    225:                        log_puts(" ");
                    226:                        log_putx(msg[i]);
                    227:                }
                    228:                log_puts("\n");
                    229:        }
                    230: #endif
                    231:        for (i = 0; i < MIDI_NEP ; i++) {
                    232:                if ((iep->txmask & (1 << i)) == 0)
                    233:                        continue;
                    234:                oep = midi_ep + i;
                    235:                if (msg[0] <= 0x7f) {
                    236:                        if (oep->owner != iep)
                    237:                                continue;
                    238:                } else if (msg[0] <= 0xf7)
                    239:                        oep->owner = iep;
                    240: #ifdef DEBUG
                    241:                if (log_level >= 4) {
                    242:                        midi_log(iep);
                    243:                        log_puts(" -> ");
                    244:                        midi_log(oep);
                    245:                        log_puts("\n");
                    246:                }
                    247: #endif
                    248:                oep->ops->omsg(oep->arg, msg, size);
                    249:        }
                    250: }
                    251:
1.2       ratchov   252: /*
                    253:  * determine if we have gained more input tickets, and if so call the
                    254:  * fill() call-back to notify the i/o layer that it can send more data
                    255:  */
                    256: void
                    257: midi_tickets(struct midi *iep)
                    258: {
                    259:        int i, tickets, avail, maxavail;
                    260:        struct midi *oep;
1.17      ratchov   261:
                    262:        /*
                    263:         * don't request iep->ops->fill() too often as it generates
                    264:         * useless network traffic: wait until we reach half of the
                    265:         * max tickets count. As in the worst case (see comment below)
                    266:         * one ticket may consume two bytes, the max ticket count is
                    267:         * BUFSZ / 2 and halt of it is simply BUFSZ / 4.
                    268:         */
                    269:        if (iep->tickets >= MIDI_BUFSZ / 4)
                    270:                return;
1.2       ratchov   271:
                    272:        maxavail = MIDI_BUFSZ;
                    273:        for (i = 0; i < MIDI_NEP ; i++) {
                    274:                if ((iep->txmask & (1 << i)) == 0)
                    275:                        continue;
                    276:                oep = midi_ep + i;
                    277:                avail = oep->obuf.len - oep->obuf.used;
                    278:                if (maxavail > avail)
                    279:                        maxavail = avail;
                    280:        }
                    281:
                    282:        /*
1.15      ratchov   283:         * in the worst case output message is twice the
1.2       ratchov   284:         * input message (2-byte messages with running status)
                    285:         */
                    286:        tickets = maxavail / 2 - iep->tickets;
                    287:        if (tickets > 0) {
                    288:                iep->tickets += tickets;
                    289:                iep->ops->fill(iep->arg, tickets);
                    290:        }
                    291: }
                    292:
                    293: /*
                    294:  * recalculate tickets of endpoints sending data to this one
                    295:  */
1.1       ratchov   296: void
                    297: midi_fill(struct midi *oep)
                    298: {
1.2       ratchov   299:        int i;
1.1       ratchov   300:        struct midi *iep;
                    301:
1.2       ratchov   302:        for (i = 0; i < MIDI_NEP; i++) {
1.1       ratchov   303:                iep = midi_ep + i;
1.2       ratchov   304:                if (iep->txmask & oep->self)
                    305:                        midi_tickets(iep);
1.1       ratchov   306:        }
                    307: }
                    308:
                    309: /*
1.2       ratchov   310:  * parse then give data chunk, and calling imsg() for each message
1.1       ratchov   311:  */
                    312: void
1.2       ratchov   313: midi_in(struct midi *iep, unsigned char *idata, int icount)
1.1       ratchov   314: {
                    315:        int i;
                    316:        unsigned char c;
                    317:
                    318:        for (i = 0; i < icount; i++) {
                    319:                c = *idata++;
                    320:                if (c >= 0xf8) {
                    321:                        if (c != MIDI_ACK)
                    322:                                iep->ops->imsg(iep->arg, &c, 1);
                    323:                } else if (c == SYSEX_END) {
                    324:                        if (iep->st == SYSEX_START) {
                    325:                                iep->msg[iep->idx++] = c;
                    326:                                iep->ops->imsg(iep->arg, iep->msg, iep->idx);
                    327:                        }
1.23      ratchov   328:
                    329:                        /*
                    330:                         * There are bogus MIDI sources that keep
                    331:                         * state across sysex; Linux virmidi ports fed
                    332:                         * by the sequencer is an example. We
                    333:                         * workaround this by saving the current
                    334:                         * status and restoring it at the end of the
                    335:                         * sysex.
                    336:                         */
                    337:                        iep->st = iep->last_st;
                    338:                        if (iep->st)
                    339:                                iep->len = voice_len[(iep->st >> 4) & 7];
1.1       ratchov   340:                        iep->idx = 0;
                    341:                } else if (c >= 0xf0) {
                    342:                        iep->msg[0] = c;
1.19      ratchov   343:                        iep->len = common_len[c & 7];
1.1       ratchov   344:                        iep->st = c;
                    345:                        iep->idx = 1;
                    346:                } else if (c >= 0x80) {
                    347:                        iep->msg[0] = c;
                    348:                        iep->len = voice_len[(c >> 4) & 7];
1.23      ratchov   349:                        iep->last_st = iep->st = c;
1.1       ratchov   350:                        iep->idx = 1;
                    351:                } else if (iep->st) {
                    352:                        if (iep->idx == 0 && iep->st != SYSEX_START)
                    353:                                iep->msg[iep->idx++] = iep->st;
                    354:                        iep->msg[iep->idx++] = c;
                    355:                        if (iep->idx == iep->len) {
                    356:                                iep->ops->imsg(iep->arg, iep->msg, iep->idx);
                    357:                                if (iep->st >= 0xf0)
                    358:                                        iep->st = 0;
                    359:                                iep->idx = 0;
                    360:                        } else if (iep->idx == MIDI_MSGMAX) {
                    361:                                /* sysex continued */
                    362:                                iep->ops->imsg(iep->arg, iep->msg, iep->idx);
                    363:                                iep->idx = 0;
                    364:                        }
                    365:                }
                    366:        }
1.2       ratchov   367:        iep->tickets -= icount;
                    368:        if (iep->tickets < 0)
                    369:                iep->tickets = 0;
1.7       ratchov   370:        midi_tickets(iep);
1.1       ratchov   371: }
                    372:
                    373: /*
                    374:  * store the given message in the output buffer
                    375:  */
                    376: void
1.15      ratchov   377: midi_out(struct midi *oep, unsigned char *idata, int icount)
1.1       ratchov   378: {
                    379:        unsigned char *odata;
                    380:        int ocount;
                    381: #ifdef DEBUG
                    382:        int i;
                    383: #endif
1.15      ratchov   384:
1.1       ratchov   385:        while (icount > 0) {
                    386:                if (oep->obuf.used == oep->obuf.len) {
                    387: #ifdef DEBUG
                    388:                        if (log_level >= 2) {
                    389:                                midi_log(oep);
1.2       ratchov   390:                                log_puts(": too slow, discarding ");
1.1       ratchov   391:                                log_putu(oep->obuf.used);
                    392:                                log_puts(" bytes\n");
                    393:                        }
                    394: #endif
                    395:                        abuf_rdiscard(&oep->obuf, oep->obuf.used);
                    396:                        oep->owner = NULL;
                    397:                        return;
                    398:                }
                    399:                odata = abuf_wgetblk(&oep->obuf, &ocount);
                    400:                if (ocount > icount)
                    401:                        ocount = icount;
                    402:                memcpy(odata, idata, ocount);
                    403: #ifdef DEBUG
                    404:                if (log_level >= 4) {
                    405:                        midi_log(oep);
                    406:                        log_puts(": out: ");
                    407:                        for (i = 0; i < ocount; i++) {
                    408:                                log_puts(" ");
                    409:                                log_putx(odata[i]);
                    410:                        }
                    411:                        log_puts("\n");
                    412:                }
                    413: #endif
                    414:                abuf_wcommit(&oep->obuf, ocount);
                    415:                icount -= ocount;
                    416:                idata += ocount;
                    417:        }
                    418: }
                    419:
1.27      ratchov   420: /*
                    421:  * disconnect clients attached to this end-point
                    422:  */
                    423: void
                    424: midi_abort(struct midi *p)
                    425: {
                    426:        int i;
                    427:        struct midi *ep;
                    428:
                    429:        for (i = 0; i < MIDI_NEP; i++) {
                    430:                ep = midi_ep + i;
                    431:                if ((ep->txmask & p->self) || (p->txmask & ep->self))
                    432:                        ep->ops->exit(ep->arg);
                    433:        }
                    434: }
                    435:
1.29    ! ratchov   436: /*
        !           437:  * connect to "nep" all endpoints currently connected to "oep"
        !           438:  */
        !           439: void
        !           440: midi_migrate(struct midi *oep, struct midi *nep)
        !           441: {
        !           442:        struct midithru *t;
        !           443:        struct midi *ep;
        !           444:        int i;
        !           445:
        !           446:        for (i = 0; i < MIDITHRU_NMAX; i++) {
        !           447:                t = midithru + i;
        !           448:                if (t->txmask & oep->self) {
        !           449:                        t->txmask &= ~oep->self;
        !           450:                        t->txmask |= nep->self;
        !           451:                }
        !           452:                if (t->rxmask & oep->self) {
        !           453:                        t->rxmask &= ~oep->self;
        !           454:                        t->rxmask |= nep->self;
        !           455:                }
        !           456:        }
        !           457:
        !           458:        for (i = 0; i < MIDI_NEP; i++) {
        !           459:                ep = midi_ep + i;
        !           460:                if (ep->txmask & oep->self) {
        !           461:                        ep->txmask &= ~oep->self;
        !           462:                        ep->txmask |= nep->self;
        !           463:                }
        !           464:        }
        !           465:
        !           466:        for (i = 0; i < MIDI_NEP; i++) {
        !           467:                ep = midi_ep + i;
        !           468:                if (oep->txmask & ep->self) {
        !           469:                        oep->txmask &= ~ep->self;
        !           470:                        nep->txmask |= ep->self;
        !           471:                }
        !           472:        }
        !           473: }
        !           474:
1.1       ratchov   475: void
                    476: port_log(struct port *p)
                    477: {
                    478:        midi_log(p->midi);
                    479: }
                    480:
                    481: void
                    482: port_imsg(void *arg, unsigned char *msg, int size)
                    483: {
                    484:        struct port *p = arg;
                    485:
                    486:        midi_send(p->midi, msg, size);
                    487: }
                    488:
                    489:
                    490: void
                    491: port_omsg(void *arg, unsigned char *msg, int size)
                    492: {
                    493:        struct port *p = arg;
                    494:
                    495:        midi_out(p->midi, msg, size);
                    496: }
                    497:
                    498: void
                    499: port_fill(void *arg, int count)
                    500: {
                    501:        /* no flow control */
                    502: }
                    503:
                    504: void
                    505: port_exit(void *arg)
                    506: {
                    507: #ifdef DEBUG
                    508:        struct port *p = arg;
                    509:
                    510:        if (log_level >= 3) {
                    511:                port_log(p);
1.3       ratchov   512:                log_puts(": port exit\n");
                    513:                panic();
1.1       ratchov   514:        }
                    515: #endif
                    516: }
                    517:
                    518: /*
                    519:  * create a new midi port
                    520:  */
                    521: struct port *
1.4       ratchov   522: port_new(char *path, unsigned int mode, int hold)
1.1       ratchov   523: {
1.29    ! ratchov   524:        struct port *c;
1.1       ratchov   525:
                    526:        c = xmalloc(sizeof(struct port));
1.29    ! ratchov   527:        c->path = path;
1.1       ratchov   528:        c->state = PORT_CFG;
1.4       ratchov   529:        c->hold = hold;
1.1       ratchov   530:        c->midi = midi_new(&port_midiops, c, mode);
1.11      ratchov   531:        c->num = midi_portnum++;
1.29    ! ratchov   532:        c->alt_next = c;
        !           533:        c->next = port_list;
        !           534:        port_list = c;
1.1       ratchov   535:        return c;
                    536: }
                    537:
                    538: /*
                    539:  * destroy the given midi port
                    540:  */
                    541: void
                    542: port_del(struct port *c)
                    543: {
                    544:        struct port **p;
                    545:
                    546:        if (c->state != PORT_CFG)
                    547:                port_close(c);
                    548:        midi_del(c->midi);
                    549:        for (p = &port_list; *p != c; p = &(*p)->next) {
                    550: #ifdef DEBUG
                    551:                if (*p == NULL) {
                    552:                        log_puts("port to delete not on list\n");
                    553:                        panic();
                    554:                }
                    555: #endif
                    556:        }
                    557:        *p = c->next;
                    558:        xfree(c);
                    559: }
                    560:
1.3       ratchov   561: int
                    562: port_ref(struct port *c)
                    563: {
                    564: #ifdef DEBUG
                    565:        if (log_level >= 3) {
                    566:                port_log(c);
                    567:                log_puts(": port requested\n");
                    568:        }
                    569: #endif
                    570:        if (c->state == PORT_CFG && !port_open(c))
                    571:                return 0;
                    572:        return 1;
                    573: }
                    574:
                    575: void
                    576: port_unref(struct port *c)
                    577: {
                    578:        int i, rxmask;
                    579:
                    580: #ifdef DEBUG
                    581:        if (log_level >= 3) {
                    582:                port_log(c);
                    583:                log_puts(": port released\n");
                    584:        }
                    585: #endif
                    586:        for (rxmask = 0, i = 0; i < MIDI_NEP; i++)
                    587:                rxmask |= midi_ep[i].txmask;
1.10      ratchov   588:        if ((rxmask & c->midi->self) == 0 && c->midi->txmask == 0 &&
                    589:            c->state == PORT_INIT && !c->hold)
1.5       ratchov   590:                port_drain(c);
1.3       ratchov   591: }
                    592:
1.1       ratchov   593: struct port *
1.29    ! ratchov   594: port_alt_ref(int num)
        !           595: {
        !           596:        struct port *a, *p;
        !           597:
        !           598:        a = port_bynum(num);
        !           599:        if (a == NULL)
        !           600:                return NULL;
        !           601:
        !           602:        /* circulate to first alt port */
        !           603:        while (a->alt_next->num > a->num)
        !           604:                a = a->alt_next;
        !           605:
        !           606:        p = a;
        !           607:        while (1) {
        !           608:                if (port_ref(p))
        !           609:                        break;
        !           610:                p = p->alt_next;
        !           611:                if (p == a)
        !           612:                        return NULL;
        !           613:        }
        !           614:
        !           615:        return p;
        !           616: }
        !           617:
        !           618: struct port *
        !           619: port_migrate(struct port *op)
        !           620: {
        !           621:        struct port *np;
        !           622:
        !           623:        /* not opened */
        !           624:        if (op->state == PORT_CFG)
        !           625:                return op;
        !           626:
        !           627:        np = op;
        !           628:        while (1) {
        !           629:                /* try next one, circulating through the list */
        !           630:                np = np->alt_next;
        !           631:                if (np == op) {
        !           632:                        if (log_level >= 2) {
        !           633:                                port_log(op);
        !           634:                                log_puts(": no fall-back port found\n");
        !           635:                        }
        !           636:                        return op;
        !           637:                }
        !           638:
        !           639:                if (port_ref(np))
        !           640:                        break;
        !           641:        }
        !           642:
        !           643:        if (log_level >= 2) {
        !           644:                port_log(op);
        !           645:                log_puts(": switching to ");
        !           646:                port_log(np);
        !           647:                log_puts("\n");
        !           648:        }
        !           649:
        !           650:        midi_migrate(op->midi, np->midi);
        !           651:        return np;
        !           652: }
        !           653:
        !           654: struct port *
1.1       ratchov   655: port_bynum(int num)
                    656: {
                    657:        struct port *p;
                    658:
                    659:        for (p = port_list; p != NULL; p = p->next) {
1.12      ratchov   660:                if (p->num == num)
1.1       ratchov   661:                        return p;
                    662:        }
                    663:        return NULL;
                    664: }
                    665:
                    666: int
                    667: port_open(struct port *c)
                    668: {
                    669:        if (!port_mio_open(c)) {
                    670:                if (log_level >= 1) {
1.21      ratchov   671:                        port_log(c);
1.1       ratchov   672:                        log_puts(": failed to open midi port\n");
                    673:                }
                    674:                return 0;
                    675:        }
                    676:        c->state = PORT_INIT;
                    677:        return 1;
1.20      ratchov   678: }
                    679:
1.1       ratchov   680: int
                    681: port_close(struct port *c)
                    682: {
                    683: #ifdef DEBUG
                    684:        if (c->state == PORT_CFG) {
                    685:                port_log(c);
                    686:                log_puts(": can't close port (not opened)\n");
1.3       ratchov   687:                panic();
1.1       ratchov   688:        }
                    689: #endif
1.29    ! ratchov   690:        port_log(c);
        !           691:        log_puts(": closed\n");
1.15      ratchov   692:        c->state = PORT_CFG;
1.1       ratchov   693:        port_mio_close(c);
                    694:        return 1;
                    695: }
                    696:
1.5       ratchov   697: void
                    698: port_drain(struct port *c)
                    699: {
                    700:        struct midi *ep = c->midi;
                    701:
                    702:        if (!(ep->mode & MODE_MIDIOUT) || ep->obuf.used == 0)
                    703:                port_close(c);
                    704:        else {
                    705:                c->state = PORT_DRAIN;
                    706: #ifdef DEBUG
                    707:                if (log_level >= 3) {
                    708:                        port_log(c);
                    709:                        log_puts(": draining\n");
                    710:                }
                    711: #endif
                    712:        }
                    713: }
                    714:
1.1       ratchov   715: int
                    716: port_init(struct port *c)
                    717: {
1.4       ratchov   718:        if (c->hold)
                    719:                return port_open(c);
                    720:        return 1;
1.1       ratchov   721: }
                    722:
                    723: void
                    724: port_done(struct port *c)
                    725: {
1.5       ratchov   726:        if (c->state == PORT_INIT)
                    727:                port_drain(c);
1.1       ratchov   728: }