[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.31

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