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