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