1 /* 2 * Copyright 2008, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include <ByteOrder.h> 10 #include <KernelExport.h> 11 #include <Drivers.h> 12 #include <malloc.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include "usb_disk.h" 16 #include "usb_disk_scsi.h" 17 18 19 #define DRIVER_NAME "usb_disk" 20 #define DEVICE_NAME_BASE "disk/usb/" 21 #define DEVICE_NAME DEVICE_NAME_BASE"%ld/%d/raw" 22 23 24 //#define TRACE_USB_DISK 25 #ifdef TRACE_USB_DISK 26 #define TRACE(x...) dprintf(DRIVER_NAME": "x) 27 #define TRACE_ALWAYS(x...) dprintf(DRIVER_NAME": "x) 28 #else 29 #define TRACE(x...) /* nothing */ 30 #define TRACE_ALWAYS(x...) dprintf(DRIVER_NAME": "x) 31 #endif 32 33 34 int32 api_version = B_CUR_DRIVER_API_VERSION; 35 static usb_module_info *gUSBModule = NULL; 36 static disk_device *gDeviceList = NULL; 37 static uint32 gDeviceCount = 0; 38 static uint32 gLunCount = 0; 39 static benaphore gDeviceListLock; 40 static char **gDeviceNames = NULL; 41 42 43 // 44 //#pragma mark - Forward Declarations 45 // 46 47 48 static void usb_disk_callback(void *cookie, status_t status, void *data, 49 size_t actualLength); 50 51 status_t usb_disk_mass_storage_reset(disk_device *device); 52 uint8 usb_disk_get_max_lun(disk_device *device); 53 void usb_disk_reset_recovery(disk_device *device); 54 status_t usb_disk_transfer_data(disk_device *device, bool directionIn, 55 void *data, size_t dataLength); 56 status_t usb_disk_receive_csw(disk_device *device, 57 command_status_wrapper *status); 58 status_t usb_disk_operation(device_lun *lun, uint8 operation, 59 uint8 opLength, uint32 logicalBlockAddress, 60 uint16 transferLength, void *data, uint32 *dataLength, 61 bool directionIn); 62 63 status_t usb_disk_request_sense(device_lun *lun); 64 status_t usb_disk_test_unit_ready(device_lun *lun); 65 status_t usb_disk_inquiry(device_lun *lun); 66 status_t usb_disk_reset_capacity(device_lun *lun); 67 status_t usb_disk_update_capacity(device_lun *lun); 68 status_t usb_disk_synchronize(device_lun *lun, bool force); 69 70 71 // 72 //#pragma mark - Device Allocation Helper Functions 73 // 74 75 76 void 77 usb_disk_free_device_and_luns(disk_device *device) 78 { 79 benaphore_lock(&device->lock); 80 benaphore_destroy(&device->lock); 81 delete_sem(device->notify); 82 for (uint8 i = 0; i < device->lun_count; i++) 83 free(device->luns[i]); 84 free(device->luns); 85 free(device); 86 } 87 88 89 // 90 //#pragma mark - Bulk-only Mass Storage Functions 91 // 92 93 94 status_t 95 usb_disk_mass_storage_reset(disk_device *device) 96 { 97 return gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_OUT 98 | USB_REQTYPE_CLASS, REQUEST_MASS_STORAGE_RESET, 0x0000, 99 device->interface, 0, NULL, NULL); 100 } 101 102 103 uint8 104 usb_disk_get_max_lun(disk_device *device) 105 { 106 uint8 result = 0; 107 size_t actualLength = 0; 108 109 // devices that do not support multiple LUNs may stall this request 110 if (gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_IN 111 | USB_REQTYPE_CLASS, REQUEST_GET_MAX_LUN, 0x0000, device->interface, 112 1, &result, &actualLength) != B_OK || actualLength != 1) 113 return 0; 114 115 if (result > MAX_LOGICAL_UNIT_NUMBER) { 116 // invalid max lun 117 return 0; 118 } 119 120 return result; 121 } 122 123 124 void 125 usb_disk_reset_recovery(disk_device *device) 126 { 127 usb_disk_mass_storage_reset(device); 128 gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); 129 gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 130 } 131 132 133 status_t 134 usb_disk_transfer_data(disk_device *device, bool directionIn, void *data, 135 size_t dataLength) 136 { 137 status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in 138 : device->bulk_out, data, dataLength, usb_disk_callback, device); 139 if (result != B_OK) { 140 TRACE_ALWAYS("failed to queue data transfer\n"); 141 return result; 142 } 143 144 do { 145 result = acquire_sem(device->notify); 146 } while (result == B_INTERRUPTED); 147 if (result != B_OK) { 148 TRACE_ALWAYS("acquire_sem failed while waiting for data transfer\n"); 149 return result; 150 } 151 152 return B_OK; 153 } 154 155 156 status_t 157 usb_disk_receive_csw(disk_device *device, command_status_wrapper *status) 158 { 159 status_t result = usb_disk_transfer_data(device, true, status, 160 sizeof(command_status_wrapper)); 161 if (result != B_OK) 162 return result; 163 164 if (device->status != B_OK 165 || device->actual_length != sizeof(command_status_wrapper)) { 166 // receiving the command status wrapper failed 167 return B_ERROR; 168 } 169 170 return B_OK; 171 } 172 173 174 status_t 175 usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, 176 uint32 logicalBlockAddress, uint16 transferLength, void *data, 177 uint32 *dataLength, bool directionIn) 178 { 179 disk_device *device = lun->device; 180 command_block_wrapper command; 181 command.signature = CBW_SIGNATURE; 182 command.tag = device->current_tag++; 183 command.data_transfer_length = (dataLength != NULL ? *dataLength : 0); 184 command.flags = (directionIn ? CBW_DATA_INPUT : CBW_DATA_OUTPUT); 185 command.lun = lun->logical_unit_number; 186 command.command_block_length = opLength; 187 memset(command.command_block, 0, sizeof(command.command_block)); 188 189 switch (opLength) { 190 case 6: { 191 scsi_command_6 *commandBlock = (scsi_command_6 *)command.command_block; 192 commandBlock->operation = operation; 193 commandBlock->lun = lun->logical_unit_number << 5; 194 commandBlock->allocation_length = (uint8)transferLength; 195 break; 196 } 197 198 case 10: { 199 scsi_command_10 *commandBlock = (scsi_command_10 *)command.command_block; 200 commandBlock->operation = operation; 201 commandBlock->lun_flags = lun->logical_unit_number << 5; 202 commandBlock->logical_block_address = htonl(logicalBlockAddress); 203 commandBlock->transfer_length = htons(transferLength); 204 break; 205 } 206 207 default: 208 TRACE_ALWAYS("unsupported operation length %d\n", opLength); 209 return B_BAD_VALUE; 210 } 211 212 status_t result = usb_disk_transfer_data(device, false, &command, 213 sizeof(command_block_wrapper)); 214 if (result != B_OK) 215 return result; 216 217 if (device->status != B_OK || 218 device->actual_length != sizeof(command_block_wrapper)) { 219 // sending the command block wrapper failed 220 TRACE_ALWAYS("sending the command block wrapper failed\n"); 221 usb_disk_reset_recovery(device); 222 return B_ERROR; 223 } 224 225 if (data != NULL && dataLength != NULL && *dataLength > 0) { 226 // we have data to transfer in a data stage 227 result = usb_disk_transfer_data(device, directionIn, data, *dataLength); 228 if (result != B_OK) 229 return result; 230 231 if (device->status != B_OK || device->actual_length != *dataLength) { 232 // sending or receiving of the data failed 233 if (device->status == B_DEV_STALLED) { 234 TRACE("stall while transfering data\n"); 235 gUSBModule->clear_feature(directionIn ? device->bulk_in 236 : device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 237 } else { 238 TRACE_ALWAYS("sending or receiving of the data failed\n"); 239 return B_ERROR; 240 } 241 } 242 } 243 244 command_status_wrapper status; 245 result = usb_disk_receive_csw(device, &status); 246 if (result != B_OK && device->status == B_DEV_STALLED) { 247 // in case of a stall clear the stall and try again 248 gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); 249 result = usb_disk_receive_csw(device, &status); 250 } 251 252 if (result != B_OK) { 253 TRACE_ALWAYS("receiving the command status wrapper failed\n"); 254 usb_disk_reset_recovery(device); 255 return result; 256 } 257 258 if (status.signature != CSW_SIGNATURE || status.tag != command.tag) { 259 // the command status wrapper is not valid 260 TRACE_ALWAYS("command status wrapper is not valid\n"); 261 usb_disk_reset_recovery(device); 262 return B_ERROR; 263 } 264 265 switch (status.status) { 266 case CSW_STATUS_COMMAND_PASSED: 267 case CSW_STATUS_COMMAND_FAILED: { 268 if (dataLength != NULL && status.data_residue <= *dataLength) 269 *dataLength -= status.data_residue; 270 271 if (status.status == CSW_STATUS_COMMAND_PASSED) { 272 // the operation is complete and has succeeded 273 result = B_OK; 274 } else { 275 // the operation is complete but has failed at the SCSI level 276 TRACE_ALWAYS("operation 0x%02x failed at the SCSI level\n", 277 operation); 278 result = usb_disk_request_sense(lun); 279 if (result == B_OK) 280 result = B_ERROR; 281 } 282 break; 283 } 284 285 case CSW_STATUS_PHASE_ERROR: { 286 // a protocol or device error occured 287 TRACE_ALWAYS("phase error in operation 0x%02x\n", operation); 288 usb_disk_reset_recovery(device); 289 if (dataLength != NULL) 290 *dataLength = 0; 291 result = B_ERROR; 292 } 293 } 294 295 return result; 296 } 297 298 299 // 300 //#pragma mark - Helper/Convenience Functions 301 // 302 303 304 status_t 305 usb_disk_request_sense(device_lun *lun) 306 { 307 uint32 dataLength = sizeof(scsi_request_sense_6_parameter); 308 scsi_request_sense_6_parameter parameter; 309 status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0, 310 dataLength, ¶meter, &dataLength, true); 311 if (result != B_OK) { 312 TRACE_ALWAYS("getting request sense data failed\n"); 313 return result; 314 } 315 316 if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY) { 317 TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: 0x%02x;\n", 318 parameter.sense_key, parameter.additional_sense_code, 319 parameter.additional_sense_code_qualifier); 320 } 321 322 switch (parameter.sense_key) { 323 case SCSI_SENSE_KEY_NO_SENSE: 324 case SCSI_SENSE_KEY_RECOVERED_ERROR: 325 return B_OK; 326 327 case SCSI_SENSE_KEY_NOT_READY: 328 TRACE("request_sense: device not ready (asc 0x%02x ascq 0x%02x)\n", 329 parameter.additional_sense_code, 330 parameter.additional_sense_code_qualifier); 331 lun->media_present = false; 332 usb_disk_reset_capacity(lun); 333 return B_DEV_NO_MEDIA; 334 335 case SCSI_SENSE_KEY_HARDWARE_ERROR: 336 case SCSI_SENSE_KEY_MEDIUM_ERROR: 337 TRACE_ALWAYS("request_sense: media or hardware error\n"); 338 return B_DEV_UNREADABLE; 339 340 case SCSI_SENSE_KEY_ILLEGAL_REQUEST: 341 TRACE_ALWAYS("request_sense: illegal request\n"); 342 return B_DEV_INVALID_IOCTL; 343 344 case SCSI_SENSE_KEY_UNIT_ATTENTION: 345 TRACE_ALWAYS("request_sense: media changed\n"); 346 lun->media_changed = true; 347 lun->media_present = true; 348 return B_DEV_MEDIA_CHANGED; 349 350 case SCSI_SENSE_KEY_DATA_PROTECT: 351 TRACE_ALWAYS("request_sense: write protected\n"); 352 return B_READ_ONLY_DEVICE; 353 354 case SCSI_SENSE_KEY_ABORTED_COMMAND: 355 TRACE_ALWAYS("request_sense: command aborted\n"); 356 return B_CANCELED; 357 } 358 359 return B_ERROR; 360 } 361 362 363 status_t 364 usb_disk_test_unit_ready(device_lun *lun) 365 { 366 return usb_disk_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0, NULL, NULL, 367 true); 368 } 369 370 371 status_t 372 usb_disk_inquiry(device_lun *lun) 373 { 374 uint32 dataLength = sizeof(scsi_inquiry_6_parameter); 375 scsi_inquiry_6_parameter parameter; 376 status_t result = B_ERROR; 377 for (uint32 tries = 0; tries < 3; tries++) { 378 result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength, 379 ¶meter, &dataLength, true); 380 if (result == B_OK) 381 break; 382 } 383 if (result != B_OK) { 384 TRACE_ALWAYS("getting inquiry data failed\n"); 385 lun->device_type = B_DISK; 386 lun->removable = true; 387 return result; 388 } 389 390 TRACE("peripherial_device_type 0x%02x\n", parameter.peripherial_device_type); 391 TRACE("peripherial_qualifier 0x%02x\n", parameter.peripherial_qualifier); 392 TRACE("removable_medium %s\n", parameter.removable_medium ? "yes" : "no"); 393 TRACE("version 0x%02x\n", parameter.version); 394 TRACE("response_data_format 0x%02x\n", parameter.response_data_format); 395 TRACE_ALWAYS("vendor_identification \"%.8s\"\n", parameter.vendor_identification); 396 TRACE_ALWAYS("product_identification \"%.16s\"\n", parameter.product_identification); 397 TRACE_ALWAYS("product_revision_level \"%.4s\"\n", parameter.product_revision_level); 398 lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ 399 lun->removable = (parameter.removable_medium == 1); 400 return B_OK; 401 } 402 403 404 status_t 405 usb_disk_reset_capacity(device_lun *lun) 406 { 407 lun->block_size = 512; 408 lun->block_count = 0; 409 return B_OK; 410 } 411 412 413 status_t 414 usb_disk_update_capacity(device_lun *lun) 415 { 416 uint32 dataLength = sizeof(scsi_read_capacity_10_parameter); 417 scsi_read_capacity_10_parameter parameter; 418 status_t result = usb_disk_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0, 419 ¶meter, &dataLength, true); 420 if (result != B_OK) { 421 TRACE_ALWAYS("failed to update capacity\n"); 422 lun->media_present = false; 423 lun->media_changed = false; 424 usb_disk_reset_capacity(lun); 425 return result; 426 } 427 428 lun->media_present = true; 429 lun->media_changed = false; 430 lun->block_size = ntohl(parameter.logical_block_length); 431 lun->block_count = ntohl(parameter.last_logical_block_address) + 1; 432 return B_OK; 433 } 434 435 436 status_t 437 usb_disk_synchronize(device_lun *lun, bool force) 438 { 439 if (lun->device->sync_support == 0) { 440 // this device repeatedly reported an illegal request when syncing 441 // it obviously does really not support this command... 442 return B_UNSUPPORTED; 443 } 444 445 if (lun->should_sync || force) { 446 status_t result = usb_disk_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 447 10, 0, 0, NULL, NULL, false); 448 lun->should_sync = false; 449 450 if (result == B_OK) 451 lun->device->sync_support = SYNC_SUPPORT_RELOAD; 452 else if (result == B_DEV_INVALID_IOCTL) 453 lun->device->sync_support--; 454 return result; 455 } 456 457 return B_OK; 458 } 459 460 461 // 462 //#pragma mark - Device Attach/Detach Notifications and Callback 463 // 464 465 466 static void 467 usb_disk_callback(void *cookie, status_t status, void *data, 468 size_t actualLength) 469 { 470 //TRACE("callback()\n"); 471 disk_device *device = (disk_device *)cookie; 472 device->status = status; 473 device->actual_length = actualLength; 474 release_sem(device->notify); 475 } 476 477 478 static status_t 479 usb_disk_device_added(usb_device newDevice, void **cookie) 480 { 481 TRACE("device_added(0x%08lx)\n", newDevice); 482 disk_device *device = (disk_device *)malloc(sizeof(disk_device)); 483 device->device = newDevice; 484 device->removed = false; 485 device->open_count = 0; 486 device->interface = 0xff; 487 device->current_tag = 0; 488 device->sync_support = SYNC_SUPPORT_RELOAD; 489 device->luns = NULL; 490 491 // scan through the interfaces to find our bulk-only data interface 492 const usb_configuration_info *configuration = gUSBModule->get_configuration(newDevice); 493 if (configuration == NULL) { 494 free(device); 495 return B_ERROR; 496 } 497 498 for (size_t i = 0; i < configuration->interface_count; i++) { 499 usb_interface_info *interface = configuration->interface[i].active; 500 if (interface == NULL) 501 continue; 502 503 if (interface->descr->interface_class == 0x08 /* mass storage */ 504 && interface->descr->interface_subclass == 0x06 /* SCSI */ 505 && interface->descr->interface_protocol == 0x50 /* bulk-only */) { 506 507 bool hasIn = false; 508 bool hasOut = false; 509 for (size_t j = 0; j < interface->endpoint_count; j++) { 510 usb_endpoint_info *endpoint = &interface->endpoint[j]; 511 if (endpoint == NULL 512 || endpoint->descr->attributes != USB_ENDPOINT_ATTR_BULK) 513 continue; 514 515 if (!hasIn && (endpoint->descr->endpoint_address 516 & USB_ENDPOINT_ADDR_DIR_IN)) { 517 device->bulk_in = endpoint->handle; 518 hasIn = true; 519 } else if (!hasOut && (endpoint->descr->endpoint_address 520 & USB_ENDPOINT_ADDR_DIR_IN) == 0) { 521 device->bulk_out = endpoint->handle; 522 hasOut = true; 523 } 524 525 if (hasIn && hasOut) 526 break; 527 } 528 529 if (!(hasIn && hasOut)) 530 continue; 531 532 device->interface = interface->descr->interface_number; 533 break; 534 } 535 } 536 537 if (device->interface == 0xff) { 538 TRACE_ALWAYS("no valid bulk-only interface found\n"); 539 free(device); 540 return B_ERROR; 541 } 542 543 status_t result = benaphore_init(&device->lock, "usb_disk device lock"); 544 if (result < B_OK) { 545 free(device); 546 return result; 547 } 548 549 device->notify = create_sem(0, "usb_disk callback notify"); 550 if (device->notify < B_OK) { 551 benaphore_destroy(&device->lock); 552 free(device); 553 return device->notify; 554 } 555 556 device->lun_count = usb_disk_get_max_lun(device) + 1; 557 device->luns = (device_lun **)malloc(device->lun_count 558 * sizeof(device_lun *)); 559 for (uint8 i = 0; i < device->lun_count; i++) 560 device->luns[i] = NULL; 561 562 TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count); 563 for (uint8 i = 0; i < device->lun_count; i++) { 564 // create the individual luns present on this device 565 device_lun *lun = (device_lun *)malloc(sizeof(device_lun)); 566 if (lun == NULL) { 567 result = B_NO_MEMORY; 568 break; 569 } 570 571 device->luns[i] = lun; 572 lun->device = device; 573 lun->logical_unit_number = i; 574 lun->should_sync = false; 575 lun->media_present = true; 576 lun->media_changed = true; 577 usb_disk_reset_capacity(lun); 578 579 // initialize this lun 580 result = usb_disk_inquiry(lun); 581 for (uint32 tries = 0; tries < 3; tries++) { 582 status_t ready = usb_disk_test_unit_ready(lun); 583 if (ready == B_OK || ready == B_DEV_NO_MEDIA) 584 break; 585 snooze(10000); 586 } 587 588 if (result != B_OK) 589 break; 590 } 591 592 if (result != B_OK) { 593 TRACE_ALWAYS("failed to initialize logical units\n"); 594 usb_disk_free_device_and_luns(device); 595 return result; 596 } 597 598 benaphore_lock(&gDeviceListLock); 599 device->link = (void *)gDeviceList; 600 gDeviceList = device; 601 uint32 deviceNumber = gDeviceCount++; 602 gLunCount += device->lun_count; 603 for (uint8 i = 0; i < device->lun_count; i++) 604 sprintf(device->luns[i]->name, DEVICE_NAME, deviceNumber, i); 605 benaphore_unlock(&gDeviceListLock); 606 607 TRACE("new device: 0x%08lx\n", (uint32)device); 608 *cookie = (void *)device; 609 return B_OK; 610 } 611 612 613 static status_t 614 usb_disk_device_removed(void *cookie) 615 { 616 TRACE("device_removed(0x%08lx)\n", (uint32)cookie); 617 disk_device *device = (disk_device *)cookie; 618 619 benaphore_lock(&gDeviceListLock); 620 if (gDeviceList == device) { 621 gDeviceList = (disk_device *)device->link; 622 } else { 623 disk_device *element = gDeviceList; 624 while (element) { 625 if (element->link == device) { 626 element->link = device->link; 627 break; 628 } 629 630 element = (disk_device *)element->link; 631 } 632 } 633 gLunCount -= device->lun_count; 634 gDeviceCount--; 635 636 benaphore_lock(&device->lock); 637 device->removed = true; 638 benaphore_unlock(&device->lock); 639 if (device->open_count == 0) 640 usb_disk_free_device_and_luns(device); 641 642 benaphore_unlock(&gDeviceListLock); 643 return B_OK; 644 } 645 646 647 // 648 //#pragma mark - Partial Buffer Functions 649 // 650 651 652 static bool 653 usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length, 654 uint32 &blockPosition, uint16 &blockCount) 655 { 656 blockPosition = (uint32)(position / lun->block_size); 657 if ((off_t)blockPosition * lun->block_size != position) 658 return true; 659 660 blockCount = (uint16)(length / lun->block_size); 661 if ((size_t)blockCount * lun->block_size != length) 662 return true; 663 664 return false; 665 } 666 667 668 static status_t 669 usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, 670 void *buffer, size_t *length) 671 { 672 status_t result = usb_disk_operation(lun, SCSI_READ_10, 10, blockPosition, 673 blockCount, buffer, length, true); 674 return result; 675 } 676 677 678 static status_t 679 usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, 680 void *buffer, size_t *length) 681 { 682 status_t result = usb_disk_operation(lun, SCSI_WRITE_10, 10, blockPosition, 683 blockCount, buffer, length, false); 684 if (result == B_OK) 685 lun->should_sync = true; 686 return result; 687 } 688 689 690 static status_t 691 usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length, 692 void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition, 693 uint16 &blockCount) 694 { 695 blockPosition = (uint32)(position / lun->block_size); 696 blockCount = (uint16)((uint32)((position + length + lun->block_size - 1) 697 / lun->block_size) - blockPosition); 698 size_t blockLength = blockCount * lun->block_size; 699 blockBuffer = malloc(blockLength); 700 if (blockBuffer == NULL) { 701 TRACE_ALWAYS("no memory to allocate partial buffer\n"); 702 return B_NO_MEMORY; 703 } 704 705 status_t result = usb_disk_block_read(lun, blockPosition, blockCount, 706 blockBuffer, &blockLength); 707 if (result != B_OK) { 708 TRACE_ALWAYS("block read failed when filling partial buffer\n"); 709 free(blockBuffer); 710 return result; 711 } 712 713 off_t offset = position - (blockPosition * lun->block_size); 714 partialBuffer = (uint8 *)blockBuffer + offset; 715 return B_OK; 716 } 717 718 719 // 720 //#pragma mark - Driver Hooks 721 // 722 723 724 static status_t 725 usb_disk_open(const char *name, uint32 flags, void **cookie) 726 { 727 TRACE("open(%s)\n", name); 728 if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0) 729 return B_NAME_NOT_FOUND; 730 731 int32 lastPart = 0; 732 for (int32 i = strlen(name) - 1; i >= 0; i--) { 733 if (name[i] == '/') { 734 lastPart = i; 735 break; 736 } 737 } 738 739 char rawName[32]; 740 strlcpy(rawName, name, lastPart + 2); 741 strcat(rawName, "raw"); 742 TRACE("opening raw device %s for %s\n", rawName, name); 743 744 benaphore_lock(&gDeviceListLock); 745 disk_device *device = gDeviceList; 746 while (device) { 747 for (uint8 i = 0; i < device->lun_count; i++) { 748 device_lun *lun = device->luns[i]; 749 if (strncmp(rawName, lun->name, 32) == 0) { 750 // found the matching device/lun 751 if (device->removed) 752 return B_ERROR; 753 754 device->open_count++; 755 *cookie = lun; 756 benaphore_unlock(&gDeviceListLock); 757 return B_OK; 758 } 759 } 760 761 device = (disk_device *)device->link; 762 } 763 764 benaphore_unlock(&gDeviceListLock); 765 return B_NAME_NOT_FOUND; 766 } 767 768 769 static status_t 770 usb_disk_close(void *cookie) 771 { 772 TRACE("close()\n"); 773 device_lun *lun = (device_lun *)cookie; 774 usb_disk_synchronize(lun, false); 775 return B_OK; 776 } 777 778 779 static status_t 780 usb_disk_free(void *cookie) 781 { 782 TRACE("free()\n"); 783 benaphore_lock(&gDeviceListLock); 784 785 device_lun *lun = (device_lun *)cookie; 786 disk_device *device = lun->device; 787 device->open_count--; 788 if (device->removed && device->open_count == 0) { 789 // we can simply free the device here as it has been removed from the 790 // device list in the device removed notification hook 791 usb_disk_free_device_and_luns(device); 792 } 793 794 benaphore_unlock(&gDeviceListLock); 795 return B_OK; 796 } 797 798 799 static status_t 800 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) 801 { 802 device_lun *lun = (device_lun *)cookie; 803 disk_device *device = lun->device; 804 benaphore_lock(&device->lock); 805 if (device->removed) { 806 benaphore_unlock(&device->lock); 807 return B_DEV_NOT_READY; 808 } 809 810 status_t result = B_DEV_INVALID_IOCTL; 811 switch (op) { 812 case B_GET_MEDIA_STATUS: { 813 *(status_t *)buffer = usb_disk_test_unit_ready(lun); 814 TRACE("B_GET_MEDIA_STATUS: 0x%08lx\n", *(status_t *)buffer); 815 result = B_OK; 816 break; 817 } 818 819 case B_GET_GEOMETRY: { 820 if (lun->media_changed) { 821 result = usb_disk_update_capacity(lun); 822 if (result != B_OK) 823 break; 824 } 825 826 device_geometry *geometry = (device_geometry *)buffer; 827 geometry->bytes_per_sector = lun->block_size; 828 geometry->cylinder_count = lun->block_count; 829 geometry->sectors_per_track = geometry->head_count = 1; 830 geometry->device_type = lun->device_type; 831 geometry->removable = lun->removable; 832 geometry->read_only = (lun->device_type == B_CD); 833 geometry->write_once = (lun->device_type == B_WORM); 834 TRACE("B_GET_GEOMETRY: %ld sectors at %ld bytes per sector\n", 835 geometry->cylinder_count, geometry->bytes_per_sector); 836 result = B_OK; 837 break; 838 } 839 840 case B_FLUSH_DRIVE_CACHE: 841 TRACE("B_FLUSH_DRIVE_CACHE\n"); 842 usb_disk_synchronize(lun, true); 843 break; 844 845 default: 846 TRACE_ALWAYS("unhandled ioctl %ld\n", op); 847 break; 848 } 849 850 benaphore_unlock(&device->lock); 851 return result; 852 } 853 854 855 static status_t 856 usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) 857 { 858 if (buffer == NULL || length == NULL) 859 return B_BAD_VALUE; 860 861 TRACE("read(%lld, %ld)\n", position, *length); 862 device_lun *lun = (device_lun *)cookie; 863 disk_device *device = lun->device; 864 benaphore_lock(&device->lock); 865 if (device->removed) { 866 *length = 0; 867 benaphore_unlock(&device->lock); 868 return B_DEV_NOT_READY; 869 } 870 871 status_t result = B_ERROR; 872 uint32 blockPosition = 0; 873 uint16 blockCount = 0; 874 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length, 875 blockPosition, blockCount); 876 if (needsPartial) { 877 void *partialBuffer = NULL; 878 void *blockBuffer = NULL; 879 result = usb_disk_prepare_partial_buffer(lun, position, *length, 880 partialBuffer, blockBuffer, blockPosition, blockCount); 881 if (result == B_OK) { 882 memcpy(buffer, partialBuffer, *length); 883 free(blockBuffer); 884 } 885 } else { 886 result = usb_disk_block_read(lun, blockPosition, blockCount, buffer, 887 length); 888 } 889 890 benaphore_unlock(&device->lock); 891 if (result == B_OK) { 892 TRACE("read successful with %ld bytes\n", *length); 893 return B_OK; 894 } 895 896 *length = 0; 897 TRACE_ALWAYS("read fails with 0x%08lx\n", result); 898 return result; 899 } 900 901 902 static status_t 903 usb_disk_write(void *cookie, off_t position, const void *buffer, 904 size_t *length) 905 { 906 if (buffer == NULL || length == NULL) 907 return B_BAD_VALUE; 908 909 TRACE("write(%lld, %ld)\n", position, *length); 910 device_lun *lun = (device_lun *)cookie; 911 disk_device *device = lun->device; 912 benaphore_lock(&device->lock); 913 if (device->removed) { 914 *length = 0; 915 benaphore_unlock(&device->lock); 916 return B_DEV_NOT_READY; 917 } 918 919 status_t result = B_ERROR; 920 uint32 blockPosition = 0; 921 uint16 blockCount = 0; 922 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, 923 *length, blockPosition, blockCount); 924 if (needsPartial) { 925 void *partialBuffer = NULL; 926 void *blockBuffer = NULL; 927 result = usb_disk_prepare_partial_buffer(lun, position, *length, 928 partialBuffer, blockBuffer, blockPosition, blockCount); 929 if (result == B_OK) { 930 memcpy(partialBuffer, buffer, *length); 931 size_t blockLength = blockCount * lun->block_size; 932 result = usb_disk_block_write(lun, blockPosition, blockCount, 933 blockBuffer, &blockLength); 934 free(blockBuffer); 935 } 936 } else { 937 result = usb_disk_block_write(lun, blockPosition, blockCount, 938 (void *)buffer, length); 939 } 940 941 benaphore_unlock(&device->lock); 942 if (result == B_OK) { 943 TRACE("write successful with %ld bytes\n", *length); 944 return B_OK; 945 } 946 947 *length = 0; 948 TRACE_ALWAYS("write fails with 0x%08lx\n", result); 949 return result; 950 } 951 952 953 // 954 //#pragma mark - Driver Entry Points 955 // 956 957 958 status_t 959 init_hardware() 960 { 961 TRACE("init_hardware()\n"); 962 return B_OK; 963 } 964 965 966 status_t 967 init_driver() 968 { 969 TRACE("init_driver()\n"); 970 static usb_notify_hooks notifyHooks = { 971 &usb_disk_device_added, 972 &usb_disk_device_removed 973 }; 974 975 static usb_support_descriptor supportedDevices = { 976 0x08 /* mass storage */, 0x06 /* SCSI */, 0x50 /* bulk only */, 0, 0 977 }; 978 979 gDeviceList = NULL; 980 gDeviceCount = 0; 981 gLunCount = 0; 982 status_t result = benaphore_init(&gDeviceListLock, "usb_disk device list lock"); 983 if (result < B_OK) { 984 TRACE("failed to create device list lock\n"); 985 return result; 986 } 987 988 TRACE("trying module %s\n", B_USB_MODULE_NAME); 989 result = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule); 990 if (result < B_OK) { 991 TRACE_ALWAYS("getting module failed 0x%08lx\n", result); 992 benaphore_destroy(&gDeviceListLock); 993 return result; 994 } 995 996 gUSBModule->register_driver(DRIVER_NAME, &supportedDevices, 1, NULL); 997 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 998 return B_OK; 999 } 1000 1001 1002 void 1003 uninit_driver() 1004 { 1005 TRACE("uninit_driver()\n"); 1006 gUSBModule->uninstall_notify(DRIVER_NAME); 1007 benaphore_lock(&gDeviceListLock); 1008 1009 if (gDeviceNames) { 1010 for (int32 i = 0; gDeviceNames[i]; i++) 1011 free(gDeviceNames[i]); 1012 free(gDeviceNames); 1013 gDeviceNames = NULL; 1014 } 1015 1016 benaphore_destroy(&gDeviceListLock); 1017 put_module(B_USB_MODULE_NAME); 1018 } 1019 1020 1021 const char ** 1022 publish_devices() 1023 { 1024 TRACE("publish_devices()\n"); 1025 if (gDeviceNames) { 1026 for (int32 i = 0; gDeviceNames[i]; i++) 1027 free(gDeviceNames[i]); 1028 free(gDeviceNames); 1029 gDeviceNames = NULL; 1030 } 1031 1032 gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1)); 1033 if (gDeviceNames == NULL) 1034 return NULL; 1035 1036 int32 index = 0; 1037 benaphore_lock(&gDeviceListLock); 1038 disk_device *device = gDeviceList; 1039 while (device) { 1040 for (uint8 i = 0; i < device->lun_count; i++) 1041 gDeviceNames[index++] = strdup(device->luns[i]->name); 1042 1043 device = (disk_device *)device->link; 1044 } 1045 1046 gDeviceNames[index++] = NULL; 1047 benaphore_unlock(&gDeviceListLock); 1048 return (const char **)gDeviceNames; 1049 } 1050 1051 1052 device_hooks * 1053 find_device(const char *name) 1054 { 1055 TRACE("find_device()\n"); 1056 static device_hooks hooks = { 1057 &usb_disk_open, 1058 &usb_disk_close, 1059 &usb_disk_free, 1060 &usb_disk_ioctl, 1061 &usb_disk_read, 1062 &usb_disk_write, 1063 NULL, 1064 NULL, 1065 NULL, 1066 NULL 1067 }; 1068 1069 return &hooks; 1070 } 1071