File: | dev/midi.c |
Warning: | line 478, column 2 Value stored to 'error' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: midi.c,v 1.52 2021/10/30 12:48:11 ratchov Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2003, 2004 Alexandre Ratchov |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include <sys/param.h> |
20 | #include <sys/fcntl.h> |
21 | #include <sys/systm.h> |
22 | #include <sys/ioctl.h> |
23 | #include <sys/conf.h> |
24 | #include <sys/poll.h> |
25 | #include <sys/kernel.h> |
26 | #include <sys/timeout.h> |
27 | #include <sys/vnode.h> |
28 | #include <sys/signalvar.h> |
29 | #include <sys/device.h> |
30 | |
31 | #include <dev/midi_if.h> |
32 | #include <dev/audio_if.h> |
33 | #include <dev/midivar.h> |
34 | |
35 | #define IPL_SOFTMIDI0x5 IPL_SOFTNET0x5 |
36 | #define DEVNAME(sc)((sc)->dev.dv_xname) ((sc)->dev.dv_xname) |
37 | |
38 | int midiopen(dev_t, int, int, struct proc *); |
39 | int midiclose(dev_t, int, int, struct proc *); |
40 | int midiread(dev_t, struct uio *, int); |
41 | int midiwrite(dev_t, struct uio *, int); |
42 | int midipoll(dev_t, int, struct proc *); |
43 | int midikqfilter(dev_t, struct knote *); |
44 | int midiioctl(dev_t, u_long, caddr_t, int, struct proc *); |
45 | int midiprobe(struct device *, void *, void *); |
46 | void midiattach(struct device *, struct device *, void *); |
47 | int mididetach(struct device *, int); |
48 | int midiprint(void *, const char *); |
49 | |
50 | void midi_iintr(void *, int); |
51 | void midi_ointr(void *); |
52 | void midi_timeout(void *); |
53 | void midi_out_start(struct midi_softc *); |
54 | void midi_out_stop(struct midi_softc *); |
55 | void midi_out_do(struct midi_softc *); |
56 | void midi_attach(struct midi_softc *, struct device *); |
57 | |
58 | |
59 | struct cfattach midi_ca = { |
60 | sizeof(struct midi_softc), midiprobe, midiattach, mididetach |
61 | }; |
62 | |
63 | struct cfdriver midi_cd = { |
64 | NULL((void *)0), "midi", DV_DULL |
65 | }; |
66 | |
67 | |
68 | void filt_midiwdetach(struct knote *); |
69 | int filt_midiwrite(struct knote *, long); |
70 | |
71 | const struct filterops midiwrite_filtops = { |
72 | .f_flags = FILTEROP_ISFD0x00000001, |
73 | .f_attach = NULL((void *)0), |
74 | .f_detach = filt_midiwdetach, |
75 | .f_event = filt_midiwrite, |
76 | }; |
77 | |
78 | void filt_midirdetach(struct knote *); |
79 | int filt_midiread(struct knote *, long); |
80 | |
81 | const struct filterops midiread_filtops = { |
82 | .f_flags = FILTEROP_ISFD0x00000001, |
83 | .f_attach = NULL((void *)0), |
84 | .f_detach = filt_midirdetach, |
85 | .f_event = filt_midiread, |
86 | }; |
87 | |
88 | void |
89 | midi_buf_wakeup(void *addr) |
90 | { |
91 | struct midi_buffer *buf = addr; |
92 | |
93 | if (buf->blocking) { |
94 | wakeup(&buf->blocking); |
95 | buf->blocking = 0; |
96 | } |
97 | /* |
98 | * As long as selwakeup() grabs the KERNEL_LOCK() make sure it is |
99 | * already held here to avoid lock ordering problems with `audio_lock' |
100 | */ |
101 | KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/midi.c" , 101, "_kernel_lock_held()")); |
102 | mtx_enter(&audio_lock); |
103 | selwakeup(&buf->sel); |
104 | mtx_leave(&audio_lock); |
105 | } |
106 | |
107 | void |
108 | midi_iintr(void *addr, int data) |
109 | { |
110 | struct midi_softc *sc = (struct midi_softc *)addr; |
111 | struct midi_buffer *mb = &sc->inbuf; |
112 | |
113 | MUTEX_ASSERT_LOCKED(&audio_lock)do { if (((&audio_lock)->mtx_owner != ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof (struct cpu_info, ci_self))); __ci;})) && !(panicstr || db_active)) panic("mutex %p not held in %s", (&audio_lock ), __func__); } while (0); |
114 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001) || !(sc->flags & FREAD0x0001)) |
115 | return; |
116 | |
117 | if (MIDIBUF_ISFULL(mb)((mb)->used >= (1 << 10))) |
118 | return; /* discard data */ |
119 | |
120 | MIDIBUF_WRITE(mb, data)do { (mb)->data[(((mb)->start + (mb)->used) & (( 1 << 10) - 1))] = (data); (mb)->used++; } while(0); |
121 | |
122 | /* |
123 | * As long as selwakeup() needs to be protected by the |
124 | * KERNEL_LOCK() we have to delay the wakeup to another |
125 | * context to keep the interrupt context KERNEL_LOCK() |
126 | * free. |
127 | */ |
128 | softintr_schedule(sc->inbuf.softintr)do { struct x86_soft_intrhand *__sih = (sc->inbuf.softintr ); struct x86_soft_intr *__si = __sih->sih_intrhead; mtx_enter (&__si->softintr_lock); if (__sih->sih_pending == 0 ) { do { (__sih)->sih_q.tqe_next = ((void *)0); (__sih)-> sih_q.tqe_prev = (&__si->softintr_q)->tqh_last; *(& __si->softintr_q)->tqh_last = (__sih); (&__si->softintr_q )->tqh_last = &(__sih)->sih_q.tqe_next; } while (0) ; __sih->sih_pending = 1; softintr(__si->softintr_ssir) ; } mtx_leave(&__si->softintr_lock); } while ( 0); |
129 | } |
130 | |
131 | int |
132 | midiread(dev_t dev, struct uio *uio, int ioflag) |
133 | { |
134 | struct midi_softc *sc; |
135 | struct midi_buffer *mb; |
136 | size_t count; |
137 | int error; |
138 | |
139 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
140 | if (sc == NULL((void *)0)) |
141 | return ENXIO6; |
142 | if (!(sc->flags & FREAD0x0001)) { |
143 | error = ENXIO6; |
144 | goto done; |
145 | } |
146 | mb = &sc->inbuf; |
147 | |
148 | /* if there is no data then sleep (unless IO_NDELAY flag is set) */ |
149 | error = 0; |
150 | mtx_enter(&audio_lock); |
151 | while (MIDIBUF_ISEMPTY(mb)((mb)->used == 0)) { |
152 | if (ioflag & IO_NDELAY0x10) { |
153 | error = EWOULDBLOCK35; |
154 | goto done_mtx; |
155 | } |
156 | sc->inbuf.blocking = 1; |
157 | error = msleep_nsec(&sc->inbuf.blocking, &audio_lock, |
158 | PWAIT32 | PCATCH0x100, "mid_rd", INFSLP0xffffffffffffffffULL); |
159 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001)) |
160 | error = EIO5; |
161 | if (error) |
162 | goto done_mtx; |
163 | } |
164 | |
165 | /* at this stage, there is at least 1 byte */ |
166 | |
167 | while (uio->uio_resid > 0 && mb->used > 0) { |
168 | count = MIDIBUF_SIZE(1 << 10) - mb->start; |
169 | if (count > mb->used) |
170 | count = mb->used; |
171 | if (count > uio->uio_resid) |
172 | count = uio->uio_resid; |
173 | mtx_leave(&audio_lock); |
174 | error = uiomove(mb->data + mb->start, count, uio); |
175 | if (error) |
176 | goto done; |
177 | mtx_enter(&audio_lock); |
178 | MIDIBUF_REMOVE(mb, count)do { (mb)->start += (count); (mb)->start &= ((1 << 10) - 1); (mb)->used -= (count); } while(0); |
179 | } |
180 | |
181 | done_mtx: |
182 | mtx_leave(&audio_lock); |
183 | done: |
184 | device_unref(&sc->dev); |
185 | return error; |
186 | } |
187 | |
188 | void |
189 | midi_ointr(void *addr) |
190 | { |
191 | struct midi_softc *sc = (struct midi_softc *)addr; |
192 | struct midi_buffer *mb; |
193 | |
194 | MUTEX_ASSERT_LOCKED(&audio_lock)do { if (((&audio_lock)->mtx_owner != ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof (struct cpu_info, ci_self))); __ci;})) && !(panicstr || db_active)) panic("mutex %p not held in %s", (&audio_lock ), __func__); } while (0); |
195 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001) || !(sc->flags & FWRITE0x0002)) |
196 | return; |
197 | |
198 | mb = &sc->outbuf; |
199 | if (mb->used > 0) { |
200 | #ifdef MIDI_DEBUG |
201 | if (!sc->isbusy) { |
202 | printf("midi_ointr: output must be busy\n"); |
203 | } |
204 | #endif |
205 | midi_out_do(sc); |
206 | } else if (sc->isbusy) |
207 | midi_out_stop(sc); |
208 | } |
209 | |
210 | void |
211 | midi_timeout(void *addr) |
212 | { |
213 | mtx_enter(&audio_lock); |
214 | midi_ointr(addr); |
215 | mtx_leave(&audio_lock); |
216 | } |
217 | |
218 | void |
219 | midi_out_start(struct midi_softc *sc) |
220 | { |
221 | if (!sc->isbusy) { |
222 | sc->isbusy = 1; |
223 | midi_out_do(sc); |
224 | } |
225 | } |
226 | |
227 | void |
228 | midi_out_stop(struct midi_softc *sc) |
229 | { |
230 | sc->isbusy = 0; |
231 | |
232 | /* |
233 | * As long as selwakeup() needs to be protected by the |
234 | * KERNEL_LOCK() we have to delay the wakeup to another |
235 | * context to keep the interrupt context KERNEL_LOCK() |
236 | * free. |
237 | */ |
238 | softintr_schedule(sc->outbuf.softintr)do { struct x86_soft_intrhand *__sih = (sc->outbuf.softintr ); struct x86_soft_intr *__si = __sih->sih_intrhead; mtx_enter (&__si->softintr_lock); if (__sih->sih_pending == 0 ) { do { (__sih)->sih_q.tqe_next = ((void *)0); (__sih)-> sih_q.tqe_prev = (&__si->softintr_q)->tqh_last; *(& __si->softintr_q)->tqh_last = (__sih); (&__si->softintr_q )->tqh_last = &(__sih)->sih_q.tqe_next; } while (0) ; __sih->sih_pending = 1; softintr(__si->softintr_ssir) ; } mtx_leave(&__si->softintr_lock); } while ( 0); |
239 | } |
240 | |
241 | void |
242 | midi_out_do(struct midi_softc *sc) |
243 | { |
244 | struct midi_buffer *mb = &sc->outbuf; |
245 | |
246 | while (mb->used > 0) { |
247 | if (!sc->hw_if->output(sc->hw_hdl, mb->data[mb->start])) |
248 | break; |
249 | MIDIBUF_REMOVE(mb, 1)do { (mb)->start += (1); (mb)->start &= ((1 << 10) - 1); (mb)->used -= (1); } while(0); |
250 | if (MIDIBUF_ISEMPTY(mb)((mb)->used == 0)) { |
251 | if (sc->hw_if->flush != NULL((void *)0)) |
252 | sc->hw_if->flush(sc->hw_hdl); |
253 | midi_out_stop(sc); |
254 | return; |
255 | } |
256 | } |
257 | |
258 | if (!(sc->props & MIDI_PROP_OUT_INTR1)) { |
259 | if (MIDIBUF_ISEMPTY(mb)((mb)->used == 0)) |
260 | midi_out_stop(sc); |
261 | else |
262 | timeout_add(&sc->timeo, 1); |
263 | } |
264 | } |
265 | |
266 | int |
267 | midiwrite(dev_t dev, struct uio *uio, int ioflag) |
268 | { |
269 | struct midi_softc *sc; |
270 | struct midi_buffer *mb; |
271 | size_t count; |
272 | int error; |
273 | |
274 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
275 | if (sc == NULL((void *)0)) |
276 | return ENXIO6; |
277 | if (!(sc->flags & FWRITE0x0002)) { |
278 | error = ENXIO6; |
279 | goto done; |
280 | } |
281 | mb = &sc->outbuf; |
282 | |
283 | /* |
284 | * If IO_NDELAY flag is set then check if there is enough room |
285 | * in the buffer to store at least one byte. If not then dont |
286 | * start the write process. |
287 | */ |
288 | error = 0; |
289 | mtx_enter(&audio_lock); |
290 | if ((ioflag & IO_NDELAY0x10) && MIDIBUF_ISFULL(mb)((mb)->used >= (1 << 10)) && (uio->uio_resid > 0)) { |
291 | error = EWOULDBLOCK35; |
292 | goto done_mtx; |
293 | } |
294 | |
295 | while (uio->uio_resid > 0) { |
296 | while (MIDIBUF_ISFULL(mb)((mb)->used >= (1 << 10))) { |
297 | if (ioflag & IO_NDELAY0x10) { |
298 | /* |
299 | * At this stage at least one byte is already |
300 | * moved so we do not return EWOULDBLOCK |
301 | */ |
302 | goto done_mtx; |
303 | } |
304 | sc->outbuf.blocking = 1; |
305 | error = msleep_nsec(&sc->outbuf.blocking, &audio_lock, |
306 | PWAIT32 | PCATCH0x100, "mid_wr", INFSLP0xffffffffffffffffULL); |
307 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001)) |
308 | error = EIO5; |
309 | if (error) |
310 | goto done_mtx; |
311 | } |
312 | |
313 | count = MIDIBUF_SIZE(1 << 10) - MIDIBUF_END(mb)(((mb)->start + (mb)->used) & ((1 << 10) - 1) ); |
314 | if (count > MIDIBUF_AVAIL(mb)((1 << 10) - (mb)->used)) |
315 | count = MIDIBUF_AVAIL(mb)((1 << 10) - (mb)->used); |
316 | if (count > uio->uio_resid) |
317 | count = uio->uio_resid; |
318 | mtx_leave(&audio_lock); |
319 | error = uiomove(mb->data + MIDIBUF_END(mb)(((mb)->start + (mb)->used) & ((1 << 10) - 1) ), count, uio); |
320 | if (error) |
321 | goto done; |
322 | mtx_enter(&audio_lock); |
323 | mb->used += count; |
324 | midi_out_start(sc); |
325 | } |
326 | |
327 | done_mtx: |
328 | mtx_leave(&audio_lock); |
329 | done: |
330 | device_unref(&sc->dev); |
331 | return error; |
332 | } |
333 | |
334 | int |
335 | midipoll(dev_t dev, int events, struct proc *p) |
336 | { |
337 | struct midi_softc *sc; |
338 | int revents; |
339 | |
340 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
341 | if (sc == NULL((void *)0)) |
342 | return POLLERR0x0008; |
343 | revents = 0; |
344 | mtx_enter(&audio_lock); |
345 | if (events & (POLLIN0x0001 | POLLRDNORM0x0040)) { |
346 | if (!MIDIBUF_ISEMPTY(&sc->inbuf)((&sc->inbuf)->used == 0)) |
347 | revents |= events & (POLLIN0x0001 | POLLRDNORM0x0040); |
348 | } |
349 | if (events & (POLLOUT0x0004 | POLLWRNORM0x0004)) { |
350 | if (!MIDIBUF_ISFULL(&sc->outbuf)((&sc->outbuf)->used >= (1 << 10))) |
351 | revents |= events & (POLLOUT0x0004 | POLLWRNORM0x0004); |
352 | } |
353 | if (revents == 0) { |
354 | if (events & (POLLIN0x0001 | POLLRDNORM0x0040)) |
355 | selrecord(p, &sc->inbuf.sel); |
356 | if (events & (POLLOUT0x0004 | POLLWRNORM0x0004)) |
357 | selrecord(p, &sc->outbuf.sel); |
358 | } |
359 | mtx_leave(&audio_lock); |
360 | device_unref(&sc->dev); |
361 | return (revents); |
362 | } |
363 | |
364 | int |
365 | midikqfilter(dev_t dev, struct knote *kn) |
366 | { |
367 | struct midi_softc *sc; |
368 | struct klist *klist; |
369 | int error; |
370 | |
371 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
372 | if (sc == NULL((void *)0)) |
373 | return ENXIO6; |
374 | error = 0; |
375 | switch (kn->kn_filterkn_kevent.filter) { |
376 | case EVFILT_READ(-1): |
377 | klist = &sc->inbuf.sel.si_note; |
378 | kn->kn_fop = &midiread_filtops; |
379 | break; |
380 | case EVFILT_WRITE(-2): |
381 | klist = &sc->outbuf.sel.si_note; |
382 | kn->kn_fop = &midiwrite_filtops; |
383 | break; |
384 | default: |
385 | error = EINVAL22; |
386 | goto done; |
387 | } |
388 | kn->kn_hook = (void *)sc; |
389 | |
390 | mtx_enter(&audio_lock); |
391 | klist_insert_locked(klist, kn); |
392 | mtx_leave(&audio_lock); |
393 | done: |
394 | device_unref(&sc->dev); |
395 | return error; |
396 | } |
397 | |
398 | void |
399 | filt_midirdetach(struct knote *kn) |
400 | { |
401 | struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; |
402 | |
403 | mtx_enter(&audio_lock); |
404 | klist_remove_locked(&sc->inbuf.sel.si_note, kn); |
405 | mtx_leave(&audio_lock); |
406 | } |
407 | |
408 | int |
409 | filt_midiread(struct knote *kn, long hint) |
410 | { |
411 | struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; |
412 | int retval; |
413 | |
414 | if ((hint & NOTE_SUBMIT0x01000000) == 0) |
415 | mtx_enter(&audio_lock); |
416 | retval = !MIDIBUF_ISEMPTY(&sc->inbuf)((&sc->inbuf)->used == 0); |
417 | if ((hint & NOTE_SUBMIT0x01000000) == 0) |
418 | mtx_leave(&audio_lock); |
419 | |
420 | return (retval); |
421 | } |
422 | |
423 | void |
424 | filt_midiwdetach(struct knote *kn) |
425 | { |
426 | struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; |
427 | |
428 | mtx_enter(&audio_lock); |
429 | klist_remove_locked(&sc->outbuf.sel.si_note, kn); |
430 | mtx_leave(&audio_lock); |
431 | } |
432 | |
433 | int |
434 | filt_midiwrite(struct knote *kn, long hint) |
435 | { |
436 | struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; |
437 | int retval; |
438 | |
439 | if ((hint & NOTE_SUBMIT0x01000000) == 0) |
440 | mtx_enter(&audio_lock); |
441 | retval = !MIDIBUF_ISFULL(&sc->outbuf)((&sc->outbuf)->used >= (1 << 10)); |
442 | if ((hint & NOTE_SUBMIT0x01000000) == 0) |
443 | mtx_leave(&audio_lock); |
444 | |
445 | return (retval); |
446 | } |
447 | |
448 | int |
449 | midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) |
450 | { |
451 | struct midi_softc *sc; |
452 | int error; |
453 | |
454 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
455 | if (sc == NULL((void *)0)) |
456 | return ENXIO6; |
457 | error = 0; |
458 | switch(cmd) { |
459 | case FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('f')) << 8) | ((126))): |
460 | /* All handled in the upper FS layer */ |
461 | break; |
462 | default: |
463 | error = ENOTTY25; |
464 | } |
465 | device_unref(&sc->dev); |
466 | return error; |
467 | } |
468 | |
469 | int |
470 | midiopen(dev_t dev, int flags, int mode, struct proc *p) |
471 | { |
472 | struct midi_softc *sc; |
473 | int error; |
474 | |
475 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
476 | if (sc == NULL((void *)0)) |
477 | return ENXIO6; |
478 | error = 0; |
Value stored to 'error' is never read | |
479 | if (sc->flags) { |
480 | error = EBUSY16; |
481 | goto done; |
482 | } |
483 | MIDIBUF_INIT(&sc->inbuf)do { (&sc->inbuf)->start = (&sc->inbuf)-> used = 0; } while(0); |
484 | MIDIBUF_INIT(&sc->outbuf)do { (&sc->outbuf)->start = (&sc->outbuf)-> used = 0; } while(0); |
485 | sc->isbusy = 0; |
486 | sc->inbuf.blocking = sc->outbuf.blocking = 0; |
487 | sc->flags = flags; |
488 | error = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc); |
489 | if (error) |
490 | sc->flags = 0; |
491 | done: |
492 | device_unref(&sc->dev); |
493 | return error; |
494 | } |
495 | |
496 | int |
497 | midiclose(dev_t dev, int fflag, int devtype, struct proc *p) |
498 | { |
499 | struct midi_softc *sc; |
500 | struct midi_buffer *mb; |
501 | int error; |
502 | |
503 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
504 | if (sc == NULL((void *)0)) |
505 | return ENXIO6; |
506 | |
507 | /* start draining output buffer */ |
508 | error = 0; |
509 | mb = &sc->outbuf; |
510 | mtx_enter(&audio_lock); |
511 | if (!MIDIBUF_ISEMPTY(mb)((mb)->used == 0)) |
512 | midi_out_start(sc); |
513 | while (sc->isbusy) { |
514 | sc->outbuf.blocking = 1; |
515 | error = msleep_nsec(&sc->outbuf.blocking, &audio_lock, |
516 | PWAIT32, "mid_dr", SEC_TO_NSEC(5)); |
517 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001)) |
518 | error = EIO5; |
519 | if (error) |
520 | break; |
521 | } |
522 | mtx_leave(&audio_lock); |
523 | |
524 | /* |
525 | * some hw_if->close() reset immediately the midi uart |
526 | * which flushes the internal buffer of the uart device, |
527 | * so we may lose some (important) data. To avoid this, |
528 | * sleep 20ms (around 64 bytes) to give the time to the |
529 | * uart to drain its internal buffers. |
530 | */ |
531 | tsleep_nsec(&sc->outbuf.blocking, PWAIT32, "mid_cl", MSEC_TO_NSEC(20)); |
532 | sc->hw_if->close(sc->hw_hdl); |
533 | sc->flags = 0; |
534 | device_unref(&sc->dev); |
535 | return 0; |
536 | } |
537 | |
538 | int |
539 | midiprobe(struct device *parent, void *match, void *aux) |
540 | { |
541 | struct audio_attach_args *sa = aux; |
542 | |
543 | return (sa != NULL((void *)0) && (sa->type == AUDIODEV_TYPE_MIDI1) ? 1 : 0); |
544 | } |
545 | |
546 | void |
547 | midiattach(struct device *parent, struct device *self, void *aux) |
548 | { |
549 | struct midi_info mi; |
550 | struct midi_softc *sc = (struct midi_softc *)self; |
551 | struct audio_attach_args *sa = (struct audio_attach_args *)aux; |
552 | struct midi_hw_if *hwif = sa->hwif; |
553 | void *hdl = sa->hdl; |
554 | |
555 | #ifdef DIAGNOSTIC1 |
556 | if (hwif == 0 || |
557 | hwif->open == 0 || |
558 | hwif->close == 0 || |
559 | hwif->output == 0 || |
560 | hwif->getinfo == 0) { |
561 | printf("%s: missing method\n", DEVNAME(sc)((sc)->dev.dv_xname)); |
562 | return; |
563 | } |
564 | #endif |
565 | |
566 | sc->inbuf.softintr = softintr_establish(IPL_SOFTMIDI0x5, |
567 | midi_buf_wakeup, &sc->inbuf); |
568 | if (sc->inbuf.softintr == NULL((void *)0)) { |
569 | printf("%s: can't establish input softintr\n", DEVNAME(sc)((sc)->dev.dv_xname)); |
570 | return; |
571 | } |
572 | |
573 | sc->outbuf.softintr = softintr_establish(IPL_SOFTMIDI0x5, |
574 | midi_buf_wakeup, &sc->outbuf); |
575 | if (sc->outbuf.softintr == NULL((void *)0)) { |
576 | printf("%s: can't establish output softintr\n", DEVNAME(sc)((sc)->dev.dv_xname)); |
577 | softintr_disestablish(sc->inbuf.softintr); |
578 | return; |
579 | } |
580 | |
581 | sc->hw_if = hwif; |
582 | sc->hw_hdl = hdl; |
583 | sc->hw_if->getinfo(sc->hw_hdl, &mi); |
584 | sc->props = mi.props; |
585 | sc->flags = 0; |
586 | timeout_set(&sc->timeo, midi_timeout, sc); |
587 | printf(": <%s>\n", mi.name); |
588 | } |
589 | |
590 | int |
591 | mididetach(struct device *self, int flags) |
592 | { |
593 | struct midi_softc *sc = (struct midi_softc *)self; |
594 | int maj, mn; |
595 | |
596 | /* locate the major number */ |
597 | for (maj = 0; maj < nchrdev; maj++) { |
598 | if (cdevsw[maj].d_open == midiopen) { |
599 | /* Nuke the vnodes for any open instances (calls close). */ |
600 | mn = self->dv_unit; |
601 | vdevgone(maj, mn, mn, VCHR); |
602 | } |
603 | } |
604 | |
605 | /* |
606 | * The close() method did nothing (device_lookup() returns |
607 | * NULL), so quickly halt transfers (normally parent is already |
608 | * gone, and code below is no-op), and wake-up user-land blocked |
609 | * in read/write/ioctl, which return EIO. |
610 | */ |
611 | if (sc->flags) { |
612 | KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/midi.c" , 612, "_kernel_lock_held()")); |
613 | if (sc->flags & FREAD0x0001) { |
614 | wakeup(&sc->inbuf.blocking); |
615 | mtx_enter(&audio_lock); |
616 | selwakeup(&sc->inbuf.sel); |
617 | mtx_leave(&audio_lock); |
618 | } |
619 | if (sc->flags & FWRITE0x0002) { |
620 | wakeup(&sc->outbuf.blocking); |
621 | mtx_enter(&audio_lock); |
622 | selwakeup(&sc->outbuf.sel); |
623 | mtx_leave(&audio_lock); |
624 | } |
625 | sc->hw_if->close(sc->hw_hdl); |
626 | sc->flags = 0; |
627 | } |
628 | |
629 | klist_invalidate(&sc->inbuf.sel.si_note); |
630 | klist_invalidate(&sc->outbuf.sel.si_note); |
631 | |
632 | if (sc->inbuf.softintr) |
633 | softintr_disestablish(sc->inbuf.softintr); |
634 | if (sc->outbuf.softintr) |
635 | softintr_disestablish(sc->outbuf.softintr); |
636 | return 0; |
637 | } |
638 | |
639 | int |
640 | midiprint(void *aux, const char *pnp) |
641 | { |
642 | if (pnp) |
643 | printf("midi at %s", pnp); |
644 | return (UNCONF1); |
645 | } |
646 | |
647 | struct device * |
648 | midi_attach_mi(struct midi_hw_if *hwif, void *hdl, struct device *dev) |
649 | { |
650 | struct audio_attach_args arg; |
651 | |
652 | arg.type = AUDIODEV_TYPE_MIDI1; |
653 | arg.hwif = hwif; |
654 | arg.hdl = hdl; |
655 | return config_found(dev, &arg, midiprint)config_found_sm((dev), (&arg), (midiprint), ((void *)0)); |
656 | } |