| File: | dev/usb/umidi.c |
| Warning: | line 753, column 19 Access to field 'endpoint' results in a dereference of a null pointer (loaded from variable 'jack') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: umidi.c,v 1.54 2020/07/31 10:49:33 mglocker Exp $ */ | |||
| 2 | /* $NetBSD: umidi.c,v 1.16 2002/07/11 21:14:32 augustss Exp $ */ | |||
| 3 | /* | |||
| 4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. | |||
| 5 | * All rights reserved. | |||
| 6 | * | |||
| 7 | * This code is derived from software contributed to The NetBSD Foundation | |||
| 8 | * by Takuya SHIOZAKI (tshiozak@netbsd.org). | |||
| 9 | * | |||
| 10 | * Redistribution and use in source and binary forms, with or without | |||
| 11 | * modification, are permitted provided that the following conditions | |||
| 12 | * are met: | |||
| 13 | * 1. Redistributions of source code must retain the above copyright | |||
| 14 | * notice, this list of conditions and the following disclaimer. | |||
| 15 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 16 | * notice, this list of conditions and the following disclaimer in the | |||
| 17 | * documentation and/or other materials provided with the distribution. | |||
| 18 | * | |||
| 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |||
| 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
| 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
| 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |||
| 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
| 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
| 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
| 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
| 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
| 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
| 29 | * POSSIBILITY OF SUCH DAMAGE. | |||
| 30 | */ | |||
| 31 | ||||
| 32 | #include <sys/param.h> | |||
| 33 | #include <sys/systm.h> | |||
| 34 | #include <sys/kernel.h> | |||
| 35 | #include <sys/malloc.h> | |||
| 36 | #include <sys/device.h> | |||
| 37 | #include <sys/ioctl.h> | |||
| 38 | #include <sys/conf.h> | |||
| 39 | #include <sys/fcntl.h> | |||
| 40 | #include <sys/selinfo.h> | |||
| 41 | #include <sys/poll.h> | |||
| 42 | ||||
| 43 | #include <dev/usb/usb.h> | |||
| 44 | #include <dev/usb/usbdi.h> | |||
| 45 | #include <dev/usb/usbdi_util.h> | |||
| 46 | ||||
| 47 | #include <dev/usb/umidireg.h> | |||
| 48 | #include <dev/usb/umidivar.h> | |||
| 49 | #include <dev/usb/umidi_quirks.h> | |||
| 50 | ||||
| 51 | #include <dev/audio_if.h> | |||
| 52 | #include <dev/midi_if.h> | |||
| 53 | ||||
| 54 | #ifdef UMIDI_DEBUG | |||
| 55 | #define DPRINTF(x) if (umididebug) printf x | |||
| 56 | #define DPRINTFN(n,x) if (umididebug >= (n)) printf x | |||
| 57 | int umididebug = 0; | |||
| 58 | #else | |||
| 59 | #define DPRINTF(x) | |||
| 60 | #define DPRINTFN(n,x) | |||
| 61 | #endif | |||
| 62 | ||||
| 63 | ||||
| 64 | static int umidi_open(void *, int, | |||
| 65 | void (*)(void *, int), void (*)(void *), void *); | |||
| 66 | static void umidi_close(void *); | |||
| 67 | static int umidi_output(void *, int); | |||
| 68 | static void umidi_flush(void *); | |||
| 69 | static void umidi_getinfo(void *, struct midi_info *); | |||
| 70 | ||||
| 71 | static usbd_status alloc_pipe(struct umidi_endpoint *); | |||
| 72 | static void free_pipe(struct umidi_endpoint *); | |||
| 73 | ||||
| 74 | static usbd_status alloc_all_endpoints(struct umidi_softc *); | |||
| 75 | static void free_all_endpoints(struct umidi_softc *); | |||
| 76 | ||||
| 77 | static usbd_status alloc_all_jacks(struct umidi_softc *); | |||
| 78 | static void free_all_jacks(struct umidi_softc *); | |||
| 79 | static usbd_status bind_jacks_to_mididev(struct umidi_softc *, | |||
| 80 | struct umidi_jack *, | |||
| 81 | struct umidi_jack *, | |||
| 82 | struct umidi_mididev *); | |||
| 83 | static void unbind_jacks_from_mididev(struct umidi_mididev *); | |||
| 84 | static void unbind_all_jacks(struct umidi_softc *); | |||
| 85 | static usbd_status assign_all_jacks_automatically(struct umidi_softc *); | |||
| 86 | static usbd_status open_out_jack(struct umidi_jack *, void *, | |||
| 87 | void (*)(void *)); | |||
| 88 | static usbd_status open_in_jack(struct umidi_jack *, void *, | |||
| 89 | void (*)(void *, int)); | |||
| 90 | static void close_jack(struct umidi_jack *); | |||
| 91 | ||||
| 92 | static usbd_status attach_mididev(struct umidi_softc *, | |||
| 93 | struct umidi_mididev *); | |||
| 94 | static usbd_status detach_mididev(struct umidi_mididev *, int); | |||
| 95 | static usbd_status deactivate_mididev(struct umidi_mididev *); | |||
| 96 | static usbd_status alloc_all_mididevs(struct umidi_softc *, int); | |||
| 97 | static void free_all_mididevs(struct umidi_softc *); | |||
| 98 | static usbd_status attach_all_mididevs(struct umidi_softc *); | |||
| 99 | static usbd_status detach_all_mididevs(struct umidi_softc *, int); | |||
| 100 | static usbd_status deactivate_all_mididevs(struct umidi_softc *); | |||
| 101 | ||||
| 102 | #ifdef UMIDI_DEBUG | |||
| 103 | static void dump_sc(struct umidi_softc *); | |||
| 104 | static void dump_ep(struct umidi_endpoint *); | |||
| 105 | static void dump_jack(struct umidi_jack *); | |||
| 106 | #endif | |||
| 107 | ||||
| 108 | static void init_packet(struct umidi_packet *); | |||
| 109 | ||||
| 110 | static usbd_status start_input_transfer(struct umidi_endpoint *); | |||
| 111 | static usbd_status start_output_transfer(struct umidi_endpoint *); | |||
| 112 | static int out_jack_output(struct umidi_jack *, int); | |||
| 113 | static void out_jack_flush(struct umidi_jack *); | |||
| 114 | static void in_intr(struct usbd_xfer *, void *, usbd_status); | |||
| 115 | static void out_intr(struct usbd_xfer *, void *, usbd_status); | |||
| 116 | static int out_build_packet(int, struct umidi_packet *, uByte, u_char *); | |||
| 117 | ||||
| 118 | ||||
| 119 | struct midi_hw_if umidi_hw_if = { | |||
| 120 | umidi_open, | |||
| 121 | umidi_close, | |||
| 122 | umidi_output, | |||
| 123 | umidi_flush, /* flush */ | |||
| 124 | umidi_getinfo, | |||
| 125 | 0, /* ioctl */ | |||
| 126 | }; | |||
| 127 | ||||
| 128 | int umidi_match(struct device *, void *, void *); | |||
| 129 | void umidi_attach(struct device *, struct device *, void *); | |||
| 130 | int umidi_detach(struct device *, int); | |||
| 131 | int umidi_activate(struct device *, int); | |||
| 132 | ||||
| 133 | struct cfdriver umidi_cd = { | |||
| 134 | NULL((void *)0), "umidi", DV_DULL | |||
| 135 | }; | |||
| 136 | ||||
| 137 | const struct cfattach umidi_ca = { | |||
| 138 | sizeof(struct umidi_softc), | |||
| 139 | umidi_match, | |||
| 140 | umidi_attach, | |||
| 141 | umidi_detach, | |||
| 142 | umidi_activate, | |||
| 143 | }; | |||
| 144 | ||||
| 145 | int | |||
| 146 | umidi_match(struct device *parent, void *match, void *aux) | |||
| 147 | { | |||
| 148 | struct usb_attach_arg *uaa = aux; | |||
| 149 | usb_interface_descriptor_t *id; | |||
| 150 | ||||
| 151 | DPRINTFN(1,("%s\n", __func__)); | |||
| 152 | ||||
| 153 | if (uaa->iface == NULL((void *)0)) | |||
| 154 | return UMATCH_NONE0; | |||
| 155 | ||||
| 156 | if (umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno)) | |||
| 157 | return UMATCH_IFACECLASS_IFACESUBCLASS4; | |||
| 158 | ||||
| 159 | id = usbd_get_interface_descriptor(uaa->iface); | |||
| 160 | if (id!=NULL((void *)0) && | |||
| 161 | id->bInterfaceClass==UICLASS_AUDIO0x01 && | |||
| 162 | id->bInterfaceSubClass==UISUBCLASS_MIDISTREAM3) | |||
| 163 | return UMATCH_IFACECLASS_IFACESUBCLASS4; | |||
| 164 | ||||
| 165 | return UMATCH_NONE0; | |||
| 166 | } | |||
| 167 | ||||
| 168 | void | |||
| 169 | umidi_attach(struct device *parent, struct device *self, void *aux) | |||
| 170 | { | |||
| 171 | usbd_status err; | |||
| 172 | struct umidi_softc *sc = (struct umidi_softc *)self; | |||
| 173 | struct usb_attach_arg *uaa = aux; | |||
| 174 | int i; | |||
| 175 | ||||
| 176 | DPRINTFN(1,("%s\n", __func__)); | |||
| 177 | ||||
| 178 | sc->sc_iface = uaa->iface; | |||
| 179 | sc->sc_udev = uaa->device; | |||
| 180 | ||||
| 181 | sc->sc_quirk = | |||
| 182 | umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno); | |||
| 183 | printf("%s: ", sc->sc_dev.dv_xname); | |||
| 184 | umidi_print_quirk(sc->sc_quirk); | |||
| 185 | ||||
| 186 | err = alloc_all_endpoints(sc); | |||
| 187 | if (err!=USBD_NORMAL_COMPLETION) | |||
| ||||
| 188 | goto error; | |||
| 189 | err = alloc_all_jacks(sc); | |||
| 190 | if (err!=USBD_NORMAL_COMPLETION) { | |||
| 191 | free_all_endpoints(sc); | |||
| 192 | goto error; | |||
| 193 | } | |||
| 194 | printf("%s: out=%d, in=%d\n", | |||
| 195 | sc->sc_dev.dv_xname, | |||
| 196 | sc->sc_out_num_jacks, sc->sc_in_num_jacks); | |||
| 197 | ||||
| 198 | err = assign_all_jacks_automatically(sc); | |||
| 199 | if (err!=USBD_NORMAL_COMPLETION) { | |||
| 200 | unbind_all_jacks(sc); | |||
| 201 | free_all_jacks(sc); | |||
| 202 | free_all_endpoints(sc); | |||
| 203 | goto error; | |||
| 204 | } | |||
| 205 | err = attach_all_mididevs(sc); | |||
| 206 | if (err!=USBD_NORMAL_COMPLETION) { | |||
| 207 | unbind_all_jacks(sc); | |||
| 208 | free_all_jacks(sc); | |||
| 209 | free_all_endpoints(sc); | |||
| 210 | goto error; | |||
| 211 | } | |||
| 212 | ||||
| 213 | #ifdef UMIDI_DEBUG | |||
| 214 | dump_sc(sc); | |||
| 215 | #endif | |||
| 216 | ||||
| 217 | for (i = 0; i < sc->sc_in_num_endpoints; i++) | |||
| 218 | (void)start_input_transfer(&sc->sc_in_ep[i]); | |||
| 219 | return; | |||
| 220 | error: | |||
| 221 | printf("%s: disabled.\n", sc->sc_dev.dv_xname); | |||
| 222 | usbd_deactivate(sc->sc_udev); | |||
| 223 | } | |||
| 224 | ||||
| 225 | int | |||
| 226 | umidi_activate(struct device *self, int act) | |||
| 227 | { | |||
| 228 | struct umidi_softc *sc = (struct umidi_softc *)self; | |||
| 229 | ||||
| 230 | if (act == DVACT_DEACTIVATE1) { | |||
| 231 | DPRINTFN(1,("%s (deactivate)\n", __func__)); | |||
| 232 | usbd_deactivate(sc->sc_udev); | |||
| 233 | deactivate_all_mididevs(sc); | |||
| 234 | } | |||
| 235 | return 0; | |||
| 236 | } | |||
| 237 | ||||
| 238 | int | |||
| 239 | umidi_detach(struct device *self, int flags) | |||
| 240 | { | |||
| 241 | struct umidi_softc *sc = (struct umidi_softc *)self; | |||
| 242 | ||||
| 243 | DPRINTFN(1,("%s\n", __func__)); | |||
| 244 | ||||
| 245 | detach_all_mididevs(sc, flags); | |||
| 246 | free_all_mididevs(sc); | |||
| 247 | free_all_jacks(sc); | |||
| 248 | free_all_endpoints(sc); | |||
| 249 | ||||
| 250 | return 0; | |||
| 251 | } | |||
| 252 | ||||
| 253 | ||||
| 254 | /* | |||
| 255 | * midi_if stuffs | |||
| 256 | */ | |||
| 257 | int | |||
| 258 | umidi_open(void *addr, | |||
| 259 | int flags, | |||
| 260 | void (*iintr)(void *, int), | |||
| 261 | void (*ointr)(void *), | |||
| 262 | void *arg) | |||
| 263 | { | |||
| 264 | struct umidi_mididev *mididev = addr; | |||
| 265 | struct umidi_softc *sc = mididev->sc; | |||
| 266 | ||||
| 267 | DPRINTF(("%s: sc=%p\n", __func__, sc)); | |||
| 268 | ||||
| 269 | if (!sc) | |||
| 270 | return ENXIO6; | |||
| 271 | if (mididev->opened) | |||
| 272 | return EBUSY16; | |||
| 273 | if (usbd_is_dying(sc->sc_udev)) | |||
| 274 | return EIO5; | |||
| 275 | ||||
| 276 | mididev->opened = 1; | |||
| 277 | mididev->flags = flags; | |||
| 278 | if ((mididev->flags & FWRITE0x0002) && mididev->out_jack) | |||
| 279 | open_out_jack(mididev->out_jack, arg, ointr); | |||
| 280 | if ((mididev->flags & FREAD0x0001) && mididev->in_jack) | |||
| 281 | open_in_jack(mididev->in_jack, arg, iintr); | |||
| 282 | return 0; | |||
| 283 | } | |||
| 284 | ||||
| 285 | void | |||
| 286 | umidi_close(void *addr) | |||
| 287 | { | |||
| 288 | int s; | |||
| 289 | struct umidi_mididev *mididev = addr; | |||
| 290 | ||||
| 291 | s = splusb()splraise(0x5); | |||
| 292 | if ((mididev->flags & FWRITE0x0002) && mididev->out_jack) | |||
| 293 | close_jack(mididev->out_jack); | |||
| 294 | if ((mididev->flags & FREAD0x0001) && mididev->in_jack) | |||
| 295 | close_jack(mididev->in_jack); | |||
| 296 | mididev->opened = 0; | |||
| 297 | splx(s)spllower(s); | |||
| 298 | } | |||
| 299 | ||||
| 300 | int | |||
| 301 | umidi_output(void *addr, int d) | |||
| 302 | { | |||
| 303 | struct umidi_mididev *mididev = addr; | |||
| 304 | ||||
| 305 | if (!mididev->out_jack || !mididev->opened) | |||
| 306 | return 1; | |||
| 307 | ||||
| 308 | return out_jack_output(mididev->out_jack, d); | |||
| 309 | } | |||
| 310 | ||||
| 311 | void | |||
| 312 | umidi_flush(void *addr) | |||
| 313 | { | |||
| 314 | struct umidi_mididev *mididev = addr; | |||
| 315 | ||||
| 316 | if (!mididev->out_jack || !mididev->opened) | |||
| 317 | return; | |||
| 318 | ||||
| 319 | out_jack_flush(mididev->out_jack); | |||
| 320 | } | |||
| 321 | ||||
| 322 | void | |||
| 323 | umidi_getinfo(void *addr, struct midi_info *mi) | |||
| 324 | { | |||
| 325 | struct umidi_mididev *mididev = addr; | |||
| 326 | ||||
| 327 | mi->name = "USB MIDI I/F"; /* XXX: model name */ | |||
| 328 | mi->props = MIDI_PROP_OUT_INTR1; | |||
| 329 | if (mididev->in_jack) | |||
| 330 | mi->props |= MIDI_PROP_CAN_INPUT2; | |||
| 331 | } | |||
| 332 | ||||
| 333 | ||||
| 334 | /* | |||
| 335 | * each endpoint stuffs | |||
| 336 | */ | |||
| 337 | ||||
| 338 | /* alloc/free pipe */ | |||
| 339 | static usbd_status | |||
| 340 | alloc_pipe(struct umidi_endpoint *ep) | |||
| 341 | { | |||
| 342 | struct umidi_softc *sc = ep->sc; | |||
| 343 | usbd_status err; | |||
| 344 | ||||
| 345 | DPRINTF(("%s: alloc_pipe %p\n", sc->sc_dev.dv_xname, ep)); | |||
| 346 | SIMPLEQ_INIT(&ep->intrq)do { (&ep->intrq)->sqh_first = ((void *)0); (&ep ->intrq)->sqh_last = &(&ep->intrq)->sqh_first ; } while (0); | |||
| 347 | ep->pending = 0; | |||
| 348 | ep->busy = 0; | |||
| 349 | ep->used = 0; | |||
| 350 | ep->xfer = usbd_alloc_xfer(sc->sc_udev); | |||
| 351 | if (ep->xfer == NULL((void *)0)) | |||
| 352 | return USBD_NOMEM; | |||
| 353 | ep->buffer = usbd_alloc_buffer(ep->xfer, ep->packetsize); | |||
| 354 | if (ep->buffer == NULL((void *)0)) { | |||
| 355 | usbd_free_xfer(ep->xfer); | |||
| 356 | return USBD_NOMEM; | |||
| 357 | } | |||
| 358 | err = usbd_open_pipe(sc->sc_iface, ep->addr, 0, &ep->pipe); | |||
| 359 | if (err != USBD_NORMAL_COMPLETION) { | |||
| 360 | usbd_free_xfer(ep->xfer); | |||
| 361 | return err; | |||
| 362 | } | |||
| 363 | return USBD_NORMAL_COMPLETION; | |||
| 364 | } | |||
| 365 | ||||
| 366 | static void | |||
| 367 | free_pipe(struct umidi_endpoint *ep) | |||
| 368 | { | |||
| 369 | DPRINTF(("%s: %s %p\n", ep->sc->sc_dev.dv_xname, __func__, ep)); | |||
| 370 | usbd_close_pipe(ep->pipe); | |||
| 371 | usbd_free_xfer(ep->xfer); | |||
| 372 | } | |||
| 373 | ||||
| 374 | ||||
| 375 | /* alloc/free the array of endpoint structures */ | |||
| 376 | ||||
| 377 | static usbd_status alloc_all_endpoints_fixed_ep(struct umidi_softc *); | |||
| 378 | static usbd_status alloc_all_endpoints_yamaha(struct umidi_softc *); | |||
| 379 | static usbd_status alloc_all_endpoints_genuine(struct umidi_softc *); | |||
| 380 | ||||
| 381 | static usbd_status | |||
| 382 | alloc_all_endpoints(struct umidi_softc *sc) | |||
| 383 | { | |||
| 384 | usbd_status err; | |||
| 385 | struct umidi_endpoint *ep; | |||
| 386 | int i; | |||
| 387 | ||||
| 388 | sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0; | |||
| 389 | ||||
| 390 | if (UMQ_ISTYPE(sc, UMQ_TYPE_FIXED_EP)((sc)->sc_quirk && ((sc)->sc_quirk->type_mask & (1<<((1)-1))))) | |||
| 391 | err = alloc_all_endpoints_fixed_ep(sc); | |||
| 392 | else if (UMQ_ISTYPE(sc, UMQ_TYPE_YAMAHA)((sc)->sc_quirk && ((sc)->sc_quirk->type_mask & (1<<((2)-1))))) | |||
| 393 | err = alloc_all_endpoints_yamaha(sc); | |||
| 394 | else | |||
| 395 | err = alloc_all_endpoints_genuine(sc); | |||
| 396 | if (err!=USBD_NORMAL_COMPLETION) | |||
| 397 | return err; | |||
| 398 | ||||
| 399 | ep = sc->sc_endpoints; | |||
| 400 | for (i=sc->sc_out_num_endpoints+sc->sc_in_num_endpoints; i>0; i--) { | |||
| 401 | err = alloc_pipe(ep); | |||
| 402 | if (err!=USBD_NORMAL_COMPLETION) { | |||
| 403 | while(ep != sc->sc_endpoints) { | |||
| 404 | ep--; | |||
| 405 | free_pipe(ep); | |||
| 406 | } | |||
| 407 | free(sc->sc_endpoints, M_USBDEV102, | |||
| 408 | (sc->sc_out_num_endpoints + sc->sc_in_num_endpoints) | |||
| 409 | * sizeof(*sc->sc_endpoints)); | |||
| 410 | sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL((void *)0); | |||
| 411 | break; | |||
| 412 | } | |||
| 413 | ep++; | |||
| 414 | } | |||
| 415 | return err; | |||
| 416 | } | |||
| 417 | ||||
| 418 | static void | |||
| 419 | free_all_endpoints(struct umidi_softc *sc) | |||
| 420 | { | |||
| 421 | int i; | |||
| 422 | ||||
| 423 | for (i=0; i<sc->sc_in_num_endpoints+sc->sc_out_num_endpoints; i++) | |||
| 424 | free_pipe(&sc->sc_endpoints[i]); | |||
| 425 | free(sc->sc_endpoints, M_USBDEV102, (sc->sc_out_num_endpoints + | |||
| 426 | sc->sc_in_num_endpoints) * sizeof(*sc->sc_endpoints)); | |||
| 427 | sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL((void *)0); | |||
| 428 | } | |||
| 429 | ||||
| 430 | static usbd_status | |||
| 431 | alloc_all_endpoints_fixed_ep(struct umidi_softc *sc) | |||
| 432 | { | |||
| 433 | struct umq_fixed_ep_desc *fp; | |||
| 434 | struct umidi_endpoint *ep; | |||
| 435 | usb_endpoint_descriptor_t *epd; | |||
| 436 | int i; | |||
| 437 | ||||
| 438 | fp = umidi_get_quirk_data_from_type(sc->sc_quirk, | |||
| 439 | UMQ_TYPE_FIXED_EP1); | |||
| 440 | sc->sc_out_num_endpoints = fp->num_out_ep; | |||
| 441 | sc->sc_in_num_endpoints = fp->num_in_ep; | |||
| 442 | sc->sc_endpoints = mallocarray(sc->sc_out_num_endpoints + | |||
| 443 | sc->sc_in_num_endpoints, sizeof(*sc->sc_endpoints), M_USBDEV102, | |||
| 444 | M_WAITOK0x0001 | M_CANFAIL0x0004); | |||
| 445 | if (!sc->sc_endpoints) | |||
| 446 | return USBD_NOMEM; | |||
| 447 | sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL((void *)0); | |||
| 448 | sc->sc_in_ep = | |||
| 449 | sc->sc_in_num_endpoints ? | |||
| 450 | sc->sc_endpoints+sc->sc_out_num_endpoints : NULL((void *)0); | |||
| 451 | ||||
| 452 | if (sc->sc_in_ep == NULL((void *)0) || sc->sc_out_ep == NULL((void *)0)) { | |||
| 453 | printf("%s: cannot get valid endpoints", sc->sc_dev.dv_xname); | |||
| 454 | goto error; | |||
| 455 | } | |||
| 456 | ep = &sc->sc_out_ep[0]; | |||
| 457 | for (i=0; i<sc->sc_out_num_endpoints; i++) { | |||
| 458 | epd = usbd_interface2endpoint_descriptor( | |||
| 459 | sc->sc_iface, | |||
| 460 | fp->out_ep[i].ep); | |||
| 461 | if (!epd) { | |||
| 462 | DPRINTF(("%s: cannot get endpoint descriptor(out:%d)\n", | |||
| 463 | sc->sc_dev.dv_xname, fp->out_ep[i].ep)); | |||
| 464 | goto error; | |||
| 465 | } | |||
| 466 | if (UE_GET_XFERTYPE(epd->bmAttributes)((epd->bmAttributes) & 0x03)!=UE_BULK0x02 || | |||
| 467 | UE_GET_DIR(epd->bEndpointAddress)((epd->bEndpointAddress) & 0x80)!=UE_DIR_OUT0x00) { | |||
| 468 | printf("%s: illegal endpoint(out:%d)\n", | |||
| 469 | sc->sc_dev.dv_xname, fp->out_ep[i].ep); | |||
| 470 | goto error; | |||
| 471 | } | |||
| 472 | ep->sc = sc; | |||
| 473 | ep->packetsize = UGETW(epd->wMaxPacketSize)(*(u_int16_t *)(epd->wMaxPacketSize)); | |||
| 474 | ep->addr = epd->bEndpointAddress; | |||
| 475 | ep->num_jacks = fp->out_ep[i].num_jacks; | |||
| 476 | sc->sc_out_num_jacks += fp->out_ep[i].num_jacks; | |||
| 477 | ep->num_open = 0; | |||
| 478 | memset(ep->jacks, 0, sizeof(ep->jacks))__builtin_memset((ep->jacks), (0), (sizeof(ep->jacks))); | |||
| 479 | ep++; | |||
| 480 | } | |||
| 481 | ep = &sc->sc_in_ep[0]; | |||
| 482 | for (i=0; i<sc->sc_in_num_endpoints; i++) { | |||
| 483 | epd = usbd_interface2endpoint_descriptor( | |||
| 484 | sc->sc_iface, | |||
| 485 | fp->in_ep[i].ep); | |||
| 486 | if (!epd) { | |||
| 487 | DPRINTF(("%s: cannot get endpoint descriptor(in:%d)\n", | |||
| 488 | sc->sc_dev.dv_xname, fp->in_ep[i].ep)); | |||
| 489 | goto error; | |||
| 490 | } | |||
| 491 | if (UE_GET_XFERTYPE(epd->bmAttributes)((epd->bmAttributes) & 0x03)!=UE_BULK0x02 || | |||
| 492 | UE_GET_DIR(epd->bEndpointAddress)((epd->bEndpointAddress) & 0x80)!=UE_DIR_IN0x80) { | |||
| 493 | printf("%s: illegal endpoint(in:%d)\n", | |||
| 494 | sc->sc_dev.dv_xname, fp->in_ep[i].ep); | |||
| 495 | goto error; | |||
| 496 | } | |||
| 497 | ep->sc = sc; | |||
| 498 | ep->addr = epd->bEndpointAddress; | |||
| 499 | ep->packetsize = UGETW(epd->wMaxPacketSize)(*(u_int16_t *)(epd->wMaxPacketSize)); | |||
| 500 | ep->num_jacks = fp->in_ep[i].num_jacks; | |||
| 501 | sc->sc_in_num_jacks += fp->in_ep[i].num_jacks; | |||
| 502 | ep->num_open = 0; | |||
| 503 | memset(ep->jacks, 0, sizeof(ep->jacks))__builtin_memset((ep->jacks), (0), (sizeof(ep->jacks))); | |||
| 504 | ep++; | |||
| 505 | } | |||
| 506 | ||||
| 507 | return USBD_NORMAL_COMPLETION; | |||
| 508 | error: | |||
| 509 | free(sc->sc_endpoints, M_USBDEV102, (sc->sc_out_num_endpoints + | |||
| 510 | sc->sc_in_num_endpoints) * sizeof(*sc->sc_endpoints)); | |||
| 511 | sc->sc_endpoints = NULL((void *)0); | |||
| 512 | return USBD_INVAL; | |||
| 513 | } | |||
| 514 | ||||
| 515 | static usbd_status | |||
| 516 | alloc_all_endpoints_yamaha(struct umidi_softc *sc) | |||
| 517 | { | |||
| 518 | /* This driver currently supports max 1in/1out bulk endpoints */ | |||
| 519 | usb_descriptor_t *desc; | |||
| 520 | usb_endpoint_descriptor_t *epd; | |||
| 521 | int out_addr, in_addr, in_packetsize, i, dir; | |||
| 522 | size_t remain, descsize; | |||
| 523 | ||||
| 524 | out_addr = in_addr = 0; | |||
| 525 | ||||
| 526 | /* detect endpoints */ | |||
| 527 | desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface))((usb_descriptor_t *)(usbd_get_interface_descriptor(sc->sc_iface ))); | |||
| 528 | for (i=(int)TO_IFD(desc)((usb_interface_descriptor_t *)(desc))->bNumEndpoints-1; i>=0; i--) { | |||
| 529 | epd = usbd_interface2endpoint_descriptor(sc->sc_iface, i); | |||
| 530 | if (epd == NULL((void *)0)) | |||
| 531 | continue; | |||
| 532 | ||||
| 533 | if (UE_GET_XFERTYPE(epd->bmAttributes)((epd->bmAttributes) & 0x03) == UE_BULK0x02) { | |||
| 534 | dir = UE_GET_DIR(epd->bEndpointAddress)((epd->bEndpointAddress) & 0x80); | |||
| 535 | if (dir==UE_DIR_OUT0x00 && !out_addr) | |||
| 536 | out_addr = epd->bEndpointAddress; | |||
| 537 | else if (dir==UE_DIR_IN0x80 && !in_addr) { | |||
| 538 | in_addr = epd->bEndpointAddress; | |||
| 539 | in_packetsize = UGETW(epd->wMaxPacketSize)(*(u_int16_t *)(epd->wMaxPacketSize)); | |||
| 540 | } | |||
| 541 | } | |||
| 542 | } | |||
| 543 | desc = NEXT_D(desc)((usb_descriptor_t *)((caddr_t)(desc)+(desc)->bLength)); | |||
| 544 | ||||
| 545 | /* count jacks */ | |||
| 546 | if (!(desc->bDescriptorType==UDESC_CS_INTERFACE0x24 && | |||
| 547 | desc->bDescriptorSubtype==UMIDI_MS_HEADER0x01)) | |||
| 548 | return USBD_INVAL; | |||
| 549 | remain = (size_t)UGETW(TO_CSIFD(desc)->wTotalLength)(*(u_int16_t *)(((struct umidi_cs_interface_descriptor *)(desc ))->wTotalLength)) - | |||
| 550 | (size_t)desc->bLength; | |||
| 551 | desc = NEXT_D(desc)((usb_descriptor_t *)((caddr_t)(desc)+(desc)->bLength)); | |||
| 552 | ||||
| 553 | while (remain>=sizeof(usb_descriptor_t)) { | |||
| 554 | descsize = desc->bLength; | |||
| 555 | if (descsize>remain || descsize==0) | |||
| 556 | break; | |||
| 557 | if (desc->bDescriptorType==UDESC_CS_INTERFACE0x24 && | |||
| 558 | remain>=UMIDI_JACK_DESCRIPTOR_SIZE5) { | |||
| 559 | if (desc->bDescriptorSubtype==UMIDI_OUT_JACK0x03) | |||
| 560 | sc->sc_out_num_jacks++; | |||
| 561 | else if (desc->bDescriptorSubtype==UMIDI_IN_JACK0x02) | |||
| 562 | sc->sc_in_num_jacks++; | |||
| 563 | } | |||
| 564 | desc = NEXT_D(desc)((usb_descriptor_t *)((caddr_t)(desc)+(desc)->bLength)); | |||
| 565 | remain-=descsize; | |||
| 566 | } | |||
| 567 | ||||
| 568 | /* validate some parameters */ | |||
| 569 | if (sc->sc_out_num_jacks>UMIDI_MAX_EPJACKS16) | |||
| 570 | sc->sc_out_num_jacks = UMIDI_MAX_EPJACKS16; | |||
| 571 | if (sc->sc_in_num_jacks>UMIDI_MAX_EPJACKS16) | |||
| 572 | sc->sc_in_num_jacks = UMIDI_MAX_EPJACKS16; | |||
| 573 | if (sc->sc_out_num_jacks && out_addr) | |||
| 574 | sc->sc_out_num_endpoints = 1; | |||
| 575 | else { | |||
| 576 | sc->sc_out_num_endpoints = 0; | |||
| 577 | sc->sc_out_num_jacks = 0; | |||
| 578 | } | |||
| 579 | if (sc->sc_in_num_jacks && in_addr) | |||
| 580 | sc->sc_in_num_endpoints = 1; | |||
| 581 | else { | |||
| 582 | sc->sc_in_num_endpoints = 0; | |||
| 583 | sc->sc_in_num_jacks = 0; | |||
| 584 | } | |||
| 585 | sc->sc_endpoints = mallocarray(sc->sc_out_num_endpoints + | |||
| 586 | sc->sc_in_num_endpoints, sizeof(struct umidi_endpoint), | |||
| 587 | M_USBDEV102, M_WAITOK0x0001 | M_CANFAIL0x0004); | |||
| 588 | if (!sc->sc_endpoints) | |||
| 589 | return USBD_NOMEM; | |||
| 590 | if (sc->sc_out_num_endpoints) { | |||
| 591 | sc->sc_out_ep = sc->sc_endpoints; | |||
| 592 | sc->sc_out_ep->sc = sc; | |||
| 593 | sc->sc_out_ep->addr = out_addr; | |||
| 594 | sc->sc_out_ep->packetsize = UGETW(epd->wMaxPacketSize)(*(u_int16_t *)(epd->wMaxPacketSize)); | |||
| 595 | sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks; | |||
| 596 | sc->sc_out_ep->num_open = 0; | |||
| 597 | memset(sc->sc_out_ep->jacks, 0, sizeof(sc->sc_out_ep->jacks))__builtin_memset((sc->sc_out_ep->jacks), (0), (sizeof(sc ->sc_out_ep->jacks))); | |||
| 598 | } else | |||
| 599 | sc->sc_out_ep = NULL((void *)0); | |||
| 600 | ||||
| 601 | if (sc->sc_in_num_endpoints) { | |||
| 602 | sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints; | |||
| 603 | sc->sc_in_ep->sc = sc; | |||
| 604 | sc->sc_in_ep->addr = in_addr; | |||
| 605 | sc->sc_in_ep->packetsize = in_packetsize; | |||
| 606 | sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks; | |||
| 607 | sc->sc_in_ep->num_open = 0; | |||
| 608 | memset(sc->sc_in_ep->jacks, 0, sizeof(sc->sc_in_ep->jacks))__builtin_memset((sc->sc_in_ep->jacks), (0), (sizeof(sc ->sc_in_ep->jacks))); | |||
| 609 | } else | |||
| 610 | sc->sc_in_ep = NULL((void *)0); | |||
| 611 | ||||
| 612 | return USBD_NORMAL_COMPLETION; | |||
| 613 | } | |||
| 614 | ||||
| 615 | static usbd_status | |||
| 616 | alloc_all_endpoints_genuine(struct umidi_softc *sc) | |||
| 617 | { | |||
| 618 | usb_interface_descriptor_t *interface_desc; | |||
| 619 | usb_config_descriptor_t *config_desc; | |||
| 620 | usb_descriptor_t *desc; | |||
| 621 | size_t remain, descsize; | |||
| 622 | struct umidi_endpoint *p, *q, *lowest, *endep, tmpep; | |||
| 623 | int epaddr, eppacketsize, num_ep; | |||
| 624 | ||||
| 625 | interface_desc = usbd_get_interface_descriptor(sc->sc_iface); | |||
| 626 | num_ep = interface_desc->bNumEndpoints; | |||
| 627 | sc->sc_endpoints = p = mallocarray(num_ep, | |||
| 628 | sizeof(struct umidi_endpoint), M_USBDEV102, M_WAITOK0x0001 | M_CANFAIL0x0004); | |||
| 629 | if (!p) | |||
| 630 | return USBD_NOMEM; | |||
| 631 | ||||
| 632 | sc->sc_out_num_endpoints = sc->sc_in_num_endpoints = 0; | |||
| 633 | epaddr = -1; | |||
| 634 | ||||
| 635 | /* get the list of endpoints for midi stream */ | |||
| 636 | config_desc = usbd_get_config_descriptor(sc->sc_udev); | |||
| 637 | desc = (usb_descriptor_t *) config_desc; | |||
| 638 | remain = (size_t)UGETW(config_desc->wTotalLength)(*(u_int16_t *)(config_desc->wTotalLength)); | |||
| 639 | while (remain>=sizeof(usb_descriptor_t)) { | |||
| 640 | descsize = desc->bLength; | |||
| 641 | if (descsize>remain || descsize==0) | |||
| 642 | break; | |||
| 643 | if (desc->bDescriptorType==UDESC_ENDPOINT0x05 && | |||
| 644 | remain>=USB_ENDPOINT_DESCRIPTOR_SIZE7 && | |||
| 645 | UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes)((((usb_endpoint_descriptor_t *)(desc))->bmAttributes) & 0x03) == UE_BULK0x02) { | |||
| 646 | epaddr = TO_EPD(desc)((usb_endpoint_descriptor_t *)(desc))->bEndpointAddress; | |||
| 647 | eppacketsize = UGETW(TO_EPD(desc)->wMaxPacketSize)(*(u_int16_t *)(((usb_endpoint_descriptor_t *)(desc))->wMaxPacketSize )); | |||
| 648 | } else if (desc->bDescriptorType==UDESC_CS_ENDPOINT0x25 && | |||
| 649 | remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE4 && | |||
| 650 | epaddr!=-1) { | |||
| 651 | if (num_ep>0) { | |||
| 652 | num_ep--; | |||
| 653 | p->sc = sc; | |||
| 654 | p->addr = epaddr; | |||
| 655 | p->packetsize = eppacketsize; | |||
| 656 | p->num_jacks = TO_CSEPD(desc)((struct umidi_cs_endpoint_descriptor *)(desc))->bNumEmbMIDIJack; | |||
| 657 | if (UE_GET_DIR(epaddr)((epaddr) & 0x80)==UE_DIR_OUT0x00) { | |||
| 658 | sc->sc_out_num_endpoints++; | |||
| 659 | sc->sc_out_num_jacks += p->num_jacks; | |||
| 660 | } else { | |||
| 661 | sc->sc_in_num_endpoints++; | |||
| 662 | sc->sc_in_num_jacks += p->num_jacks; | |||
| 663 | } | |||
| 664 | p++; | |||
| 665 | } | |||
| 666 | } else | |||
| 667 | epaddr = -1; | |||
| 668 | desc = NEXT_D(desc)((usb_descriptor_t *)((caddr_t)(desc)+(desc)->bLength)); | |||
| 669 | remain-=descsize; | |||
| 670 | } | |||
| 671 | ||||
| 672 | /* sort endpoints */ | |||
| 673 | num_ep = sc->sc_out_num_endpoints + sc->sc_in_num_endpoints; | |||
| 674 | p = sc->sc_endpoints; | |||
| 675 | endep = p + num_ep; | |||
| 676 | while (p<endep) { | |||
| 677 | lowest = p; | |||
| 678 | for (q=p+1; q<endep; q++) { | |||
| 679 | if ((UE_GET_DIR(lowest->addr)((lowest->addr) & 0x80)==UE_DIR_IN0x80 && | |||
| 680 | UE_GET_DIR(q->addr)((q->addr) & 0x80)==UE_DIR_OUT0x00) || | |||
| 681 | ((UE_GET_DIR(lowest->addr)((lowest->addr) & 0x80)== | |||
| 682 | UE_GET_DIR(q->addr)((q->addr) & 0x80)) && | |||
| 683 | (UE_GET_ADDR(lowest->addr)((lowest->addr) & 0x0f)> | |||
| 684 | UE_GET_ADDR(q->addr)((q->addr) & 0x0f)))) | |||
| 685 | lowest = q; | |||
| 686 | } | |||
| 687 | if (lowest != p) { | |||
| 688 | memcpy((void *)&tmpep, (void *)p, sizeof(tmpep))__builtin_memcpy(((void *)&tmpep), ((void *)p), (sizeof(tmpep ))); | |||
| 689 | memcpy((void *)p, (void *)lowest, sizeof(tmpep))__builtin_memcpy(((void *)p), ((void *)lowest), (sizeof(tmpep ))); | |||
| 690 | memcpy((void *)lowest, (void *)&tmpep, sizeof(tmpep))__builtin_memcpy(((void *)lowest), ((void *)&tmpep), (sizeof (tmpep))); | |||
| 691 | } | |||
| 692 | p->num_open = 0; | |||
| 693 | p++; | |||
| 694 | } | |||
| 695 | ||||
| 696 | sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL((void *)0); | |||
| 697 | sc->sc_in_ep = | |||
| 698 | sc->sc_in_num_endpoints ? | |||
| 699 | sc->sc_endpoints+sc->sc_out_num_endpoints : NULL((void *)0); | |||
| 700 | ||||
| 701 | return USBD_NORMAL_COMPLETION; | |||
| 702 | } | |||
| 703 | ||||
| 704 | ||||
| 705 | /* | |||
| 706 | * jack stuffs | |||
| 707 | */ | |||
| 708 | ||||
| 709 | static usbd_status | |||
| 710 | alloc_all_jacks(struct umidi_softc *sc) | |||
| 711 | { | |||
| 712 | int i, j; | |||
| 713 | struct umidi_endpoint *ep; | |||
| 714 | struct umidi_jack *jack, **rjack; | |||
| 715 | ||||
| 716 | /* allocate/initialize structures */ | |||
| 717 | sc->sc_jacks = mallocarray(sc->sc_in_num_jacks + sc->sc_out_num_jacks, | |||
| 718 | sizeof(*sc->sc_out_jacks), M_USBDEV102, M_WAITOK0x0001 | M_CANFAIL0x0004); | |||
| 719 | if (!sc->sc_jacks) | |||
| 720 | return USBD_NOMEM; | |||
| 721 | sc->sc_out_jacks = | |||
| 722 | sc->sc_out_num_jacks ? sc->sc_jacks : NULL((void *)0); | |||
| 723 | sc->sc_in_jacks = | |||
| 724 | sc->sc_in_num_jacks ? sc->sc_jacks+sc->sc_out_num_jacks : NULL((void *)0); | |||
| 725 | ||||
| 726 | jack = &sc->sc_out_jacks[0]; | |||
| 727 | for (i=0; i<sc->sc_out_num_jacks; i++) { | |||
| 728 | jack->opened = 0; | |||
| 729 | jack->binded = 0; | |||
| 730 | jack->arg = NULL((void *)0); | |||
| 731 | jack->u.out.intr = NULL((void *)0); | |||
| 732 | jack->intr = 0; | |||
| 733 | jack->cable_number = i; | |||
| 734 | jack++; | |||
| 735 | } | |||
| 736 | jack = &sc->sc_in_jacks[0]; | |||
| 737 | for (i=0; i<sc->sc_in_num_jacks; i++) { | |||
| 738 | jack->opened = 0; | |||
| 739 | jack->binded = 0; | |||
| 740 | jack->arg = NULL((void *)0); | |||
| 741 | jack->u.in.intr = NULL((void *)0); | |||
| 742 | jack->cable_number = i; | |||
| 743 | jack++; | |||
| 744 | } | |||
| 745 | ||||
| 746 | /* assign each jacks to each endpoints */ | |||
| 747 | jack = &sc->sc_out_jacks[0]; | |||
| 748 | ep = &sc->sc_out_ep[0]; | |||
| 749 | for (i=0; i<sc->sc_out_num_endpoints; i++) { | |||
| 750 | rjack = &ep->jacks[0]; | |||
| 751 | for (j=0; j<ep->num_jacks; j++) { | |||
| 752 | *rjack = jack; | |||
| 753 | jack->endpoint = ep; | |||
| ||||
| 754 | jack++; | |||
| 755 | rjack++; | |||
| 756 | } | |||
| 757 | ep++; | |||
| 758 | } | |||
| 759 | jack = &sc->sc_in_jacks[0]; | |||
| 760 | ep = &sc->sc_in_ep[0]; | |||
| 761 | for (i=0; i<sc->sc_in_num_endpoints; i++) { | |||
| 762 | rjack = &ep->jacks[0]; | |||
| 763 | for (j=0; j<ep->num_jacks; j++) { | |||
| 764 | *rjack = jack; | |||
| 765 | jack->endpoint = ep; | |||
| 766 | jack++; | |||
| 767 | rjack++; | |||
| 768 | } | |||
| 769 | ep++; | |||
| 770 | } | |||
| 771 | ||||
| 772 | return USBD_NORMAL_COMPLETION; | |||
| 773 | } | |||
| 774 | ||||
| 775 | static void | |||
| 776 | free_all_jacks(struct umidi_softc *sc) | |||
| 777 | { | |||
| 778 | int s, jacks = sc->sc_in_num_jacks + sc->sc_out_num_jacks; | |||
| 779 | ||||
| 780 | s = splusb()splraise(0x5); | |||
| 781 | if (sc->sc_out_jacks) { | |||
| 782 | free(sc->sc_jacks, M_USBDEV102, jacks * sizeof(*sc->sc_out_jacks)); | |||
| 783 | sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL((void *)0); | |||
| 784 | sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0; | |||
| 785 | } | |||
| 786 | splx(s)spllower(s); | |||
| 787 | } | |||
| 788 | ||||
| 789 | static usbd_status | |||
| 790 | bind_jacks_to_mididev(struct umidi_softc *sc, | |||
| 791 | struct umidi_jack *out_jack, | |||
| 792 | struct umidi_jack *in_jack, | |||
| 793 | struct umidi_mididev *mididev) | |||
| 794 | { | |||
| 795 | if ((out_jack && out_jack->binded) || (in_jack && in_jack->binded)) | |||
| 796 | return USBD_IN_USE; | |||
| 797 | if (mididev->out_jack || mididev->in_jack) | |||
| 798 | return USBD_IN_USE; | |||
| 799 | ||||
| 800 | if (out_jack) | |||
| 801 | out_jack->binded = 1; | |||
| 802 | if (in_jack) | |||
| 803 | in_jack->binded = 1; | |||
| 804 | mididev->in_jack = in_jack; | |||
| 805 | mididev->out_jack = out_jack; | |||
| 806 | ||||
| 807 | return USBD_NORMAL_COMPLETION; | |||
| 808 | } | |||
| 809 | ||||
| 810 | static void | |||
| 811 | unbind_jacks_from_mididev(struct umidi_mididev *mididev) | |||
| 812 | { | |||
| 813 | if ((mididev->flags & FWRITE0x0002) && mididev->out_jack) | |||
| 814 | close_jack(mididev->out_jack); | |||
| 815 | if ((mididev->flags & FREAD0x0001) && mididev->in_jack) | |||
| 816 | close_jack(mididev->in_jack); | |||
| 817 | ||||
| 818 | if (mididev->out_jack) | |||
| 819 | mididev->out_jack->binded = 0; | |||
| 820 | if (mididev->in_jack) | |||
| 821 | mididev->in_jack->binded = 0; | |||
| 822 | mididev->out_jack = mididev->in_jack = NULL((void *)0); | |||
| 823 | } | |||
| 824 | ||||
| 825 | static void | |||
| 826 | unbind_all_jacks(struct umidi_softc *sc) | |||
| 827 | { | |||
| 828 | int i; | |||
| 829 | ||||
| 830 | if (sc->sc_mididevs) | |||
| 831 | for (i=0; i<sc->sc_num_mididevs; i++) { | |||
| 832 | unbind_jacks_from_mididev(&sc->sc_mididevs[i]); | |||
| 833 | } | |||
| 834 | } | |||
| 835 | ||||
| 836 | static usbd_status | |||
| 837 | assign_all_jacks_automatically(struct umidi_softc *sc) | |||
| 838 | { | |||
| 839 | usbd_status err; | |||
| 840 | int i; | |||
| 841 | struct umidi_jack *out, *in; | |||
| 842 | ||||
| 843 | err = | |||
| 844 | alloc_all_mididevs(sc, | |||
| 845 | max(sc->sc_out_num_jacks, sc->sc_in_num_jacks)); | |||
| 846 | if (err!=USBD_NORMAL_COMPLETION) | |||
| 847 | return err; | |||
| 848 | ||||
| 849 | for (i=0; i<sc->sc_num_mididevs; i++) { | |||
| 850 | out = (i<sc->sc_out_num_jacks) ? &sc->sc_out_jacks[i]:NULL((void *)0); | |||
| 851 | in = (i<sc->sc_in_num_jacks) ? &sc->sc_in_jacks[i]:NULL((void *)0); | |||
| 852 | err = bind_jacks_to_mididev(sc, out, in, &sc->sc_mididevs[i]); | |||
| 853 | if (err!=USBD_NORMAL_COMPLETION) { | |||
| 854 | free_all_mididevs(sc); | |||
| 855 | return err; | |||
| 856 | } | |||
| 857 | } | |||
| 858 | ||||
| 859 | return USBD_NORMAL_COMPLETION; | |||
| 860 | } | |||
| 861 | ||||
| 862 | static usbd_status | |||
| 863 | open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *)) | |||
| 864 | { | |||
| 865 | if (jack->opened) | |||
| 866 | return USBD_IN_USE; | |||
| 867 | ||||
| 868 | jack->arg = arg; | |||
| 869 | jack->u.out.intr = intr; | |||
| 870 | init_packet(&jack->packet); | |||
| 871 | jack->opened = 1; | |||
| 872 | jack->endpoint->num_open++; | |||
| 873 | ||||
| 874 | return USBD_NORMAL_COMPLETION; | |||
| 875 | } | |||
| 876 | ||||
| 877 | static usbd_status | |||
| 878 | open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int)) | |||
| 879 | { | |||
| 880 | if (jack->opened) | |||
| 881 | return USBD_IN_USE; | |||
| 882 | ||||
| 883 | jack->arg = arg; | |||
| 884 | jack->u.in.intr = intr; | |||
| 885 | jack->opened = 1; | |||
| 886 | jack->endpoint->num_open++; | |||
| 887 | ||||
| 888 | return USBD_NORMAL_COMPLETION; | |||
| 889 | } | |||
| 890 | ||||
| 891 | static void | |||
| 892 | close_jack(struct umidi_jack *jack) | |||
| 893 | { | |||
| 894 | if (jack->opened) { | |||
| 895 | jack->opened = 0; | |||
| 896 | jack->endpoint->num_open--; | |||
| 897 | } | |||
| 898 | } | |||
| 899 | ||||
| 900 | static usbd_status | |||
| 901 | attach_mididev(struct umidi_softc *sc, struct umidi_mididev *mididev) | |||
| 902 | { | |||
| 903 | if (mididev->sc) | |||
| 904 | return USBD_IN_USE; | |||
| 905 | ||||
| 906 | mididev->sc = sc; | |||
| 907 | ||||
| 908 | mididev->mdev = midi_attach_mi(&umidi_hw_if, mididev, &sc->sc_dev); | |||
| 909 | ||||
| 910 | return USBD_NORMAL_COMPLETION; | |||
| 911 | } | |||
| 912 | ||||
| 913 | static usbd_status | |||
| 914 | detach_mididev(struct umidi_mididev *mididev, int flags) | |||
| 915 | { | |||
| 916 | if (!mididev->sc) | |||
| 917 | return USBD_NO_ADDR; | |||
| 918 | ||||
| 919 | if (mididev->opened) | |||
| 920 | umidi_close(mididev); | |||
| 921 | unbind_jacks_from_mididev(mididev); | |||
| 922 | ||||
| 923 | if (mididev->mdev) | |||
| 924 | config_detach(mididev->mdev, flags); | |||
| 925 | ||||
| 926 | mididev->sc = NULL((void *)0); | |||
| 927 | ||||
| 928 | return USBD_NORMAL_COMPLETION; | |||
| 929 | } | |||
| 930 | ||||
| 931 | static usbd_status | |||
| 932 | deactivate_mididev(struct umidi_mididev *mididev) | |||
| 933 | { | |||
| 934 | if (mididev->out_jack) | |||
| 935 | mididev->out_jack->binded = 0; | |||
| 936 | if (mididev->in_jack) | |||
| 937 | mididev->in_jack->binded = 0; | |||
| 938 | config_deactivate(mididev->mdev); | |||
| 939 | ||||
| 940 | return USBD_NORMAL_COMPLETION; | |||
| 941 | } | |||
| 942 | ||||
| 943 | static usbd_status | |||
| 944 | alloc_all_mididevs(struct umidi_softc *sc, int nmidi) | |||
| 945 | { | |||
| 946 | sc->sc_num_mididevs = nmidi; | |||
| 947 | sc->sc_mididevs = mallocarray(nmidi, sizeof(*sc->sc_mididevs), | |||
| 948 | M_USBDEV102, M_WAITOK0x0001 | M_CANFAIL0x0004 | M_ZERO0x0008); | |||
| 949 | if (!sc->sc_mididevs) | |||
| 950 | return USBD_NOMEM; | |||
| 951 | ||||
| 952 | return USBD_NORMAL_COMPLETION; | |||
| 953 | } | |||
| 954 | ||||
| 955 | static void | |||
| 956 | free_all_mididevs(struct umidi_softc *sc) | |||
| 957 | { | |||
| 958 | if (sc->sc_mididevs) | |||
| 959 | free(sc->sc_mididevs, M_USBDEV102, | |||
| 960 | sc->sc_num_mididevs * sizeof(*sc->sc_mididevs)); | |||
| 961 | sc->sc_mididevs = NULL((void *)0); | |||
| 962 | sc->sc_num_mididevs = 0; | |||
| 963 | } | |||
| 964 | ||||
| 965 | static usbd_status | |||
| 966 | attach_all_mididevs(struct umidi_softc *sc) | |||
| 967 | { | |||
| 968 | usbd_status err; | |||
| 969 | int i; | |||
| 970 | ||||
| 971 | if (sc->sc_mididevs) | |||
| 972 | for (i=0; i<sc->sc_num_mididevs; i++) { | |||
| 973 | err = attach_mididev(sc, &sc->sc_mididevs[i]); | |||
| 974 | if (err!=USBD_NORMAL_COMPLETION) | |||
| 975 | return err; | |||
| 976 | } | |||
| 977 | ||||
| 978 | return USBD_NORMAL_COMPLETION; | |||
| 979 | } | |||
| 980 | ||||
| 981 | static usbd_status | |||
| 982 | detach_all_mididevs(struct umidi_softc *sc, int flags) | |||
| 983 | { | |||
| 984 | usbd_status err; | |||
| 985 | int i; | |||
| 986 | ||||
| 987 | if (sc->sc_mididevs) | |||
| 988 | for (i=0; i<sc->sc_num_mididevs; i++) { | |||
| 989 | err = detach_mididev(&sc->sc_mididevs[i], flags); | |||
| 990 | if (err!=USBD_NORMAL_COMPLETION) | |||
| 991 | return err; | |||
| 992 | } | |||
| 993 | ||||
| 994 | return USBD_NORMAL_COMPLETION; | |||
| 995 | } | |||
| 996 | ||||
| 997 | static usbd_status | |||
| 998 | deactivate_all_mididevs(struct umidi_softc *sc) | |||
| 999 | { | |||
| 1000 | usbd_status err; | |||
| 1001 | int i; | |||
| 1002 | ||||
| 1003 | if (sc->sc_mididevs) | |||
| 1004 | for (i=0; i<sc->sc_num_mididevs; i++) { | |||
| 1005 | err = deactivate_mididev(&sc->sc_mididevs[i]); | |||
| 1006 | if (err!=USBD_NORMAL_COMPLETION) | |||
| 1007 | return err; | |||
| 1008 | } | |||
| 1009 | ||||
| 1010 | return USBD_NORMAL_COMPLETION; | |||
| 1011 | } | |||
| 1012 | ||||
| 1013 | #ifdef UMIDI_DEBUG | |||
| 1014 | static void | |||
| 1015 | dump_sc(struct umidi_softc *sc) | |||
| 1016 | { | |||
| 1017 | int i; | |||
| 1018 | ||||
| 1019 | DPRINTFN(10, ("%s: %s\n", sc->sc_dev.dv_xname, __func__)); | |||
| 1020 | for (i=0; i<sc->sc_out_num_endpoints; i++) { | |||
| 1021 | DPRINTFN(10, ("\tout_ep(%p):\n", &sc->sc_out_ep[i])); | |||
| 1022 | dump_ep(&sc->sc_out_ep[i]); | |||
| 1023 | } | |||
| 1024 | for (i=0; i<sc->sc_in_num_endpoints; i++) { | |||
| 1025 | DPRINTFN(10, ("\tin_ep(%p):\n", &sc->sc_in_ep[i])); | |||
| 1026 | dump_ep(&sc->sc_in_ep[i]); | |||
| 1027 | } | |||
| 1028 | } | |||
| 1029 | ||||
| 1030 | static void | |||
| 1031 | dump_ep(struct umidi_endpoint *ep) | |||
| 1032 | { | |||
| 1033 | int i; | |||
| 1034 | for (i=0; i<ep->num_jacks; i++) { | |||
| 1035 | DPRINTFN(10, ("\t\tjack(%p):\n", ep->jacks[i])); | |||
| 1036 | dump_jack(ep->jacks[i]); | |||
| 1037 | } | |||
| 1038 | } | |||
| 1039 | static void | |||
| 1040 | dump_jack(struct umidi_jack *jack) | |||
| 1041 | { | |||
| 1042 | DPRINTFN(10, ("\t\t\tep=%p\n", | |||
| 1043 | jack->endpoint)); | |||
| 1044 | } | |||
| 1045 | ||||
| 1046 | #endif /* UMIDI_DEBUG */ | |||
| 1047 | ||||
| 1048 | ||||
| 1049 | ||||
| 1050 | /* | |||
| 1051 | * MUX MIDI PACKET | |||
| 1052 | */ | |||
| 1053 | ||||
| 1054 | static const int packet_length[16] = { | |||
| 1055 | /*0*/ -1, | |||
| 1056 | /*1*/ -1, | |||
| 1057 | /*2*/ 2, | |||
| 1058 | /*3*/ 3, | |||
| 1059 | /*4*/ 3, | |||
| 1060 | /*5*/ 1, | |||
| 1061 | /*6*/ 2, | |||
| 1062 | /*7*/ 3, | |||
| 1063 | /*8*/ 3, | |||
| 1064 | /*9*/ 3, | |||
| 1065 | /*A*/ 3, | |||
| 1066 | /*B*/ 3, | |||
| 1067 | /*C*/ 2, | |||
| 1068 | /*D*/ 2, | |||
| 1069 | /*E*/ 3, | |||
| 1070 | /*F*/ 1, | |||
| 1071 | }; | |||
| 1072 | ||||
| 1073 | #define GET_CN(p)(((unsigned char)(p)>>4)&0x0F) (((unsigned char)(p)>>4)&0x0F) | |||
| 1074 | #define GET_CIN(p)((unsigned char)(p)&0x0F) ((unsigned char)(p)&0x0F) | |||
| 1075 | ||||
| 1076 | static void | |||
| 1077 | init_packet(struct umidi_packet *packet) | |||
| 1078 | { | |||
| 1079 | packet->status = 0; | |||
| 1080 | packet->index = 0; | |||
| 1081 | } | |||
| 1082 | ||||
| 1083 | static usbd_status | |||
| 1084 | start_input_transfer(struct umidi_endpoint *ep) | |||
| 1085 | { | |||
| 1086 | usbd_status err; | |||
| 1087 | usbd_setup_xfer(ep->xfer, ep->pipe, | |||
| 1088 | (void *)ep, | |||
| 1089 | ep->buffer, ep->packetsize, | |||
| 1090 | USBD_SHORT_XFER_OK0x04 | USBD_NO_COPY0x01, USBD_NO_TIMEOUT0, in_intr); | |||
| 1091 | err = usbd_transfer(ep->xfer); | |||
| 1092 | if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS) { | |||
| 1093 | DPRINTF(("%s: %s: usbd_transfer() failed err=%s\n", | |||
| 1094 | ep->sc->sc_dev.dv_xname, __func__, usbd_errstr(err))); | |||
| 1095 | return err; | |||
| 1096 | } | |||
| 1097 | return USBD_NORMAL_COMPLETION; | |||
| 1098 | } | |||
| 1099 | ||||
| 1100 | static usbd_status | |||
| 1101 | start_output_transfer(struct umidi_endpoint *ep) | |||
| 1102 | { | |||
| 1103 | usbd_status err; | |||
| 1104 | usbd_setup_xfer(ep->xfer, ep->pipe, | |||
| 1105 | (void *)ep, | |||
| 1106 | ep->buffer, ep->used, | |||
| 1107 | USBD_NO_COPY0x01, USBD_NO_TIMEOUT0, out_intr); | |||
| 1108 | err = usbd_transfer(ep->xfer); | |||
| 1109 | if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS) { | |||
| 1110 | DPRINTF(("%s: %s: usbd_transfer() failed err=%s\n", | |||
| 1111 | ep->sc->sc_dev.dv_xname, __func__, usbd_errstr(err))); | |||
| 1112 | return err; | |||
| 1113 | } | |||
| 1114 | ep->used = ep->packetsize; | |||
| 1115 | return USBD_NORMAL_COMPLETION; | |||
| 1116 | } | |||
| 1117 | ||||
| 1118 | ||||
| 1119 | #ifdef UMIDI_DEBUG | |||
| 1120 | #define DPR_PACKET(dir, sc, p) \ | |||
| 1121 | DPRINTFN(500, \ | |||
| 1122 | ("%s: umidi packet(" #dir "): %02X %02X %02X %02X\n", \ | |||
| 1123 | sc->sc_dev.dv_xname, \ | |||
| 1124 | (unsigned char)(p)->buffer[0], \ | |||
| 1125 | (unsigned char)(p)->buffer[1], \ | |||
| 1126 | (unsigned char)(p)->buffer[2], \ | |||
| 1127 | (unsigned char)(p)->buffer[3])); | |||
| 1128 | #else | |||
| 1129 | #define DPR_PACKET(dir, sc, p) | |||
| 1130 | #endif | |||
| 1131 | ||||
| 1132 | static int | |||
| 1133 | out_jack_output(struct umidi_jack *j, int d) | |||
| 1134 | { | |||
| 1135 | struct umidi_endpoint *ep = j->endpoint; | |||
| 1136 | struct umidi_softc *sc = ep->sc; | |||
| 1137 | int s; | |||
| 1138 | ||||
| 1139 | if (usbd_is_dying(sc->sc_udev)) | |||
| 1140 | return 1; | |||
| 1141 | if (!j->opened) | |||
| 1142 | return 1; | |||
| 1143 | s = splusb()splraise(0x5); | |||
| 1144 | if (ep->busy) { | |||
| 1145 | if (!j->intr) { | |||
| 1146 | SIMPLEQ_INSERT_TAIL(&ep->intrq, j, intrq_entry)do { (j)->intrq_entry.sqe_next = ((void *)0); *(&ep-> intrq)->sqh_last = (j); (&ep->intrq)->sqh_last = &(j)->intrq_entry.sqe_next; } while (0); | |||
| 1147 | ep->pending++; | |||
| 1148 | j->intr = 1; | |||
| 1149 | } | |||
| 1150 | splx(s)spllower(s); | |||
| 1151 | return 0; | |||
| 1152 | } | |||
| 1153 | if (!out_build_packet(j->cable_number, &j->packet, d, | |||
| 1154 | ep->buffer + ep->used)) { | |||
| 1155 | splx(s)spllower(s); | |||
| 1156 | return 1; | |||
| 1157 | } | |||
| 1158 | ep->used += UMIDI_PACKET_SIZE4; | |||
| 1159 | if (ep->used == ep->packetsize) { | |||
| 1160 | ep->busy = 1; | |||
| 1161 | start_output_transfer(ep); | |||
| 1162 | } | |||
| 1163 | splx(s)spllower(s); | |||
| 1164 | return 1; | |||
| 1165 | } | |||
| 1166 | ||||
| 1167 | static void | |||
| 1168 | out_jack_flush(struct umidi_jack *j) | |||
| 1169 | { | |||
| 1170 | struct umidi_endpoint *ep = j->endpoint; | |||
| 1171 | int s; | |||
| 1172 | ||||
| 1173 | if (usbd_is_dying(ep->sc->sc_udev) || !j->opened) | |||
| 1174 | return; | |||
| 1175 | ||||
| 1176 | s = splusb()splraise(0x5); | |||
| 1177 | if (ep->used != 0 && !ep->busy) { | |||
| 1178 | ep->busy = 1; | |||
| 1179 | start_output_transfer(ep); | |||
| 1180 | } | |||
| 1181 | splx(s)spllower(s); | |||
| 1182 | } | |||
| 1183 | ||||
| 1184 | ||||
| 1185 | static void | |||
| 1186 | in_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) | |||
| 1187 | { | |||
| 1188 | int cn, evlen, remain, i; | |||
| 1189 | unsigned char *buf; | |||
| 1190 | struct umidi_endpoint *ep = (struct umidi_endpoint *)priv; | |||
| 1191 | struct umidi_jack *jack; | |||
| 1192 | ||||
| 1193 | if (usbd_is_dying(ep->sc->sc_udev)) | |||
| 1194 | return; | |||
| 1195 | ||||
| 1196 | usbd_get_xfer_status(xfer, NULL((void *)0), NULL((void *)0), &remain, NULL((void *)0)); | |||
| 1197 | if (status != USBD_NORMAL_COMPLETION) { | |||
| 1198 | DPRINTF(("%s: abnormal status: %s\n", __func__, usbd_errstr(status))); | |||
| 1199 | return; | |||
| 1200 | } | |||
| 1201 | buf = ep->buffer; | |||
| 1202 | while (remain >= UMIDI_PACKET_SIZE4) { | |||
| 1203 | cn = GET_CN(buf[0])(((unsigned char)(buf[0])>>4)&0x0F); | |||
| 1204 | if (cn < ep->num_jacks && (jack = ep->jacks[cn]) && | |||
| 1205 | jack->binded && jack->opened && jack->u.in.intr) { | |||
| 1206 | evlen = packet_length[GET_CIN(buf[0])((unsigned char)(buf[0])&0x0F)]; | |||
| 1207 | mtx_enter(&audio_lock); | |||
| 1208 | for (i=0; i<evlen; i++) | |||
| 1209 | (*jack->u.in.intr)(jack->arg, buf[i+1]); | |||
| 1210 | mtx_leave(&audio_lock); | |||
| 1211 | } | |||
| 1212 | buf += UMIDI_PACKET_SIZE4; | |||
| 1213 | remain -= UMIDI_PACKET_SIZE4; | |||
| 1214 | } | |||
| 1215 | (void)start_input_transfer(ep); | |||
| 1216 | } | |||
| 1217 | ||||
| 1218 | static void | |||
| 1219 | out_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) | |||
| 1220 | { | |||
| 1221 | struct umidi_endpoint *ep = (struct umidi_endpoint *)priv; | |||
| 1222 | struct umidi_softc *sc = ep->sc; | |||
| 1223 | struct umidi_jack *j; | |||
| 1224 | unsigned pending; | |||
| 1225 | ||||
| 1226 | if (usbd_is_dying(sc->sc_udev)) | |||
| 1227 | return; | |||
| 1228 | ||||
| 1229 | ep->used = 0; | |||
| 1230 | ep->busy = 0; | |||
| 1231 | for (pending = ep->pending; pending > 0; pending--) { | |||
| 1232 | j = SIMPLEQ_FIRST(&ep->intrq)((&ep->intrq)->sqh_first); | |||
| 1233 | #ifdef DIAGNOSTIC1 | |||
| 1234 | if (j == NULL((void *)0)) { | |||
| 1235 | printf("umidi: missing intr entry\n"); | |||
| 1236 | break; | |||
| 1237 | } | |||
| 1238 | #endif | |||
| 1239 | SIMPLEQ_REMOVE_HEAD(&ep->intrq, intrq_entry)do { if (((&ep->intrq)->sqh_first = (&ep->intrq )->sqh_first->intrq_entry.sqe_next) == ((void *)0)) (& ep->intrq)->sqh_last = &(&ep->intrq)->sqh_first ; } while (0); | |||
| 1240 | ep->pending--; | |||
| 1241 | j->intr = 0; | |||
| 1242 | mtx_enter(&audio_lock); | |||
| 1243 | if (j->opened && j->u.out.intr) | |||
| 1244 | (*j->u.out.intr)(j->arg); | |||
| 1245 | mtx_leave(&audio_lock); | |||
| 1246 | } | |||
| 1247 | } | |||
| 1248 | ||||
| 1249 | #define UMIDI_VOICELEN(status)(umidi_evlen[((status) >> 4) & 7]) (umidi_evlen[((status) >> 4) & 7]) | |||
| 1250 | static const unsigned int umidi_evlen[] = { 4, 4, 4, 4, 3, 3, 4 }; | |||
| 1251 | ||||
| 1252 | #define EV_SYSEX0xf0 0xf0 | |||
| 1253 | #define EV_MTC0xf1 0xf1 | |||
| 1254 | #define EV_SPP0xf2 0xf2 | |||
| 1255 | #define EV_SONGSEL0xf3 0xf3 | |||
| 1256 | #define EV_TUNE_REQ0xf6 0xf6 | |||
| 1257 | #define EV_SYSEX_STOP0xf7 0xf7 | |||
| 1258 | ||||
| 1259 | static int | |||
| 1260 | out_build_packet(int cable_number, struct umidi_packet *packet, | |||
| 1261 | uByte data, u_char *obuf) | |||
| 1262 | { | |||
| 1263 | if (data >= 0xf8) { /* is it a realtime message ? */ | |||
| 1264 | obuf[0] = data >> 4 | cable_number << 4; | |||
| 1265 | obuf[1] = data; | |||
| 1266 | obuf[2] = 0; | |||
| 1267 | obuf[3] = 0; | |||
| 1268 | return 1; | |||
| 1269 | } | |||
| 1270 | if (data >= 0xf0) { /* is it a common message ? */ | |||
| 1271 | switch(data) { | |||
| 1272 | case EV_SYSEX0xf0: | |||
| 1273 | packet->buf[1] = packet->status = data; | |||
| 1274 | packet->index = 2; | |||
| 1275 | break; | |||
| 1276 | case EV_SYSEX_STOP0xf7: | |||
| 1277 | if (packet->status != EV_SYSEX0xf0) break; | |||
| 1278 | if (packet->index == 0) | |||
| 1279 | packet->index = 1; | |||
| 1280 | packet->status = data; | |||
| 1281 | packet->buf[packet->index++] = data; | |||
| 1282 | packet->buf[0] = (0x4 - 1 + packet->index) | cable_number << 4; | |||
| 1283 | goto packetready; | |||
| 1284 | case EV_TUNE_REQ0xf6: | |||
| 1285 | packet->status = data; | |||
| 1286 | packet->buf[0] = 0x5 | cable_number << 4; | |||
| 1287 | packet->index = 1; | |||
| 1288 | goto packetready; | |||
| 1289 | default: | |||
| 1290 | packet->status = data; | |||
| 1291 | break; | |||
| 1292 | } | |||
| 1293 | return 0; | |||
| 1294 | } | |||
| 1295 | if (data >= 0x80) { /* is it a voice message ? */ | |||
| 1296 | packet->status = data; | |||
| 1297 | packet->index = 0; | |||
| 1298 | return 0; | |||
| 1299 | } | |||
| 1300 | ||||
| 1301 | /* else it is a data byte */ | |||
| 1302 | if (packet->status >= 0xf0) { | |||
| 1303 | switch(packet->status) { | |||
| 1304 | case EV_SYSEX0xf0: /* sysex starts or continues */ | |||
| 1305 | if (packet->index == 0) | |||
| 1306 | packet->index = 1; | |||
| 1307 | ||||
| 1308 | packet->buf[packet->index++] = data; | |||
| 1309 | if (packet->index >= UMIDI_PACKET_SIZE4) { | |||
| 1310 | packet->buf[0] = 0x4 | cable_number << 4; | |||
| 1311 | goto packetready; | |||
| 1312 | } | |||
| 1313 | break; | |||
| 1314 | case EV_MTC0xf1: /* messages with 1 data byte */ | |||
| 1315 | case EV_SONGSEL0xf3: | |||
| 1316 | packet->buf[0] = 0x2 | cable_number << 4; | |||
| 1317 | packet->buf[1] = packet->status; | |||
| 1318 | packet->buf[2] = data; | |||
| 1319 | packet->index = 3; | |||
| 1320 | goto packetready; | |||
| 1321 | case EV_SPP0xf2: /* messages with 2 data bytes */ | |||
| 1322 | if (packet->index == 0) { | |||
| 1323 | packet->buf[0] = 0x3 | cable_number << 4; | |||
| 1324 | packet->index = 1; | |||
| 1325 | } | |||
| 1326 | packet->buf[packet->index++] = data; | |||
| 1327 | if (packet->index >= UMIDI_PACKET_SIZE4) { | |||
| 1328 | packet->buf[1] = packet->status; | |||
| 1329 | goto packetready; | |||
| 1330 | } | |||
| 1331 | break; | |||
| 1332 | default: /* ignore data with unknown status */ | |||
| 1333 | break; | |||
| 1334 | } | |||
| 1335 | return 0; | |||
| 1336 | } | |||
| 1337 | if (packet->status >= 0x80) { /* is it a voice message ? */ | |||
| 1338 | if (packet->index == 0) { | |||
| 1339 | packet->buf[0] = packet->status >> 4 | cable_number << 4; | |||
| 1340 | packet->buf[1] = packet->status; | |||
| 1341 | packet->index = 2; | |||
| 1342 | } | |||
| 1343 | packet->buf[packet->index++] = data; | |||
| 1344 | if (packet->index >= UMIDI_VOICELEN(packet->status)(umidi_evlen[((packet->status) >> 4) & 7])) | |||
| 1345 | goto packetready; | |||
| 1346 | } | |||
| 1347 | /* ignore data with unknown status */ | |||
| 1348 | return 0; | |||
| 1349 | ||||
| 1350 | packetready: | |||
| 1351 | while (packet->index < UMIDI_PACKET_SIZE4) | |||
| 1352 | packet->buf[packet->index++] = 0; | |||
| 1353 | packet->index = 0; | |||
| 1354 | memcpy(obuf, packet->buf, UMIDI_PACKET_SIZE)__builtin_memcpy((obuf), (packet->buf), (4)); | |||
| 1355 | return 1; | |||
| 1356 | } |