1 /* 2 * midi usb driver 3 * usb_midi.c 4 * 5 * Copyright 2006-2011 Haiku Inc. All rights reserved. 6 * Distributed under the terms of the MIT Licence. 7 * 8 * Authors: 9 * Jérôme Duval 10 * Pete Goodeve, pete.goodeve@computer.org 11 * 12 * Some portions of this code were originally derived from 13 * USB Joystick driver for BeOS R5 14 * Copyright 2000 (C) ITO, Takayuki 15 * All rights reserved 16 * 17 */ 18 19 20 /* #define DEBUG 1 */ /* Define this to enable DPRINTF_DEBUG statements */ 21 /* (Other categories of printout set in usb_midi.h) */ 22 23 #include "usb_midi.h" 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 31 const char* midi_base_name = "midi/usb/"; 32 33 34 usbmidi_port_info* 35 create_usbmidi_port(usbmidi_device_info* devinfo, 36 int cable, bool has_in, bool has_out) 37 { 38 usbmidi_port_info* port = NULL; 39 assert(usb != NULL && devinfo != NULL); 40 41 port = (usbmidi_port_info*)malloc(sizeof(usbmidi_port_info)); 42 if (port == NULL) 43 return NULL; 44 45 sprintf(port->name, "%s-%d", devinfo->name, cable); 46 port->device = devinfo; 47 port->cable = cable; 48 port->next = NULL; 49 port->open = 0; 50 port->open_fd = NULL; 51 port->has_in = has_in; 52 port->has_out = has_out; 53 port->rbuf = create_ring_buffer(1024); 54 55 devinfo->ports[cable] = port; 56 57 DPRINTF_INFO((MY_ID "Created port %p cable %d: %s\n", 58 port, cable, port->name)); 59 60 return port; 61 } 62 63 64 void 65 remove_port(usbmidi_port_info* port) 66 { 67 assert(port != NULL); 68 if (port->rbuf != NULL) { 69 delete_ring_buffer(port->rbuf); 70 port->rbuf = NULL; 71 } 72 DPRINTF_INFO((MY_ID "remove_port %p done\n", port)); 73 74 free(port); 75 } 76 77 78 usbmidi_device_info* 79 create_device(const usb_device* dev, uint16 ifno) 80 { 81 usbmidi_device_info* midiDevice = NULL; 82 int number; 83 area_id area; 84 sem_id sem; 85 char area_name[32]; 86 87 assert(usb != NULL && dev != NULL); 88 89 number = find_free_device_number(); 90 91 midiDevice = (usbmidi_device_info*)malloc(sizeof(usbmidi_device_info)); 92 if (midiDevice == NULL) 93 return NULL; 94 95 midiDevice->sem_lock = sem = create_sem(1, DRIVER_NAME "_lock"); 96 if (sem < 0) { 97 DPRINTF_ERR((MY_ID "create_sem() failed 0x%lx\n", sem)); 98 free(midiDevice); 99 return NULL; 100 } 101 102 sprintf(area_name, DRIVER_NAME "_buffer%d", number); 103 midiDevice->buffer_area = area = create_area(area_name, 104 (void**)&midiDevice->buffer, B_ANY_KERNEL_ADDRESS, 105 B_PAGE_SIZE, B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); 106 if (area < 0) { 107 DPRINTF_ERR((MY_ID "create_area() failed 0x%lx\n", area)); 108 delete_sem(midiDevice->sem_lock); 109 free(midiDevice); 110 return NULL; 111 } 112 /* use half of reserved area for each of in and out buffers: */ 113 midiDevice->out_buffer = 114 (usb_midi_event_packet*)((uint8*)midiDevice->buffer + B_PAGE_SIZE / 2); 115 midiDevice->sem_send = sem = create_sem(1, DRIVER_NAME "_send"); 116 if (sem < 0) { 117 DPRINTF_ERR((MY_ID "create_sem() failed 0x%lx\n", sem)); 118 delete_sem(midiDevice->sem_lock); 119 delete_area(area); 120 free(midiDevice); 121 return NULL; 122 } 123 { 124 int32 bc; 125 get_sem_count(sem, &bc); 126 DPRINTF_DEBUG((MY_ID "Allocated %ld write buffers\n", bc)); 127 } 128 129 130 sprintf(midiDevice->name, "%s%d", midi_base_name, number); 131 midiDevice->dev = dev; 132 midiDevice->devnum = number; 133 midiDevice->ifno = ifno; 134 midiDevice->active = true; 135 midiDevice->flags = 0; 136 memset(midiDevice->ports, 0, sizeof(midiDevice->ports)); 137 midiDevice->buffer_size = B_PAGE_SIZE / 2; 138 DPRINTF_INFO((MY_ID "Created device %p\n", midiDevice)); 139 140 return midiDevice; 141 } 142 143 144 void 145 remove_device(usbmidi_device_info* midiDevice) 146 { 147 assert(midiDevice != NULL); 148 DPRINTF_INFO((MY_ID "remove_device %p\n", midiDevice)); 149 150 delete_area(midiDevice->buffer_area); 151 delete_sem(midiDevice->sem_lock); 152 delete_sem(midiDevice->sem_send); 153 free(midiDevice); 154 } 155 156 157 /* driver cookie (per open -- but only one open per port allowed!) */ 158 159 typedef struct driver_cookie 160 { 161 struct driver_cookie* next; 162 usbmidi_device_info* device; /* a bit redundant, but convenient */ 163 usbmidi_port_info* port; 164 sem_id sem_cb; 165 } driver_cookie; 166 167 168 /* NB global variables are valid only while driver is loaded */ 169 170 _EXPORT int32 api_version = B_CUR_DRIVER_API_VERSION; 171 172 const char* usb_midi_driver_name = "usb_midi"; 173 174 const int CINbytes[] = { /* See USB-MIDI Spec */ 175 0, /* 0x0 -- undefined Misc -- Reserved */ 176 0, /* 0x1 -- undefined Cable -- Reserved */ 177 2, /* 0x2 -- 2-byte system common */ 178 3, /* 0x3 -- 3-byte system common */ 179 3, /* 0x4 -- SysEx start/continue */ 180 1, /* 0x5 -- SysEx single-byte-end, or 1-byte Common */ 181 2, /* 0x6 -- SysEx two-byte-end */ 182 3, /* 0x7 -- SysEx three-byte-end */ 183 3, /* 0x8 -- Note Off */ 184 3, /* 0x9 -- Note On */ 185 3, /* 0xA -- Poly KeyPress*/ 186 3, /* 0xB -- Control Change */ 187 2, /* 0xC -- Program Change */ 188 2, /* 0xD -- Channel Pressure */ 189 3, /* 0xE -- Pitch Bend */ 190 1, /* 0xF -- Single Byte */ 191 }; 192 193 usb_module_info* usb; 194 195 196 static void 197 interpret_midi_buffer(usbmidi_device_info* midiDevice) 198 { 199 usb_midi_event_packet* packet = midiDevice->buffer; 200 size_t bytes_left = midiDevice->actual_length; 201 while (bytes_left) { /* buffer may have several packets */ 202 int pktlen = CINbytes[packet->cin]; 203 usbmidi_port_info* port = midiDevice->ports[packet->cn]; 204 205 DPRINTF_DEBUG((MY_ID "received packet %x:%d %x %x %x\n", 206 packet->cin, packet->cn, 207 packet->midi[0], packet->midi[1], packet->midi[2])); 208 209 /* port matching 'cable number' */ 210 if (port == NULL) { 211 DPRINTF_ERR((MY_ID "no port matching cable number %d!\n", 212 packet->cn)); 213 } else { 214 ring_buffer_write(port->rbuf, packet->midi, pktlen); 215 release_sem_etc(port->open_fd->sem_cb, pktlen, 216 B_DO_NOT_RESCHEDULE); 217 } 218 219 packet++; 220 bytes_left -= sizeof(usb_midi_event_packet); 221 } 222 } 223 224 225 /* 226 callback: got a report, issue next request 227 */ 228 229 static void 230 midi_usb_read_callback(void* cookie, status_t status, 231 void* data, size_t actual_len) 232 { 233 status_t st; 234 usbmidi_device_info* midiDevice = (usbmidi_device_info*)cookie; 235 236 assert(cookie != NULL); 237 DPRINTF_DEBUG((MY_ID "midi_usb_read_callback() -- packet length %ld\n", 238 actual_len)); 239 240 acquire_sem(midiDevice->sem_lock); 241 midiDevice->actual_length = actual_len; 242 midiDevice->bus_status = status; /* B_USB_STATUS_* */ 243 if (status != B_OK) { 244 /* request failed */ 245 DPRINTF_DEBUG((MY_ID "bus status 0x%lx\n", status)); 246 if (status == B_CANCELED || !midiDevice->active) { 247 /* cancelled: device is unplugged */ 248 DPRINTF_DEBUG((MY_ID "midi_usb_read_callback: cancelled" 249 "(status=%lx active=%d -- deleting sem_cbs\n", 250 status, midiDevice->active)); 251 252 // Free any read() still blocked on semaphore 253 for (int cable = 0; cable < 16; cable++) { 254 usbmidi_port_info* port = midiDevice->ports[cable]; 255 if (port == NULL) 256 break; 257 if (port->open_fd != NULL) 258 delete_sem(port->open_fd->sem_cb); 259 } 260 release_sem(midiDevice->sem_lock); 261 return; 262 } 263 release_sem(midiDevice->sem_lock); 264 } else { 265 /* got a report */ 266 midiDevice->timestamp = system_time(); /* not used... */ 267 268 interpret_midi_buffer(midiDevice); 269 release_sem(midiDevice->sem_lock); 270 } 271 272 /* issue next request */ 273 st = usb->queue_bulk(midiDevice->ept_in->handle, 274 midiDevice->buffer, midiDevice->buffer_size, 275 (usb_callback_func)midi_usb_read_callback, midiDevice); 276 if (st != B_OK) { 277 /* probably endpoint stall */ 278 DPRINTF_ERR((MY_ID "queue_bulk() error 0x%lx\n", st)); 279 } 280 } 281 282 283 static void 284 midi_usb_write_callback(void* cookie, status_t status, 285 void* data, size_t actual_len) 286 { 287 usbmidi_device_info* midiDevice = (usbmidi_device_info*)cookie; 288 #ifdef DEBUG 289 usb_midi_event_packet* pkt = data; 290 #endif 291 292 assert(cookie != NULL); 293 DPRINTF_DEBUG((MY_ID "midi_usb_write_callback()" 294 " status %ld length %ld pkt %p cin %x\n", 295 status, actual_len, pkt, pkt->cin)); 296 release_sem(midiDevice->sem_send); /* done with buffer */ 297 } 298 299 300 /* 301 USB specific device hooks 302 */ 303 304 static status_t 305 usb_midi_added(const usb_device* dev, void** cookie) 306 { 307 /* This seems overcomplicated, but endpoints can be in either order... 308 and could possibly have different number of connectors! */ 309 int in_cables = 0, out_cables = 0; 310 int cable_count[2] = {0, 0}; 311 int iep = 0; 312 status_t status; 313 314 assert(dev != NULL && cookie != NULL); 315 DPRINTF_INFO((MY_ID "usb_midi_added(%p, %p)\n", dev, cookie)); 316 317 const usb_device_descriptor* dev_desc = usb->get_device_descriptor(dev); 318 319 DPRINTF_INFO((MY_ID "vendor ID 0x%04X, product ID 0x%04X\n", 320 dev_desc->vendor_id, dev_desc->product_id)); 321 322 /* check interface class */ 323 const usb_configuration_info* conf; 324 if ((conf = usb->get_nth_configuration(dev, DEFAULT_CONFIGURATION)) 325 == NULL) { 326 DPRINTF_ERR((MY_ID "cannot get default configuration\n")); 327 return B_ERROR; 328 } 329 DPRINTF_INFO((MY_ID "Interface count = %ld\n", conf->interface_count)); 330 331 uint16 alt, ifno; 332 const usb_interface_info* intf; 333 for (ifno = 0; ifno < conf->interface_count; ifno++) { 334 int devclass, subclass, protocol; 335 336 for (alt = 0; alt < conf->interface[ifno].alt_count; alt++) { 337 intf = &conf->interface[ifno].alt[alt]; 338 devclass = intf->descr->interface_class; 339 subclass = intf->descr->interface_subclass; 340 protocol = intf->descr->interface_protocol; 341 DPRINTF_INFO(( 342 MY_ID "interface %d, alt : %d: class %d," 343 " subclass %d, protocol %d\n", 344 ifno, alt, devclass, subclass, protocol)); 345 346 if (devclass == USB_AUDIO_DEVICE_CLASS 347 && subclass == USB_AUDIO_INTERFACE_MIDISTREAMING_SUBCLASS) 348 goto got_one; 349 } 350 } 351 352 DPRINTF_INFO((MY_ID "Midi interface not found\n")); 353 return B_ERROR; 354 355 got_one: 356 357 if ((status = usb->set_configuration(dev, conf)) != B_OK) { 358 DPRINTF_ERR((MY_ID "set_configuration() failed 0x%lx\n", status)); 359 return B_ERROR; 360 } 361 362 usbmidi_device_info* midiDevice; 363 if ((midiDevice = create_device(dev, ifno)) == NULL) { 364 return B_ERROR; 365 } 366 367 /* get the actual number of ports in and out */ 368 for (uint16 i = 0; i < intf->generic_count; i++) { 369 usb_generic_descriptor *generic = &intf->generic[i]->generic; 370 DPRINTF_DEBUG((MY_ID "descriptor %d: type %x sub %x\n", 371 i, generic->descriptor_type, generic->data[0])); 372 if (generic->descriptor_type == USB_DESCRIPTOR_CS_ENDPOINT 373 && generic->data[0] == USB_MS_GENERAL_DESCRIPTOR) { 374 /* These *better* be in the same order as the endpoints! */ 375 cable_count[iep] = generic->data[1]; 376 iep = 1; 377 } 378 } 379 380 DPRINTF_DEBUG((MY_ID "midiDevice = %p endpoint count = %ld\n", 381 midiDevice, intf->endpoint_count)); 382 midiDevice->ept_in = midiDevice->ept_out = NULL; 383 384 for (uint16 i = 0; i < intf->endpoint_count && i < 2; i++) { 385 /* we are actually assuming max one IN, one OUT endpoint... */ 386 DPRINTF_INFO((MY_ID "endpoint %d = %p %s\n", 387 i, &intf->endpoint[i], 388 (intf->endpoint[i].descr->endpoint_address & 0x80) != 0 389 ? "IN" : "OUT")); 390 if ((intf->endpoint[i].descr->endpoint_address & 0x80) != 0) { 391 if (midiDevice->ept_in == NULL) { 392 midiDevice->ept_in = &intf->endpoint[i]; 393 in_cables = cable_count[i]; 394 } 395 } else if (midiDevice->ept_out == NULL) { 396 midiDevice->ept_out = &intf->endpoint[i]; 397 out_cables = cable_count[i]; 398 } 399 } 400 401 midiDevice->timestamp = system_time(); /* This never seems to be used */ 402 403 /* Create the actual device ports */ 404 usbmidi_port_info* port; 405 for (uint16 i = 0; in_cables > 0 || out_cables > 0; i++) { 406 port = create_usbmidi_port(midiDevice, i, 407 (bool)in_cables, (bool)out_cables); 408 midiDevice->ports[i] = port; 409 if (in_cables) 410 in_cables--; 411 if (out_cables) 412 out_cables--; 413 add_port_info(port); 414 } 415 416 /* issue bulk transfer */ 417 DPRINTF_DEBUG((MY_ID "queueing bulk xfer IN endpoint\n")); 418 status = usb->queue_bulk(midiDevice->ept_in->handle, midiDevice->buffer, 419 midiDevice->buffer_size, 420 (usb_callback_func)midi_usb_read_callback, midiDevice); 421 if (status != B_OK) { 422 DPRINTF_ERR((MY_ID "queue_bulk() error 0x%lx\n", status)); 423 return B_ERROR; 424 } 425 426 *cookie = midiDevice; 427 DPRINTF_INFO((MY_ID "usb_midi_added: %s\n", midiDevice->name)); 428 429 return B_OK; 430 } 431 432 433 static status_t 434 usb_midi_removed(void* cookie) 435 { 436 usbmidi_device_info* midiDevice = (usbmidi_device_info*)cookie; 437 438 assert(cookie != NULL); 439 440 DPRINTF_INFO((MY_ID "usb_midi_removed(%s)\n", midiDevice->name)); 441 midiDevice->active = false; 442 for (int cable = 0; cable < 16; cable++) { 443 usbmidi_port_info* port = midiDevice->ports[cable]; 444 if (port == NULL) 445 break; 446 DPRINTF_DEBUG((MY_ID "removing port %d\n", cable)); 447 if (port->open_fd != NULL) { 448 remove_port_info(port); 449 port->open_fd->port = NULL; 450 port->open_fd->device = NULL; 451 delete_sem(port->open_fd->sem_cb); 452 /* done here to ensure read is freed */ 453 } 454 remove_port(port); 455 } 456 usb->cancel_queued_transfers(midiDevice->ept_in->handle); 457 usb->cancel_queued_transfers(midiDevice->ept_out->handle); 458 DPRINTF_DEBUG((MY_ID "usb_midi_removed: doing remove: %s\n", 459 midiDevice->name)); 460 remove_device(midiDevice); 461 return B_OK; 462 } 463 464 465 static usb_notify_hooks my_notify_hooks = 466 { 467 usb_midi_added, usb_midi_removed 468 }; 469 470 #define SUPPORTED_DEVICES 1 471 usb_support_descriptor my_supported_devices[SUPPORTED_DEVICES] = 472 { 473 { 474 USB_AUDIO_DEVICE_CLASS, 475 USB_AUDIO_INTERFACE_MIDISTREAMING_SUBCLASS, 476 0, 0, 0 477 }, 478 }; 479 480 481 /* 482 Device Driver Hook Functions 483 -- open, read, write, close, and free 484 */ 485 486 static status_t 487 usb_midi_open(const char* name, uint32 flags, 488 driver_cookie** out_cookie) 489 { 490 driver_cookie* cookie; 491 usbmidi_port_info* port; 492 int mode = flags & O_RWMASK; 493 494 assert(name != NULL); 495 assert(out_cookie != NULL); 496 DPRINTF_INFO((MY_ID "usb_midi_open(%s) flags=%lx\n", name, flags)); 497 498 if ((port = search_port_info(name)) == NULL) 499 return B_ENTRY_NOT_FOUND; 500 501 if (!port->has_in && mode != O_RDONLY) 502 return B_PERMISSION_DENIED; /* == EACCES */ 503 else if (!port->has_out && mode != O_WRONLY) 504 return B_PERMISSION_DENIED; 505 506 if ((cookie = (driver_cookie*)malloc(sizeof(driver_cookie))) == NULL) 507 return B_NO_MEMORY; 508 509 cookie->sem_cb = create_sem(0, DRIVER_NAME "_cb"); 510 if (cookie->sem_cb < 0) { 511 DPRINTF_ERR((MY_ID "create_sem() failed 0x%lx\n", cookie->sem_cb)); 512 free(cookie); 513 return B_ERROR; 514 } 515 516 cookie->port = port; 517 cookie->device = port->device; 518 519 acquire_sem(usbmidi_port_list_lock); 520 if (port->open_fd != NULL) { 521 /* there can only be one open channel to the device */ 522 delete_sem(cookie->sem_cb); 523 free(cookie); 524 release_sem(usbmidi_port_list_lock); 525 return B_BUSY; 526 } 527 port->open_fd = cookie; 528 port->open++; 529 release_sem(usbmidi_port_list_lock); 530 531 *out_cookie = cookie; 532 DPRINTF_INFO((MY_ID "usb_midi_open: device %s open (%d)\n", 533 name, port->open)); 534 return B_OK; 535 } 536 537 538 static status_t 539 usb_midi_read(driver_cookie* cookie, off_t position, 540 void* buf, size_t* num_bytes) 541 { 542 assert(cookie != NULL); 543 status_t err = B_ERROR; 544 usbmidi_port_info* port = cookie->port; 545 usbmidi_device_info* midiDevice = cookie->device; 546 547 if (midiDevice == NULL || !midiDevice->active) 548 return B_ERROR; /* already unplugged */ 549 550 DPRINTF_DEBUG((MY_ID "usb_midi_read: (%ld byte buffer at %lld cookie %p)" 551 "\n", *num_bytes, position, cookie)); 552 while (midiDevice && midiDevice->active) { 553 DPRINTF_DEBUG((MY_ID "waiting on acquire_sem_etc\n")); 554 err = acquire_sem_etc(cookie->sem_cb, 1, 555 B_RELATIVE_TIMEOUT, 1000000); 556 if (err == B_TIMED_OUT) { 557 DPRINTF_DEBUG((MY_ID "acquire_sem_etc timed out\n")); 558 continue; /* see if we're still active */ 559 } 560 if (err != B_OK) { 561 *num_bytes = 0; 562 DPRINTF_DEBUG((MY_ID "acquire_sem_etc aborted\n")); 563 break; 564 } 565 DPRINTF_DEBUG((MY_ID "reading from ringbuffer\n")); 566 acquire_sem(midiDevice->sem_lock); 567 /* a global semaphore -- OK, I think */ 568 ring_buffer_user_read(port->rbuf, (uint8*)buf, 1); 569 release_sem(midiDevice->sem_lock); 570 *num_bytes = 1; 571 DPRINTF_DEBUG((MY_ID "read byte %x -- cookie %p)\n", 572 *(uint8*)buf, cookie)); 573 return B_OK; 574 } 575 DPRINTF_INFO((MY_ID "usb_midi_read: loop terminated" 576 " -- Device no longer active\n")); 577 return B_CANCELED; 578 } 579 580 581 const uint8 CINcode[] = { /* see USB-MIDI Spec */ 582 0x4, /* 0x0 - sysex start */ 583 0, /* 0x1 -- undefined */ 584 0x3, /* 0x2 -- song pos */ 585 0x2, /* 0x3 -- song select */ 586 0, /* 0x4 -- undefined */ 587 0, /* 0x5 -- undefined */ 588 0x2, /* 0x6 -- tune request */ 589 0x5, /* 0x7 -- sysex end */ 590 0x5, /* 0x8 -- clock */ 591 0, /* 0x9 -- undefined */ 592 0x5, /* 0xA -- start */ 593 0x5, /* 0xB -- continue */ 594 0x5, /* 0xC -- stop */ 595 0, /* 0xD -- undefined */ 596 0x5, /* 0xE -- active sensing */ 597 0x5, /* 0x0 -- system reset */ 598 }; 599 600 601 static status_t 602 usb_midi_write(driver_cookie* cookie, off_t position, 603 const void* buf, size_t* num_bytes) 604 { 605 uint8* midiseq = (uint8*)buf; 606 uint8 midicode = midiseq[0]; /* preserved for reference */ 607 status_t status; 608 size_t buff_lim; 609 uint8 cin = ((midicode & 0xF0) == 0xF0) ? CINcode[midicode & 0x0F] 610 : (midicode >> 4); 611 612 assert(cookie != NULL); 613 usbmidi_port_info* port = cookie->port; 614 usbmidi_device_info* midiDevice = cookie->device; 615 616 if (!midiDevice || !midiDevice->active) 617 return B_ERROR; /* already unplugged */ 618 619 buff_lim = midiDevice->buffer_size * 3 / 4; 620 /* max MIDI bytes buffer space */ 621 622 DPRINTF_DEBUG((MY_ID "MIDI write (%ld bytes at %lld)\n", 623 *num_bytes, position)); 624 if (*num_bytes > 3 && midicode != 0xF0) { 625 DPRINTF_ERR((MY_ID "Non-SysEx packet of %ld bytes" 626 " -- too big to handle\n", *num_bytes)); 627 return B_ERROR; 628 } 629 630 size_t bytes_left = *num_bytes; 631 while (bytes_left) { 632 size_t xfer_bytes = (bytes_left < buff_lim) ? bytes_left : buff_lim; 633 usb_midi_event_packet* pkt = midiDevice->out_buffer; 634 int packet_count = 0; 635 636 status = acquire_sem_etc(midiDevice->sem_send, 637 1, B_RELATIVE_TIMEOUT, 2000000LL); 638 if (status != B_OK) 639 return status; 640 641 while (xfer_bytes) { 642 uint8 pkt_bytes = CINbytes[cin]; 643 memset(pkt, 0, sizeof(usb_midi_event_packet)); 644 pkt->cin = cin; 645 pkt->cn = port->cable; 646 DPRINTF_DEBUG((MY_ID "using packet data (code %x -- %d bytes)" 647 " %x %x %x\n", pkt->cin, CINbytes[pkt->cin], 648 midiseq[0], midiseq[1], midiseq[2])); 649 memcpy(pkt->midi, midiseq, pkt_bytes); 650 DPRINTF_DEBUG((MY_ID "built packet %p %x:%d %x %x %x\n", 651 pkt, pkt->cin, pkt->cn, 652 pkt->midi[0], pkt->midi[1], pkt->midi[2])); 653 xfer_bytes -= pkt_bytes; 654 bytes_left -= pkt_bytes; 655 midiseq += pkt_bytes; 656 packet_count++; 657 pkt++; 658 if (midicode == 0xF0 && bytes_left < 4) cin = 4 + bytes_left; 659 /* see USB-MIDI Spec */ 660 } 661 status = usb->queue_bulk(midiDevice->ept_out->handle, 662 midiDevice->out_buffer, sizeof(usb_midi_event_packet) 663 * packet_count, (usb_callback_func)midi_usb_write_callback, 664 midiDevice); 665 if (status != B_OK) { 666 DPRINTF_ERR((MY_ID "midi write queue_bulk() error 0x%lx\n", 667 status)); 668 return B_ERROR; 669 } 670 } 671 return B_OK; 672 } 673 674 675 static status_t 676 usb_midi_control(void* cookie, uint32 iop, void* data, size_t len) 677 { 678 return B_ERROR; 679 } 680 681 682 static status_t 683 usb_midi_close(driver_cookie* cookie) 684 { 685 assert(cookie != NULL); 686 delete_sem(cookie->sem_cb); 687 688 usbmidi_port_info* port = cookie->port; 689 usbmidi_device_info* midiDevice = cookie->device; 690 691 DPRINTF_INFO((MY_ID "usb_midi_close(%p device=%p port=%p)\n", 692 cookie, midiDevice, port)); 693 694 acquire_sem(usbmidi_port_list_lock); 695 if (port != NULL) { 696 /* detach the cookie from port */ 697 port->open_fd = NULL; 698 --port->open; 699 } 700 release_sem(usbmidi_port_list_lock); 701 DPRINTF_DEBUG((MY_ID "usb_midi_close: complete\n")); 702 703 return B_OK; 704 } 705 706 707 static status_t 708 usb_midi_free(driver_cookie* cookie) 709 { 710 assert(cookie != NULL); 711 usbmidi_device_info* midiDevice = cookie->device; 712 DPRINTF_INFO((MY_ID "usb_midi_free(%p device=%p)\n", cookie, midiDevice)); 713 714 free(cookie); 715 716 return B_OK; 717 } 718 719 720 static device_hooks usb_midi_hooks = { 721 (device_open_hook)usb_midi_open, 722 (device_close_hook)usb_midi_close, 723 (device_free_hook)usb_midi_free, 724 (device_control_hook)usb_midi_control, 725 (device_read_hook)usb_midi_read, 726 (device_write_hook)usb_midi_write, 727 NULL, NULL, NULL, NULL 728 }; 729 730 731 /* 732 Driver Registration 733 */ 734 735 _EXPORT status_t 736 init_hardware(void) 737 { 738 DPRINTF_DEBUG((MY_ID "init_hardware() version:" 739 __DATE__ " " __TIME__ "\n")); 740 return B_OK; 741 } 742 743 744 _EXPORT status_t 745 init_driver(void) 746 { 747 DPRINTF_INFO((MY_ID "init_driver() version:" __DATE__ " " __TIME__ "\n")); 748 749 if (get_module(B_USB_MODULE_NAME, (module_info**)&usb) != B_OK) 750 return B_ERROR; 751 752 if ((usbmidi_port_list_lock = create_sem(1, "dev_list_lock")) < 0) { 753 put_module(B_USB_MODULE_NAME); 754 return usbmidi_port_list_lock; /* error code */ 755 } 756 757 usb->register_driver(usb_midi_driver_name, my_supported_devices, 758 SUPPORTED_DEVICES, NULL); 759 usb->install_notify(usb_midi_driver_name, &my_notify_hooks); 760 DPRINTF_INFO((MY_ID "init_driver() OK\n")); 761 762 return B_OK; 763 } 764 765 766 _EXPORT void 767 uninit_driver(void) 768 { 769 DPRINTF_INFO((MY_ID "uninit_driver()\n")); 770 usb->uninstall_notify(usb_midi_driver_name); 771 772 delete_sem(usbmidi_port_list_lock); 773 put_module(B_USB_MODULE_NAME); 774 free_port_names(); 775 DPRINTF_INFO((MY_ID "uninit complete\n")); 776 } 777 778 779 _EXPORT const char** 780 publish_devices(void) 781 { 782 DPRINTF_INFO((MY_ID "publish_devices()\n")); 783 784 if (usbmidi_port_list_changed) { 785 free_port_names(); 786 alloc_port_names(); 787 if (usbmidi_port_names != NULL) 788 rebuild_port_names(); 789 usbmidi_port_list_changed = false; 790 } 791 assert(usbmidi_port_names != NULL); 792 return (const char**)usbmidi_port_names; 793 } 794 795 796 _EXPORT device_hooks* 797 find_device(const char* name) 798 { 799 assert(name != NULL); 800 DPRINTF_INFO((MY_ID "find_device(%s)\n", name)); 801 if (search_port_info(name) == NULL) 802 return NULL; 803 return &usb_midi_hooks; 804 } 805 806