1 /* $OpenBSD: miofile.c,v 1.9 2021/11/01 14:43:25 ratchov Exp $ */
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
18 #include <sys/types.h>
19 #include <sys/time.h>
20
21 #include <poll.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sndio.h>
26 #include "defs.h"
27 #include "fdpass.h"
28 #include "file.h"
29 #include "midi.h"
30 #include "miofile.h"
31 #include "utils.h"
32
33 int port_mio_pollfd(void *, struct pollfd *);
34 int port_mio_revents(void *, struct pollfd *);
35 void port_mio_in(void *);
36 void port_mio_out(void *);
37 void port_mio_hup(void *);
38
39 struct fileops port_mio_ops = {
40 "mio",
41 port_mio_pollfd,
42 port_mio_revents,
43 port_mio_in,
44 port_mio_out,
45 port_mio_hup
46 };
47
48 int
port_mio_open(struct port * p)49 port_mio_open(struct port *p)
50 {
51 p->mio.hdl = fdpass_mio_open(p->num, p->midi->mode);
52 if (p->mio.hdl == NULL)
53 return 0;
54 p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(p->mio.hdl));
55 return 1;
56 }
57
58 void
port_mio_close(struct port * p)59 port_mio_close(struct port *p)
60 {
61 file_del(p->mio.file);
62 mio_close(p->mio.hdl);
63 }
64
65 int
port_mio_pollfd(void * addr,struct pollfd * pfd)66 port_mio_pollfd(void *addr, struct pollfd *pfd)
67 {
68 struct port *p = addr;
69 struct midi *ep = p->midi;
70 int events = 0;
71
72 if (ep->mode & MODE_MIDIIN)
73 events |= POLLIN;
74 if ((ep->mode & MODE_MIDIOUT) && ep->obuf.used > 0)
75 events |= POLLOUT;
76 return mio_pollfd(p->mio.hdl, pfd, events);
77 }
78
79 int
port_mio_revents(void * addr,struct pollfd * pfd)80 port_mio_revents(void *addr, struct pollfd *pfd)
81 {
82 struct port *p = addr;
83
84 return mio_revents(p->mio.hdl, pfd);
85 }
86
87 void
port_mio_in(void * arg)88 port_mio_in(void *arg)
89 {
90 unsigned char data[MIDI_BUFSZ];
91 struct port *p = arg;
92 struct midi *ep = p->midi;
93 int n;
94
95 for (;;) {
96 n = mio_read(p->mio.hdl, data, MIDI_BUFSZ);
97 if (n == 0)
98 break;
99 midi_in(ep, data, n);
100 }
101 }
102
103 void
port_mio_out(void * arg)104 port_mio_out(void *arg)
105 {
106 struct port *p = arg;
107 struct midi *ep = p->midi;
108 unsigned char *data;
109 int n, count;
110
111 for (;;) {
112 data = abuf_rgetblk(&ep->obuf, &count);
113 if (count == 0)
114 break;
115 n = mio_write(p->mio.hdl, data, count);
116 if (n == 0)
117 break;
118 abuf_rdiscard(&ep->obuf, n);
119 if (n < count)
120 break;
121 }
122 if (p->state == PORT_DRAIN && ep->obuf.used == 0)
123 port_close(p);
124 midi_fill(ep);
125 }
126
127 void
port_mio_hup(void * arg)128 port_mio_hup(void *arg)
129 {
130 struct port *p = arg;
131
132 port_migrate(p);
133 midi_abort(p->midi);
134 if (p->state != PORT_CFG)
135 port_close(p);
136 }
137