File: | dev/midi.c |
Warning: | line 463, column 2 Value stored to 'error' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: midi.c,v 1.56 2023/09/26 19:55:24 mvs 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/kernel.h> |
25 | #include <sys/timeout.h> |
26 | #include <sys/vnode.h> |
27 | #include <sys/signalvar.h> |
28 | #include <sys/device.h> |
29 | |
30 | #include <dev/midi_if.h> |
31 | #include <dev/audio_if.h> |
32 | #include <dev/midivar.h> |
33 | |
34 | #define DEVNAME(sc)((sc)->dev.dv_xname) ((sc)->dev.dv_xname) |
35 | |
36 | int midiopen(dev_t, int, int, struct proc *); |
37 | int midiclose(dev_t, int, int, struct proc *); |
38 | int midiread(dev_t, struct uio *, int); |
39 | int midiwrite(dev_t, struct uio *, int); |
40 | int midikqfilter(dev_t, struct knote *); |
41 | int midiioctl(dev_t, u_long, caddr_t, int, struct proc *); |
42 | int midiprobe(struct device *, void *, void *); |
43 | void midiattach(struct device *, struct device *, void *); |
44 | int mididetach(struct device *, int); |
45 | int midiprint(void *, const char *); |
46 | |
47 | void midi_iintr(void *, int); |
48 | void midi_ointr(void *); |
49 | void midi_timeout(void *); |
50 | void midi_out_start(struct midi_softc *); |
51 | void midi_out_stop(struct midi_softc *); |
52 | void midi_out_do(struct midi_softc *); |
53 | void midi_attach(struct midi_softc *, struct device *); |
54 | |
55 | |
56 | const struct cfattach midi_ca = { |
57 | sizeof(struct midi_softc), midiprobe, midiattach, mididetach |
58 | }; |
59 | |
60 | struct cfdriver midi_cd = { |
61 | NULL((void *)0), "midi", DV_DULL |
62 | }; |
63 | |
64 | |
65 | void filt_midiwdetach(struct knote *); |
66 | int filt_midiwrite(struct knote *, long); |
67 | int filt_midimodify(struct kevent *, struct knote *); |
68 | int filt_midiprocess(struct knote *, struct kevent *); |
69 | |
70 | const struct filterops midiwrite_filtops = { |
71 | .f_flags = FILTEROP_ISFD0x00000001 | FILTEROP_MPSAFE0x00000002, |
72 | .f_attach = NULL((void *)0), |
73 | .f_detach = filt_midiwdetach, |
74 | .f_event = filt_midiwrite, |
75 | .f_modify = filt_midimodify, |
76 | .f_process = filt_midiprocess, |
77 | }; |
78 | |
79 | void filt_midirdetach(struct knote *); |
80 | int filt_midiread(struct knote *, long); |
81 | |
82 | const struct filterops midiread_filtops = { |
83 | .f_flags = FILTEROP_ISFD0x00000001 | FILTEROP_MPSAFE0x00000002, |
84 | .f_attach = NULL((void *)0), |
85 | .f_detach = filt_midirdetach, |
86 | .f_event = filt_midiread, |
87 | .f_modify = filt_midimodify, |
88 | .f_process = filt_midiprocess, |
89 | }; |
90 | |
91 | void |
92 | midi_buf_wakeup(struct midi_buffer *buf) |
93 | { |
94 | if (buf->blocking) { |
95 | wakeup(&buf->blocking); |
96 | buf->blocking = 0; |
97 | } |
98 | knote_locked(&buf->klist, 0); |
99 | } |
100 | |
101 | void |
102 | midi_iintr(void *addr, int data) |
103 | { |
104 | struct midi_softc *sc = (struct midi_softc *)addr; |
105 | struct midi_buffer *mb = &sc->inbuf; |
106 | |
107 | 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); |
108 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001) || !(sc->flags & FREAD0x0001)) |
109 | return; |
110 | |
111 | if (MIDIBUF_ISFULL(mb)((mb)->used >= (1 << 10))) |
112 | return; /* discard data */ |
113 | |
114 | MIDIBUF_WRITE(mb, data)do { (mb)->data[(((mb)->start + (mb)->used) & (( 1 << 10) - 1))] = (data); (mb)->used++; } while(0); |
115 | |
116 | midi_buf_wakeup(mb); |
117 | } |
118 | |
119 | int |
120 | midiread(dev_t dev, struct uio *uio, int ioflag) |
121 | { |
122 | struct midi_softc *sc; |
123 | struct midi_buffer *mb; |
124 | size_t count; |
125 | int error; |
126 | |
127 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
128 | if (sc == NULL((void *)0)) |
129 | return ENXIO6; |
130 | if (!(sc->flags & FREAD0x0001)) { |
131 | error = ENXIO6; |
132 | goto done; |
133 | } |
134 | mb = &sc->inbuf; |
135 | |
136 | /* if there is no data then sleep (unless IO_NDELAY flag is set) */ |
137 | error = 0; |
138 | mtx_enter(&audio_lock); |
139 | while (MIDIBUF_ISEMPTY(mb)((mb)->used == 0)) { |
140 | if (ioflag & IO_NDELAY0x10) { |
141 | error = EWOULDBLOCK35; |
142 | goto done_mtx; |
143 | } |
144 | sc->inbuf.blocking = 1; |
145 | error = msleep_nsec(&sc->inbuf.blocking, &audio_lock, |
146 | PWAIT32 | PCATCH0x100, "mid_rd", INFSLP0xffffffffffffffffULL); |
147 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001)) |
148 | error = EIO5; |
149 | if (error) |
150 | goto done_mtx; |
151 | } |
152 | |
153 | /* at this stage, there is at least 1 byte */ |
154 | |
155 | while (uio->uio_resid > 0 && mb->used > 0) { |
156 | count = MIDIBUF_SIZE(1 << 10) - mb->start; |
157 | if (count > mb->used) |
158 | count = mb->used; |
159 | if (count > uio->uio_resid) |
160 | count = uio->uio_resid; |
161 | mtx_leave(&audio_lock); |
162 | error = uiomove(mb->data + mb->start, count, uio); |
163 | if (error) |
164 | goto done; |
165 | mtx_enter(&audio_lock); |
166 | MIDIBUF_REMOVE(mb, count)do { (mb)->start += (count); (mb)->start &= ((1 << 10) - 1); (mb)->used -= (count); } while(0); |
167 | } |
168 | |
169 | done_mtx: |
170 | mtx_leave(&audio_lock); |
171 | done: |
172 | device_unref(&sc->dev); |
173 | return error; |
174 | } |
175 | |
176 | void |
177 | midi_ointr(void *addr) |
178 | { |
179 | struct midi_softc *sc = (struct midi_softc *)addr; |
180 | struct midi_buffer *mb; |
181 | |
182 | 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); |
183 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001) || !(sc->flags & FWRITE0x0002)) |
184 | return; |
185 | |
186 | mb = &sc->outbuf; |
187 | if (mb->used > 0) { |
188 | #ifdef MIDI_DEBUG |
189 | if (!sc->isbusy) { |
190 | printf("midi_ointr: output must be busy\n"); |
191 | } |
192 | #endif |
193 | midi_out_do(sc); |
194 | } else if (sc->isbusy) |
195 | midi_out_stop(sc); |
196 | } |
197 | |
198 | void |
199 | midi_timeout(void *addr) |
200 | { |
201 | mtx_enter(&audio_lock); |
202 | midi_ointr(addr); |
203 | mtx_leave(&audio_lock); |
204 | } |
205 | |
206 | void |
207 | midi_out_start(struct midi_softc *sc) |
208 | { |
209 | if (!sc->isbusy) { |
210 | sc->isbusy = 1; |
211 | midi_out_do(sc); |
212 | } |
213 | } |
214 | |
215 | void |
216 | midi_out_stop(struct midi_softc *sc) |
217 | { |
218 | sc->isbusy = 0; |
219 | midi_buf_wakeup(&sc->outbuf); |
220 | } |
221 | |
222 | void |
223 | midi_out_do(struct midi_softc *sc) |
224 | { |
225 | struct midi_buffer *mb = &sc->outbuf; |
226 | |
227 | while (mb->used > 0) { |
228 | if (!sc->hw_if->output(sc->hw_hdl, mb->data[mb->start])) |
229 | break; |
230 | MIDIBUF_REMOVE(mb, 1)do { (mb)->start += (1); (mb)->start &= ((1 << 10) - 1); (mb)->used -= (1); } while(0); |
231 | if (MIDIBUF_ISEMPTY(mb)((mb)->used == 0)) { |
232 | if (sc->hw_if->flush != NULL((void *)0)) |
233 | sc->hw_if->flush(sc->hw_hdl); |
234 | midi_out_stop(sc); |
235 | return; |
236 | } |
237 | } |
238 | |
239 | if (!(sc->props & MIDI_PROP_OUT_INTR1)) { |
240 | if (MIDIBUF_ISEMPTY(mb)((mb)->used == 0)) |
241 | midi_out_stop(sc); |
242 | else |
243 | timeout_add(&sc->timeo, 1); |
244 | } |
245 | } |
246 | |
247 | int |
248 | midiwrite(dev_t dev, struct uio *uio, int ioflag) |
249 | { |
250 | struct midi_softc *sc; |
251 | struct midi_buffer *mb; |
252 | size_t count; |
253 | int error; |
254 | |
255 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
256 | if (sc == NULL((void *)0)) |
257 | return ENXIO6; |
258 | if (!(sc->flags & FWRITE0x0002)) { |
259 | error = ENXIO6; |
260 | goto done; |
261 | } |
262 | mb = &sc->outbuf; |
263 | |
264 | /* |
265 | * If IO_NDELAY flag is set then check if there is enough room |
266 | * in the buffer to store at least one byte. If not then dont |
267 | * start the write process. |
268 | */ |
269 | error = 0; |
270 | mtx_enter(&audio_lock); |
271 | if ((ioflag & IO_NDELAY0x10) && MIDIBUF_ISFULL(mb)((mb)->used >= (1 << 10)) && (uio->uio_resid > 0)) { |
272 | error = EWOULDBLOCK35; |
273 | goto done_mtx; |
274 | } |
275 | |
276 | while (uio->uio_resid > 0) { |
277 | while (MIDIBUF_ISFULL(mb)((mb)->used >= (1 << 10))) { |
278 | if (ioflag & IO_NDELAY0x10) { |
279 | /* |
280 | * At this stage at least one byte is already |
281 | * moved so we do not return EWOULDBLOCK |
282 | */ |
283 | goto done_mtx; |
284 | } |
285 | sc->outbuf.blocking = 1; |
286 | error = msleep_nsec(&sc->outbuf.blocking, &audio_lock, |
287 | PWAIT32 | PCATCH0x100, "mid_wr", INFSLP0xffffffffffffffffULL); |
288 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001)) |
289 | error = EIO5; |
290 | if (error) |
291 | goto done_mtx; |
292 | } |
293 | |
294 | count = MIDIBUF_SIZE(1 << 10) - MIDIBUF_END(mb)(((mb)->start + (mb)->used) & ((1 << 10) - 1) ); |
295 | if (count > MIDIBUF_AVAIL(mb)((1 << 10) - (mb)->used)) |
296 | count = MIDIBUF_AVAIL(mb)((1 << 10) - (mb)->used); |
297 | if (count > uio->uio_resid) |
298 | count = uio->uio_resid; |
299 | mtx_leave(&audio_lock); |
300 | error = uiomove(mb->data + MIDIBUF_END(mb)(((mb)->start + (mb)->used) & ((1 << 10) - 1) ), count, uio); |
301 | if (error) |
302 | goto done; |
303 | mtx_enter(&audio_lock); |
304 | mb->used += count; |
305 | midi_out_start(sc); |
306 | } |
307 | |
308 | done_mtx: |
309 | mtx_leave(&audio_lock); |
310 | done: |
311 | device_unref(&sc->dev); |
312 | return error; |
313 | } |
314 | |
315 | int |
316 | midikqfilter(dev_t dev, struct knote *kn) |
317 | { |
318 | struct midi_softc *sc; |
319 | struct klist *klist; |
320 | int error; |
321 | |
322 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
323 | if (sc == NULL((void *)0)) |
324 | return ENXIO6; |
325 | error = 0; |
326 | switch (kn->kn_filterkn_kevent.filter) { |
327 | case EVFILT_READ(-1): |
328 | klist = &sc->inbuf.klist; |
329 | kn->kn_fop = &midiread_filtops; |
330 | break; |
331 | case EVFILT_WRITE(-2): |
332 | klist = &sc->outbuf.klist; |
333 | kn->kn_fop = &midiwrite_filtops; |
334 | break; |
335 | default: |
336 | error = EINVAL22; |
337 | goto done; |
338 | } |
339 | kn->kn_hook = (void *)sc; |
340 | |
341 | klist_insert(klist, kn); |
342 | done: |
343 | device_unref(&sc->dev); |
344 | return error; |
345 | } |
346 | |
347 | void |
348 | filt_midirdetach(struct knote *kn) |
349 | { |
350 | struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; |
351 | |
352 | klist_remove(&sc->inbuf.klist, kn); |
353 | } |
354 | |
355 | int |
356 | filt_midiread(struct knote *kn, long hint) |
357 | { |
358 | struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; |
359 | |
360 | return (!MIDIBUF_ISEMPTY(&sc->inbuf)((&sc->inbuf)->used == 0)); |
361 | } |
362 | |
363 | void |
364 | filt_midiwdetach(struct knote *kn) |
365 | { |
366 | struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; |
367 | |
368 | klist_remove(&sc->outbuf.klist, kn); |
369 | } |
370 | |
371 | int |
372 | filt_midiwrite(struct knote *kn, long hint) |
373 | { |
374 | struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; |
375 | |
376 | return (!MIDIBUF_ISFULL(&sc->outbuf)((&sc->outbuf)->used >= (1 << 10))); |
377 | } |
378 | |
379 | int |
380 | filt_midimodify(struct kevent *kev, struct knote *kn) |
381 | { |
382 | int active; |
383 | |
384 | mtx_enter(&audio_lock); |
385 | active = knote_modify(kev, kn); |
386 | mtx_leave(&audio_lock); |
387 | |
388 | return active; |
389 | } |
390 | |
391 | int |
392 | filt_midiprocess(struct knote *kn, struct kevent *kev) |
393 | { |
394 | int active; |
395 | |
396 | mtx_enter(&audio_lock); |
397 | active = knote_process(kn, kev); |
398 | mtx_leave(&audio_lock); |
399 | |
400 | return active; |
401 | } |
402 | |
403 | int |
404 | midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) |
405 | { |
406 | struct midi_softc *sc; |
407 | int error; |
408 | |
409 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
410 | if (sc == NULL((void *)0)) |
411 | return ENXIO6; |
412 | error = 0; |
413 | switch(cmd) { |
414 | case FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('f')) << 8) | ((126))): |
415 | /* All handled in the upper FS layer */ |
416 | break; |
417 | default: |
418 | error = ENOTTY25; |
419 | } |
420 | device_unref(&sc->dev); |
421 | return error; |
422 | } |
423 | |
424 | int |
425 | midiopen(dev_t dev, int flags, int mode, struct proc *p) |
426 | { |
427 | struct midi_softc *sc; |
428 | int error; |
429 | |
430 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
431 | if (sc == NULL((void *)0)) |
432 | return ENXIO6; |
433 | error = 0; |
434 | if (sc->flags) { |
435 | error = EBUSY16; |
436 | goto done; |
437 | } |
438 | MIDIBUF_INIT(&sc->inbuf)do { (&sc->inbuf)->start = (&sc->inbuf)-> used = 0; } while(0); |
439 | MIDIBUF_INIT(&sc->outbuf)do { (&sc->outbuf)->start = (&sc->outbuf)-> used = 0; } while(0); |
440 | sc->isbusy = 0; |
441 | sc->inbuf.blocking = sc->outbuf.blocking = 0; |
442 | sc->flags = flags; |
443 | error = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc); |
444 | if (error) |
445 | sc->flags = 0; |
446 | done: |
447 | device_unref(&sc->dev); |
448 | return error; |
449 | } |
450 | |
451 | int |
452 | midiclose(dev_t dev, int fflag, int devtype, struct proc *p) |
453 | { |
454 | struct midi_softc *sc; |
455 | struct midi_buffer *mb; |
456 | int error; |
457 | |
458 | sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))); |
459 | if (sc == NULL((void *)0)) |
460 | return ENXIO6; |
461 | |
462 | /* start draining output buffer */ |
463 | error = 0; |
Value stored to 'error' is never read | |
464 | mb = &sc->outbuf; |
465 | mtx_enter(&audio_lock); |
466 | if (!MIDIBUF_ISEMPTY(mb)((mb)->used == 0)) |
467 | midi_out_start(sc); |
468 | while (sc->isbusy) { |
469 | sc->outbuf.blocking = 1; |
470 | error = msleep_nsec(&sc->outbuf.blocking, &audio_lock, |
471 | PWAIT32, "mid_dr", SEC_TO_NSEC(5)); |
472 | if (!(sc->dev.dv_flags & DVF_ACTIVE0x0001)) |
473 | error = EIO5; |
474 | if (error) |
475 | break; |
476 | } |
477 | mtx_leave(&audio_lock); |
478 | |
479 | /* |
480 | * some hw_if->close() reset immediately the midi uart |
481 | * which flushes the internal buffer of the uart device, |
482 | * so we may lose some (important) data. To avoid this, |
483 | * sleep 20ms (around 64 bytes) to give the time to the |
484 | * uart to drain its internal buffers. |
485 | */ |
486 | tsleep_nsec(&sc->outbuf.blocking, PWAIT32, "mid_cl", MSEC_TO_NSEC(20)); |
487 | sc->hw_if->close(sc->hw_hdl); |
488 | sc->flags = 0; |
489 | device_unref(&sc->dev); |
490 | return 0; |
491 | } |
492 | |
493 | int |
494 | midiprobe(struct device *parent, void *match, void *aux) |
495 | { |
496 | struct audio_attach_args *sa = aux; |
497 | |
498 | return (sa != NULL((void *)0) && (sa->type == AUDIODEV_TYPE_MIDI1) ? 1 : 0); |
499 | } |
500 | |
501 | void |
502 | midiattach(struct device *parent, struct device *self, void *aux) |
503 | { |
504 | struct midi_info mi; |
505 | struct midi_softc *sc = (struct midi_softc *)self; |
506 | struct audio_attach_args *sa = (struct audio_attach_args *)aux; |
507 | const struct midi_hw_if *hwif = sa->hwif; |
508 | void *hdl = sa->hdl; |
509 | |
510 | #ifdef DIAGNOSTIC1 |
511 | if (hwif == 0 || |
512 | hwif->open == 0 || |
513 | hwif->close == 0 || |
514 | hwif->output == 0 || |
515 | hwif->getinfo == 0) { |
516 | printf("%s: missing method\n", DEVNAME(sc)((sc)->dev.dv_xname)); |
517 | return; |
518 | } |
519 | #endif |
520 | |
521 | klist_init_mutex(&sc->inbuf.klist, &audio_lock); |
522 | klist_init_mutex(&sc->outbuf.klist, &audio_lock); |
523 | |
524 | sc->hw_if = hwif; |
525 | sc->hw_hdl = hdl; |
526 | sc->hw_if->getinfo(sc->hw_hdl, &mi); |
527 | sc->props = mi.props; |
528 | sc->flags = 0; |
529 | timeout_set(&sc->timeo, midi_timeout, sc); |
530 | printf(": <%s>\n", mi.name); |
531 | } |
532 | |
533 | int |
534 | mididetach(struct device *self, int flags) |
535 | { |
536 | struct midi_softc *sc = (struct midi_softc *)self; |
537 | int maj, mn; |
538 | |
539 | /* locate the major number */ |
540 | for (maj = 0; maj < nchrdev; maj++) { |
541 | if (cdevsw[maj].d_open == midiopen) { |
542 | /* Nuke the vnodes for any open instances (calls close). */ |
543 | mn = self->dv_unit; |
544 | vdevgone(maj, mn, mn, VCHR); |
545 | } |
546 | } |
547 | |
548 | /* |
549 | * The close() method did nothing (device_lookup() returns |
550 | * NULL), so quickly halt transfers (normally parent is already |
551 | * gone, and code below is no-op), and wake-up user-land blocked |
552 | * in read/write/ioctl, which return EIO. |
553 | */ |
554 | if (sc->flags) { |
555 | KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/midi.c" , 555, "_kernel_lock_held()")); |
556 | if (sc->flags & FREAD0x0001) |
557 | wakeup(&sc->inbuf.blocking); |
558 | if (sc->flags & FWRITE0x0002) |
559 | wakeup(&sc->outbuf.blocking); |
560 | sc->hw_if->close(sc->hw_hdl); |
561 | sc->flags = 0; |
562 | } |
563 | |
564 | klist_invalidate(&sc->inbuf.klist); |
565 | klist_invalidate(&sc->outbuf.klist); |
566 | klist_free(&sc->inbuf.klist); |
567 | klist_free(&sc->outbuf.klist); |
568 | |
569 | return 0; |
570 | } |
571 | |
572 | int |
573 | midiprint(void *aux, const char *pnp) |
574 | { |
575 | if (pnp) |
576 | printf("midi at %s", pnp); |
577 | return (UNCONF1); |
578 | } |
579 | |
580 | struct device * |
581 | midi_attach_mi(const struct midi_hw_if *hwif, void *hdl, struct device *dev) |
582 | { |
583 | struct audio_attach_args arg; |
584 | |
585 | arg.type = AUDIODEV_TYPE_MIDI1; |
586 | arg.hwif = hwif; |
587 | arg.hdl = hdl; |
588 | return config_found(dev, &arg, midiprint)config_found_sm((dev), (&arg), (midiprint), ((void *)0)); |
589 | } |