1*9fd7fddfSratchov /* $OpenBSD: midi.c,v 1.3 2012/11/30 20:48:00 ratchov Exp $ */ 287bc9f6aSratchov /* 387bc9f6aSratchov * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org> 487bc9f6aSratchov * 587bc9f6aSratchov * Permission to use, copy, modify, and distribute this software for any 687bc9f6aSratchov * purpose with or without fee is hereby granted, provided that the above 787bc9f6aSratchov * copyright notice and this permission notice appear in all copies. 887bc9f6aSratchov * 987bc9f6aSratchov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1087bc9f6aSratchov * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1187bc9f6aSratchov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1287bc9f6aSratchov * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1387bc9f6aSratchov * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1487bc9f6aSratchov * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1587bc9f6aSratchov * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1687bc9f6aSratchov */ 1787bc9f6aSratchov /* 1887bc9f6aSratchov * TODO 1987bc9f6aSratchov * 2087bc9f6aSratchov * use shadow variables (to save NRPNs, LSB of controller) 2187bc9f6aSratchov * in the midi merger 2287bc9f6aSratchov */ 2387bc9f6aSratchov #include <stdio.h> 2487bc9f6aSratchov #include <stdlib.h> 2587bc9f6aSratchov #include <string.h> 2687bc9f6aSratchov 2787bc9f6aSratchov #include "abuf.h" 2887bc9f6aSratchov #include "defs.h" 2987bc9f6aSratchov #include "dev.h" 3087bc9f6aSratchov #include "file.h" 3187bc9f6aSratchov #include "midi.h" 3287bc9f6aSratchov #include "miofile.h" 3387bc9f6aSratchov #include "sysex.h" 3487bc9f6aSratchov #include "utils.h" 3587bc9f6aSratchov 3687bc9f6aSratchov /* 3787bc9f6aSratchov * input data rate is XFER / TIMO (in bytes per microsecond), 3887bc9f6aSratchov * it must be slightly larger than the MIDI standard 3125 bytes/s 3987bc9f6aSratchov */ 4087bc9f6aSratchov #define MIDI_XFER 1 4187bc9f6aSratchov #define MIDI_TIMO 100000 4287bc9f6aSratchov 4387bc9f6aSratchov int port_open(struct port *); 4487bc9f6aSratchov void port_imsg(void *, unsigned char *, int); 4587bc9f6aSratchov void port_omsg(void *, unsigned char *, int); 4687bc9f6aSratchov void port_fill(void *, int); 4787bc9f6aSratchov void port_exit(void *); 4887bc9f6aSratchov 4987bc9f6aSratchov struct midiops port_midiops = { 5087bc9f6aSratchov port_imsg, 5187bc9f6aSratchov port_omsg, 5287bc9f6aSratchov port_fill, 5387bc9f6aSratchov port_exit 5487bc9f6aSratchov }; 5587bc9f6aSratchov 5687bc9f6aSratchov #define MIDI_NEP 32 5787bc9f6aSratchov struct midi midi_ep[MIDI_NEP]; 5887bc9f6aSratchov struct timo midi_timo; 5987bc9f6aSratchov struct port *port_list = NULL; 6087bc9f6aSratchov unsigned int midi_portnum = 0; 6187bc9f6aSratchov 6287bc9f6aSratchov struct midithru { 6307826207Sratchov unsigned int txmask, rxmask; 6487bc9f6aSratchov #define MIDITHRU_NMAX 32 6587bc9f6aSratchov } midithru[MIDITHRU_NMAX]; 6687bc9f6aSratchov 6787bc9f6aSratchov /* 6887bc9f6aSratchov * length of voice and common messages (status byte included) 6987bc9f6aSratchov */ 7087bc9f6aSratchov unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 }; 7187bc9f6aSratchov unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 }; 7287bc9f6aSratchov 7387bc9f6aSratchov void 7487bc9f6aSratchov midi_log(struct midi *ep) 7587bc9f6aSratchov { 7687bc9f6aSratchov log_puts("midi"); 7787bc9f6aSratchov log_putu(ep - midi_ep); 7887bc9f6aSratchov } 7987bc9f6aSratchov 8087bc9f6aSratchov void 8187bc9f6aSratchov midi_ontimo(void *arg) 8287bc9f6aSratchov { 8387bc9f6aSratchov int i; 8487bc9f6aSratchov struct midi *ep; 8587bc9f6aSratchov 8687bc9f6aSratchov for (i = MIDI_NEP, ep = midi_ep; i > 0; i--, ep++) { 8787bc9f6aSratchov } 8887bc9f6aSratchov timo_add(&midi_timo, MIDI_TIMO); 8987bc9f6aSratchov } 9087bc9f6aSratchov 9187bc9f6aSratchov void 9287bc9f6aSratchov midi_init(void) 9387bc9f6aSratchov { 9487bc9f6aSratchov timo_set(&midi_timo, midi_ontimo, NULL); 9587bc9f6aSratchov timo_add(&midi_timo, MIDI_TIMO); 9687bc9f6aSratchov } 9787bc9f6aSratchov 9887bc9f6aSratchov void 9987bc9f6aSratchov midi_done(void) 10087bc9f6aSratchov { 10187bc9f6aSratchov timo_del(&midi_timo); 10287bc9f6aSratchov } 10387bc9f6aSratchov 10487bc9f6aSratchov struct midi * 10587bc9f6aSratchov midi_new(struct midiops *ops, void *arg, int mode) 10687bc9f6aSratchov { 10787bc9f6aSratchov int i; 10887bc9f6aSratchov struct midi *ep; 10987bc9f6aSratchov 11087bc9f6aSratchov for (i = 0, ep = midi_ep;; i++, ep++) { 11187bc9f6aSratchov if (i == MIDI_NEP) 11287bc9f6aSratchov return NULL; 11387bc9f6aSratchov if (ep->ops == NULL) 11487bc9f6aSratchov break; 11587bc9f6aSratchov } 11687bc9f6aSratchov ep->ops = ops; 11787bc9f6aSratchov ep->arg = arg; 11887bc9f6aSratchov ep->used = 0; 11987bc9f6aSratchov ep->len = 0; 12087bc9f6aSratchov ep->idx = 0; 12187bc9f6aSratchov ep->st = 0; 12287bc9f6aSratchov ep->txmask = 0; 12307826207Sratchov ep->self = 1 << i; 12407826207Sratchov ep->tickets = 0; 12587bc9f6aSratchov ep->mode = mode; 12607826207Sratchov 12787bc9f6aSratchov /* 12807826207Sratchov * the output buffer is the client intput 12987bc9f6aSratchov */ 13007826207Sratchov if (ep->mode & MODE_MIDIIN) 13187bc9f6aSratchov abuf_init(&ep->obuf, MIDI_BUFSZ); 13207826207Sratchov midi_tickets(ep); 13387bc9f6aSratchov return ep; 13487bc9f6aSratchov } 13587bc9f6aSratchov 13687bc9f6aSratchov void 13787bc9f6aSratchov midi_del(struct midi *ep) 13887bc9f6aSratchov { 13987bc9f6aSratchov int i; 14007826207Sratchov struct midi *peer; 14187bc9f6aSratchov 14207826207Sratchov ep->txmask = 0; 14307826207Sratchov for (i = 0; i < MIDI_NEP; i++) { 14407826207Sratchov peer = midi_ep + i; 14507826207Sratchov if (peer->txmask & ep->self) { 14607826207Sratchov peer->txmask &= ~ep->self; 14707826207Sratchov midi_tickets(peer); 14887bc9f6aSratchov } 14907826207Sratchov } 15007826207Sratchov for (i = 0; i < MIDITHRU_NMAX; i++) { 15107826207Sratchov midithru[i].txmask &= ~ep->self; 15207826207Sratchov midithru[i].rxmask &= ~ep->self; 15307826207Sratchov } 15407826207Sratchov ep->ops = NULL; 15587bc9f6aSratchov if (ep->mode & MODE_MIDIIN) { 15687bc9f6aSratchov abuf_done(&ep->obuf); 15787bc9f6aSratchov } 15887bc9f6aSratchov } 15987bc9f6aSratchov 16087bc9f6aSratchov /* 16107826207Sratchov * connect two midi endpoints 16207826207Sratchov */ 16307826207Sratchov void 16407826207Sratchov midi_link(struct midi *ep, struct midi *peer) 16507826207Sratchov { 16607826207Sratchov if (ep->mode & MODE_MIDIOUT) { 16707826207Sratchov ep->txmask |= peer->self; 16807826207Sratchov midi_tickets(ep); 16907826207Sratchov } 17007826207Sratchov if (ep->mode & MODE_MIDIIN) { 17107826207Sratchov #ifdef DEBUG 17207826207Sratchov if (ep->obuf.used > 0) { 17307826207Sratchov midi_log(ep); 17407826207Sratchov log_puts(": linked with non-empty buffer\n"); 17507826207Sratchov panic(); 17607826207Sratchov } 17707826207Sratchov #endif 17807826207Sratchov /* ep has empry buffer, so no need to call midi_tickets() */ 17907826207Sratchov peer->txmask |= ep->self; 18007826207Sratchov } 18107826207Sratchov } 18207826207Sratchov 18307826207Sratchov /* 18487bc9f6aSratchov * add the midi endpoint in the ``tag'' midi thru box 18587bc9f6aSratchov */ 18687bc9f6aSratchov void 18787bc9f6aSratchov midi_tag(struct midi *ep, unsigned int tag) 18887bc9f6aSratchov { 18907826207Sratchov struct midi *peer; 19007826207Sratchov struct midithru *t = midithru + tag; 19187bc9f6aSratchov int i; 19287bc9f6aSratchov 19307826207Sratchov if (ep->mode & MODE_MIDIOUT) { 19407826207Sratchov ep->txmask |= t->txmask; 19507826207Sratchov midi_tickets(ep); 19607826207Sratchov } 19707826207Sratchov if (ep->mode & MODE_MIDIIN) { 19807826207Sratchov #ifdef DEBUG 19907826207Sratchov if (ep->obuf.used > 0) { 20007826207Sratchov midi_log(ep); 20107826207Sratchov log_puts(": tagged with non-empty buffer\n"); 20207826207Sratchov panic(); 20307826207Sratchov } 20407826207Sratchov #endif 20507826207Sratchov for (i = 0; i < MIDI_NEP; i++) { 20607826207Sratchov if (!(t->rxmask & (1 << i))) 20787bc9f6aSratchov continue; 20807826207Sratchov peer = midi_ep + i; 20907826207Sratchov peer->txmask |= ep->self; 21007826207Sratchov } 21107826207Sratchov } 21287bc9f6aSratchov if (ep->mode & MODE_MIDIOUT) 21307826207Sratchov t->rxmask |= ep->self; 21487bc9f6aSratchov if (ep->mode & MODE_MIDIIN) 21507826207Sratchov t->txmask |= ep->self; 21687bc9f6aSratchov } 21787bc9f6aSratchov 21887bc9f6aSratchov /* 21987bc9f6aSratchov * broadcast the given message to other members of the thru box 22087bc9f6aSratchov */ 22187bc9f6aSratchov void 22287bc9f6aSratchov midi_send(struct midi *iep, unsigned char *msg, int size) 22387bc9f6aSratchov { 22487bc9f6aSratchov struct midi *oep; 22587bc9f6aSratchov int i; 22687bc9f6aSratchov 22787bc9f6aSratchov #ifdef DEBUG 22887bc9f6aSratchov if (log_level >= 4) { 22987bc9f6aSratchov midi_log(iep); 23087bc9f6aSratchov log_puts(": sending:"); 23187bc9f6aSratchov for (i = 0; i < size; i++) { 23287bc9f6aSratchov log_puts(" "); 23387bc9f6aSratchov log_putx(msg[i]); 23487bc9f6aSratchov } 23587bc9f6aSratchov log_puts("\n"); 23687bc9f6aSratchov } 23787bc9f6aSratchov #endif 23887bc9f6aSratchov for (i = 0; i < MIDI_NEP ; i++) { 23987bc9f6aSratchov if ((iep->txmask & (1 << i)) == 0) 24087bc9f6aSratchov continue; 24187bc9f6aSratchov oep = midi_ep + i; 24287bc9f6aSratchov if (msg[0] <= 0x7f) { 24387bc9f6aSratchov if (oep->owner != iep) 24487bc9f6aSratchov continue; 24587bc9f6aSratchov } else if (msg[0] <= 0xf7) 24687bc9f6aSratchov oep->owner = iep; 24787bc9f6aSratchov #ifdef DEBUG 24887bc9f6aSratchov if (log_level >= 4) { 24987bc9f6aSratchov midi_log(iep); 25087bc9f6aSratchov log_puts(" -> "); 25187bc9f6aSratchov midi_log(oep); 25287bc9f6aSratchov log_puts("\n"); 25387bc9f6aSratchov } 25487bc9f6aSratchov #endif 25587bc9f6aSratchov oep->ops->omsg(oep->arg, msg, size); 25687bc9f6aSratchov } 25787bc9f6aSratchov } 25887bc9f6aSratchov 25987bc9f6aSratchov 26007826207Sratchov /* 26107826207Sratchov * determine if we have gained more input tickets, and if so call the 26207826207Sratchov * fill() call-back to notify the i/o layer that it can send more data 26307826207Sratchov */ 26487bc9f6aSratchov void 26507826207Sratchov midi_tickets(struct midi *iep) 26687bc9f6aSratchov { 26707826207Sratchov int i, tickets, avail, maxavail; 26807826207Sratchov struct midi *oep; 26987bc9f6aSratchov 27007826207Sratchov maxavail = MIDI_BUFSZ; 27187bc9f6aSratchov for (i = 0; i < MIDI_NEP ; i++) { 27207826207Sratchov if ((iep->txmask & (1 << i)) == 0) 27387bc9f6aSratchov continue; 27407826207Sratchov oep = midi_ep + i; 27507826207Sratchov avail = oep->obuf.len - oep->obuf.used; 27607826207Sratchov if (maxavail > avail) 27707826207Sratchov maxavail = avail; 27807826207Sratchov } 27907826207Sratchov 28007826207Sratchov /* 28107826207Sratchov * in the worst case output message is twice the 28207826207Sratchov * input message (2-byte messages with running status) 28307826207Sratchov */ 28407826207Sratchov tickets = maxavail / 2 - iep->tickets; 28507826207Sratchov if (tickets > 0) { 28607826207Sratchov iep->tickets += tickets; 28707826207Sratchov iep->ops->fill(iep->arg, tickets); 28887bc9f6aSratchov } 28987bc9f6aSratchov } 29087bc9f6aSratchov 29187bc9f6aSratchov /* 29207826207Sratchov * recalculate tickets of endpoints sending data to this one 29387bc9f6aSratchov */ 29487bc9f6aSratchov void 29507826207Sratchov midi_fill(struct midi *oep) 29607826207Sratchov { 29707826207Sratchov int i; 29807826207Sratchov struct midi *iep; 29907826207Sratchov 30007826207Sratchov for (i = 0; i < MIDI_NEP; i++) { 30107826207Sratchov iep = midi_ep + i; 30207826207Sratchov if (iep->txmask & oep->self) 30307826207Sratchov midi_tickets(iep); 30407826207Sratchov } 30507826207Sratchov } 30607826207Sratchov 30707826207Sratchov /* 30807826207Sratchov * parse then give data chunk, and calling imsg() for each message 30907826207Sratchov */ 31007826207Sratchov void 31107826207Sratchov midi_in(struct midi *iep, unsigned char *idata, int icount) 31287bc9f6aSratchov { 31387bc9f6aSratchov int i; 31487bc9f6aSratchov unsigned char c; 31587bc9f6aSratchov 31687bc9f6aSratchov for (i = 0; i < icount; i++) { 31787bc9f6aSratchov c = *idata++; 31887bc9f6aSratchov if (c >= 0xf8) { 31987bc9f6aSratchov if (c != MIDI_ACK) 32087bc9f6aSratchov iep->ops->imsg(iep->arg, &c, 1); 32187bc9f6aSratchov } else if (c == SYSEX_END) { 32287bc9f6aSratchov if (iep->st == SYSEX_START) { 32387bc9f6aSratchov iep->msg[iep->idx++] = c; 32487bc9f6aSratchov iep->ops->imsg(iep->arg, iep->msg, iep->idx); 32587bc9f6aSratchov } 32687bc9f6aSratchov iep->st = 0; 32787bc9f6aSratchov iep->idx = 0; 32887bc9f6aSratchov } else if (c >= 0xf0) { 32987bc9f6aSratchov iep->msg[0] = c; 33087bc9f6aSratchov iep->len = common_len[c & 7]; 33187bc9f6aSratchov iep->st = c; 33287bc9f6aSratchov iep->idx = 1; 33387bc9f6aSratchov } else if (c >= 0x80) { 33487bc9f6aSratchov iep->msg[0] = c; 33587bc9f6aSratchov iep->len = voice_len[(c >> 4) & 7]; 33687bc9f6aSratchov iep->st = c; 33787bc9f6aSratchov iep->idx = 1; 33887bc9f6aSratchov } else if (iep->st) { 33987bc9f6aSratchov if (iep->idx == 0 && iep->st != SYSEX_START) 34087bc9f6aSratchov iep->msg[iep->idx++] = iep->st; 34187bc9f6aSratchov iep->msg[iep->idx++] = c; 34287bc9f6aSratchov if (iep->idx == iep->len) { 34387bc9f6aSratchov iep->ops->imsg(iep->arg, iep->msg, iep->idx); 34487bc9f6aSratchov if (iep->st >= 0xf0) 34587bc9f6aSratchov iep->st = 0; 34687bc9f6aSratchov iep->idx = 0; 34787bc9f6aSratchov } else if (iep->idx == MIDI_MSGMAX) { 34887bc9f6aSratchov /* sysex continued */ 34987bc9f6aSratchov iep->ops->imsg(iep->arg, iep->msg, iep->idx); 35087bc9f6aSratchov iep->idx = 0; 35187bc9f6aSratchov } 35287bc9f6aSratchov } 35387bc9f6aSratchov } 35407826207Sratchov iep->tickets -= icount; 35507826207Sratchov if (iep->tickets < 0) 35607826207Sratchov iep->tickets = 0; 35787bc9f6aSratchov } 35887bc9f6aSratchov 35987bc9f6aSratchov /* 36087bc9f6aSratchov * store the given message in the output buffer 36187bc9f6aSratchov */ 36287bc9f6aSratchov void 36387bc9f6aSratchov midi_out(struct midi *oep, unsigned char *idata, int icount) 36487bc9f6aSratchov { 36587bc9f6aSratchov unsigned char *odata; 36687bc9f6aSratchov int ocount; 36787bc9f6aSratchov #ifdef DEBUG 36887bc9f6aSratchov int i; 36987bc9f6aSratchov #endif 37087bc9f6aSratchov 37187bc9f6aSratchov while (icount > 0) { 37287bc9f6aSratchov if (oep->obuf.used == oep->obuf.len) { 37387bc9f6aSratchov #ifdef DEBUG 37487bc9f6aSratchov if (log_level >= 2) { 37587bc9f6aSratchov midi_log(oep); 37607826207Sratchov log_puts(": too slow, discarding "); 37787bc9f6aSratchov log_putu(oep->obuf.used); 37887bc9f6aSratchov log_puts(" bytes\n"); 37987bc9f6aSratchov } 38087bc9f6aSratchov #endif 38187bc9f6aSratchov abuf_rdiscard(&oep->obuf, oep->obuf.used); 38287bc9f6aSratchov oep->owner = NULL; 38387bc9f6aSratchov return; 38487bc9f6aSratchov } 38587bc9f6aSratchov odata = abuf_wgetblk(&oep->obuf, &ocount); 38687bc9f6aSratchov if (ocount > icount) 38787bc9f6aSratchov ocount = icount; 38887bc9f6aSratchov memcpy(odata, idata, ocount); 38987bc9f6aSratchov #ifdef DEBUG 39087bc9f6aSratchov if (log_level >= 4) { 39187bc9f6aSratchov midi_log(oep); 39287bc9f6aSratchov log_puts(": out: "); 39387bc9f6aSratchov for (i = 0; i < ocount; i++) { 39487bc9f6aSratchov log_puts(" "); 39587bc9f6aSratchov log_putx(odata[i]); 39687bc9f6aSratchov } 39787bc9f6aSratchov log_puts("\n"); 39887bc9f6aSratchov } 39987bc9f6aSratchov #endif 40087bc9f6aSratchov abuf_wcommit(&oep->obuf, ocount); 40187bc9f6aSratchov icount -= ocount; 40287bc9f6aSratchov idata += ocount; 40387bc9f6aSratchov } 40487bc9f6aSratchov } 40587bc9f6aSratchov 40687bc9f6aSratchov #ifdef DEBUG 40787bc9f6aSratchov void 40887bc9f6aSratchov port_log(struct port *p) 40987bc9f6aSratchov { 41087bc9f6aSratchov midi_log(p->midi); 41187bc9f6aSratchov } 41287bc9f6aSratchov #endif 41387bc9f6aSratchov 41487bc9f6aSratchov void 41587bc9f6aSratchov port_imsg(void *arg, unsigned char *msg, int size) 41687bc9f6aSratchov { 41787bc9f6aSratchov struct port *p = arg; 41887bc9f6aSratchov 41987bc9f6aSratchov midi_send(p->midi, msg, size); 42087bc9f6aSratchov } 42187bc9f6aSratchov 42287bc9f6aSratchov 42387bc9f6aSratchov void 42487bc9f6aSratchov port_omsg(void *arg, unsigned char *msg, int size) 42587bc9f6aSratchov { 42687bc9f6aSratchov struct port *p = arg; 42787bc9f6aSratchov 42887bc9f6aSratchov midi_out(p->midi, msg, size); 42987bc9f6aSratchov } 43087bc9f6aSratchov 43187bc9f6aSratchov void 43287bc9f6aSratchov port_fill(void *arg, int count) 43387bc9f6aSratchov { 43487bc9f6aSratchov /* no flow control */ 43587bc9f6aSratchov } 43687bc9f6aSratchov 43787bc9f6aSratchov void 43887bc9f6aSratchov port_exit(void *arg) 43987bc9f6aSratchov { 44087bc9f6aSratchov #ifdef DEBUG 44187bc9f6aSratchov struct port *p = arg; 44287bc9f6aSratchov 44387bc9f6aSratchov if (log_level >= 3) { 44487bc9f6aSratchov port_log(p); 445*9fd7fddfSratchov log_puts(": port exit\n"); 446*9fd7fddfSratchov panic(); 44787bc9f6aSratchov } 44887bc9f6aSratchov #endif 44987bc9f6aSratchov } 45087bc9f6aSratchov 45187bc9f6aSratchov /* 45287bc9f6aSratchov * create a new midi port 45387bc9f6aSratchov */ 45487bc9f6aSratchov struct port * 45587bc9f6aSratchov port_new(char *path, unsigned int mode) 45687bc9f6aSratchov { 45787bc9f6aSratchov struct port *c; 45887bc9f6aSratchov 45987bc9f6aSratchov c = xmalloc(sizeof(struct port)); 46087bc9f6aSratchov c->path = path; 46187bc9f6aSratchov c->state = PORT_CFG; 46287bc9f6aSratchov c->midi = midi_new(&port_midiops, c, mode); 46387bc9f6aSratchov midi_portnum++; 46487bc9f6aSratchov c->next = port_list; 46587bc9f6aSratchov port_list = c; 46687bc9f6aSratchov return c; 46787bc9f6aSratchov } 46887bc9f6aSratchov 46987bc9f6aSratchov /* 47087bc9f6aSratchov * destroy the given midi port 47187bc9f6aSratchov */ 47287bc9f6aSratchov void 47387bc9f6aSratchov port_del(struct port *c) 47487bc9f6aSratchov { 47587bc9f6aSratchov struct port **p; 47687bc9f6aSratchov 47787bc9f6aSratchov if (c->state != PORT_CFG) 47887bc9f6aSratchov port_close(c); 47987bc9f6aSratchov midi_del(c->midi); 48087bc9f6aSratchov for (p = &port_list; *p != c; p = &(*p)->next) { 48187bc9f6aSratchov #ifdef DEBUG 48287bc9f6aSratchov if (*p == NULL) { 48387bc9f6aSratchov log_puts("port to delete not on list\n"); 48487bc9f6aSratchov panic(); 48587bc9f6aSratchov } 48687bc9f6aSratchov #endif 48787bc9f6aSratchov } 48887bc9f6aSratchov *p = c->next; 48987bc9f6aSratchov xfree(c); 49087bc9f6aSratchov } 49187bc9f6aSratchov 492*9fd7fddfSratchov int 493*9fd7fddfSratchov port_ref(struct port *c) 494*9fd7fddfSratchov { 495*9fd7fddfSratchov #ifdef DEBUG 496*9fd7fddfSratchov if (log_level >= 3) { 497*9fd7fddfSratchov port_log(c); 498*9fd7fddfSratchov log_puts(": port requested\n"); 499*9fd7fddfSratchov } 500*9fd7fddfSratchov #endif 501*9fd7fddfSratchov if (c->state == PORT_CFG && !port_open(c)) 502*9fd7fddfSratchov return 0; 503*9fd7fddfSratchov return 1; 504*9fd7fddfSratchov } 505*9fd7fddfSratchov 506*9fd7fddfSratchov void 507*9fd7fddfSratchov port_unref(struct port *c) 508*9fd7fddfSratchov { 509*9fd7fddfSratchov int i, rxmask; 510*9fd7fddfSratchov 511*9fd7fddfSratchov #ifdef DEBUG 512*9fd7fddfSratchov if (log_level >= 3) { 513*9fd7fddfSratchov port_log(c); 514*9fd7fddfSratchov log_puts(": port released\n"); 515*9fd7fddfSratchov } 516*9fd7fddfSratchov #endif 517*9fd7fddfSratchov for (rxmask = 0, i = 0; i < MIDI_NEP; i++) 518*9fd7fddfSratchov rxmask |= midi_ep[i].txmask; 519*9fd7fddfSratchov if ((rxmask & c->midi->self) == 0 && c->state == PORT_INIT) 520*9fd7fddfSratchov port_close(c); 521*9fd7fddfSratchov } 522*9fd7fddfSratchov 52387bc9f6aSratchov struct port * 52487bc9f6aSratchov port_bynum(int num) 52587bc9f6aSratchov { 52687bc9f6aSratchov struct port *p; 52787bc9f6aSratchov 52887bc9f6aSratchov for (p = port_list; p != NULL; p = p->next) { 52987bc9f6aSratchov if (num-- == 0) 53087bc9f6aSratchov return p; 53187bc9f6aSratchov } 53287bc9f6aSratchov return NULL; 53387bc9f6aSratchov } 53487bc9f6aSratchov 53587bc9f6aSratchov int 53687bc9f6aSratchov port_open(struct port *c) 53787bc9f6aSratchov { 53887bc9f6aSratchov if (!port_mio_open(c)) { 53987bc9f6aSratchov if (log_level >= 1) { 54087bc9f6aSratchov log_puts(c->path); 54187bc9f6aSratchov log_puts(": failed to open midi port\n"); 54287bc9f6aSratchov } 54387bc9f6aSratchov return 0; 54487bc9f6aSratchov } 54587bc9f6aSratchov c->state = PORT_INIT; 54687bc9f6aSratchov return 1; 54787bc9f6aSratchov } 54887bc9f6aSratchov 54987bc9f6aSratchov int 55087bc9f6aSratchov port_close(struct port *c) 55187bc9f6aSratchov { 552*9fd7fddfSratchov int i; 553*9fd7fddfSratchov struct midi *ep; 55487bc9f6aSratchov #ifdef DEBUG 55587bc9f6aSratchov if (c->state == PORT_CFG) { 55687bc9f6aSratchov port_log(c); 55787bc9f6aSratchov log_puts(": can't close port (not opened)\n"); 558*9fd7fddfSratchov panic(); 55987bc9f6aSratchov } 56087bc9f6aSratchov #endif 56187bc9f6aSratchov c->state = PORT_CFG; 562*9fd7fddfSratchov port_mio_close(c); 563*9fd7fddfSratchov 564*9fd7fddfSratchov for (i = 0; i < MIDI_NEP; i++) { 565*9fd7fddfSratchov ep = midi_ep + i; 566*9fd7fddfSratchov if ((ep->txmask & c->midi->self) || 567*9fd7fddfSratchov (c->midi->txmask & ep->self)) 568*9fd7fddfSratchov ep->ops->exit(ep->arg); 569*9fd7fddfSratchov } 57087bc9f6aSratchov return 1; 57187bc9f6aSratchov } 57287bc9f6aSratchov 57387bc9f6aSratchov int 57487bc9f6aSratchov port_init(struct port *c) 57587bc9f6aSratchov { 57687bc9f6aSratchov return port_open(c); 57787bc9f6aSratchov } 57887bc9f6aSratchov 57987bc9f6aSratchov void 58087bc9f6aSratchov port_done(struct port *c) 58187bc9f6aSratchov { 58287bc9f6aSratchov /* XXX: drain? */ 58387bc9f6aSratchov if (c->state != PORT_CFG) 58487bc9f6aSratchov port_close(c); 58587bc9f6aSratchov } 586