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