diff --git a/sndiod/midi.c b/sndiod/midi.c index d133b55..9c1beb6 100644 --- a/sndiod/midi.c +++ b/sndiod/midi.c @@ -443,7 +443,8 @@ port_exit(void *arg) if (log_level >= 3) { port_log(p); - log_puts(": exit\n"); + log_puts(": port exit\n"); + panic(); } #endif } @@ -489,6 +490,37 @@ port_del(struct port *c) xfree(c); } +int +port_ref(struct port *c) +{ +#ifdef DEBUG + if (log_level >= 3) { + port_log(c); + log_puts(": port requested\n"); + } +#endif + if (c->state == PORT_CFG && !port_open(c)) + return 0; + return 1; +} + +void +port_unref(struct port *c) +{ + int i, rxmask; + +#ifdef DEBUG + if (log_level >= 3) { + port_log(c); + log_puts(": port released\n"); + } +#endif + for (rxmask = 0, i = 0; i < MIDI_NEP; i++) + rxmask |= midi_ep[i].txmask; + if ((rxmask & c->midi->self) == 0 && c->state == PORT_INIT) + port_close(c); +} + struct port * port_bynum(int num) { @@ -518,14 +550,24 @@ port_open(struct port *c) int port_close(struct port *c) { + int i; + struct midi *ep; #ifdef DEBUG if (c->state == PORT_CFG) { port_log(c); log_puts(": can't close port (not opened)\n"); + panic(); } #endif - port_mio_close(c); c->state = PORT_CFG; + port_mio_close(c); + + for (i = 0; i < MIDI_NEP; i++) { + ep = midi_ep + i; + if ((ep->txmask & c->midi->self) || + (c->midi->txmask & ep->self)) + ep->ops->exit(ep->arg); + } return 1; } diff --git a/sndiod/midi.h b/sndiod/midi.h index 5bfbae6..20d10fe 100644 --- a/sndiod/midi.h +++ b/sndiod/midi.h @@ -89,7 +89,6 @@ struct port { unsigned int state; char *path; struct midi *midi; - unsigned int refs; }; /* @@ -113,6 +112,8 @@ void midi_link(struct midi *, struct midi *); struct port *port_new(char *, unsigned int); struct port *port_bynum(int); void port_del(struct port *); +int port_ref(struct port *); +void port_unref(struct port *); int port_init(struct port *); void port_done(struct port *); int port_close(struct port *); diff --git a/sndiod/sock.c b/sndiod/sock.c index 911f925..9e78444 100644 --- a/sndiod/sock.c +++ b/sndiod/sock.c @@ -151,6 +151,10 @@ sock_close(struct sock *f) midi_del(f->midi); f->midi = NULL; } + if (f->port) { + port_unref(f->port); + f->port = NULL; + } file_del(f->file); close(f->fd); xfree(f); @@ -850,6 +854,7 @@ sock_hello(struct sock *f) } f->pstate = SOCK_INIT; if (mode & MODE_MIDIMASK) { + f->port = NULL; f->slot = NULL; f->midi = midi_new(&sock_midiops, f, mode); if (f->midi == NULL) @@ -864,8 +869,9 @@ sock_hello(struct sock *f) midi_tag(f->midi, p->devnum); } else if (p->devnum < 48) { c = port_bynum(p->devnum - 32); - if (c == NULL) + if (c == NULL || !port_ref(c)) return 0; + f->port = c; midi_link(f->midi, c->midi); } else return 0; diff --git a/sndiod/sock.h b/sndiod/sock.h index 9a99682..6d1778e 100644 --- a/sndiod/sock.h +++ b/sndiod/sock.h @@ -58,7 +58,8 @@ struct sock { int lastvol; /* last volume */ struct opt *opt; /* "subdevice" definition */ struct slot *slot; /* audio device slot number */ - struct midi *midi; /* midi endpoint number */ + struct midi *midi; /* midi endpoint */ + struct port *port; /* midi port */ char who[12]; /* label, mostly for debugging */ };