1/* 2 * Copyright 2008-2009, 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_floppy" 20#define DEVICE_NAME_BASE "disk/ufi/" 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("\x1B[35m"DRIVER_NAME"\x1B[0m: "x) 27#define TRACE_ALWAYS(x...) dprintf("\x1B[35m"DRIVER_NAME"\x1B[0m: "x) 28#else 29#define TRACE(x...) /* nothing */ 30#define TRACE_ALWAYS(x...) dprintf("\x1B[35m"DRIVER_NAME"\x1B[0m: "x) 31#endif 32 33 34int32 api_version = B_CUR_DRIVER_API_VERSION; 35static usb_module_info *gUSBModule = NULL; 36static disk_device *gDeviceList = NULL; 37static uint32 gDeviceCount = 0; 38static uint32 gLunCount = 0; 39static mutex gDeviceListLock; 40static char **gDeviceNames = NULL; 41 42static uint8 kDeviceIcon[] = { 43 0x6e, 0x63, 0x69, 0x66, 0x0d, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 44 0x00, 0x6a, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, 0xeb, 0x7a, 45 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, 0x75, 0xed, 46 0x00, 0x7a, 0xff, 0x4b, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, 47 0xeb, 0x7a, 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, 48 0x75, 0xed, 0x00, 0x8a, 0xff, 0x2c, 0x05, 0x7d, 0x02, 0x00, 0x16, 0x02, 49 0x39, 0xc6, 0x30, 0x36, 0xa8, 0x1b, 0xb9, 0x51, 0xe6, 0x3c, 0x5b, 0xb3, 50 0x4b, 0x4d, 0xa8, 0x4a, 0x1a, 0xa1, 0x00, 0x3a, 0xff, 0x5d, 0x02, 0x00, 51 0x16, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, 0x07, 0xb9, 52 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x01, 0x75, 0xfe, 0xc4, 53 0x02, 0x00, 0x16, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, 54 0x07, 0xb9, 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x00, 0x5c, 55 0xfe, 0x9b, 0x02, 0x00, 0x16, 0x05, 0x36, 0xef, 0x60, 0x38, 0xe2, 0xe5, 56 0xbd, 0x22, 0x41, 0x3b, 0x2f, 0xce, 0x4a, 0x0e, 0x78, 0x4a, 0x5a, 0x6c, 57 0x00, 0xb8, 0x38, 0xe6, 0x77, 0xb8, 0xbd, 0xd2, 0xff, 0x93, 0x02, 0x00, 58 0x16, 0x05, 0x34, 0x0a, 0x8f, 0x38, 0xd2, 0xa2, 0xba, 0xb4, 0xc5, 0x35, 59 0xe9, 0xec, 0x49, 0xfd, 0x24, 0x4a, 0x64, 0x62, 0x00, 0xe1, 0x38, 0xff, 60 0x75, 0xd7, 0xba, 0xf3, 0xfd, 0xd0, 0x02, 0x00, 0x16, 0x02, 0x36, 0x67, 61 0xbe, 0x39, 0xdd, 0xbc, 0xbe, 0x50, 0x04, 0x3a, 0xe0, 0x9f, 0x4b, 0x85, 62 0x01, 0x49, 0x2a, 0x3f, 0x00, 0xff, 0xff, 0xd8, 0x03, 0x38, 0x6d, 0xbe, 63 0x02, 0x00, 0x16, 0x02, 0x3c, 0x40, 0xef, 0x3b, 0x82, 0xd1, 0xba, 0xeb, 64 0x42, 0x3b, 0xbf, 0x4d, 0x4a, 0xa7, 0xce, 0x49, 0x5d, 0xc1, 0xff, 0x01, 65 0x00, 0x4a, 0x12, 0x0a, 0x05, 0x44, 0x5a, 0x44, 0x40, 0x5e, 0x40, 0x5f, 66 0x45, 0x49, 0x5a, 0x0a, 0x06, 0x45, 0x58, 0x5c, 0x42, 0x5c, 0x40, 0x3d, 67 0x34, 0xb5, 0x6b, 0xc2, 0x2e, 0xb5, 0x63, 0xc3, 0xbb, 0x0a, 0x04, 0x44, 68 0x58, 0x26, 0x4a, 0x26, 0x47, 0x44, 0x54, 0x0a, 0x04, 0x44, 0x59, 0x5c, 69 0x42, 0x5c, 0x3e, 0x44, 0x54, 0x0a, 0x05, 0x44, 0x56, 0x5c, 0x40, 0x3d, 70 0x34, 0xb5, 0x6b, 0xc2, 0x2e, 0xb5, 0x43, 0xc3, 0x3b, 0x0a, 0x04, 0x2a, 71 0x4c, 0x3f, 0x56, 0x3f, 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x2a, 0x4b, 0x39, 72 0x52, 0x39, 0x50, 0x2a, 0x4a, 0x0a, 0x04, 0x31, 0x42, 0x45, 0x4c, 0x3f, 73 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x3f, 0x49, 0x38, 0x50, 0x2a, 0x4a, 0x31, 74 0x43, 0x0a, 0x04, 0x3f, 0x36, 0x57, 0x3e, 0x49, 0x4b, 0x32, 0x40, 0x08, 75 0x02, 0x3c, 0x3b, 0x4d, 0x43, 0x00, 0x02, 0x3b, 0x3b, 0x31, 0x36, 0x43, 76 0x3f, 0x48, 0x3d, 0x3f, 0x36, 0xc4, 0x82, 0xbf, 0xc7, 0x00, 0x02, 0x3e, 77 0x3c, 0xbc, 0x58, 0xbd, 0x93, 0x47, 0x3e, 0x45, 0x44, 0x3d, 0x43, 0x4d, 78 0x45, 0x02, 0x04, 0x39, 0x3b, 0x39, 0x3d, 0x39, 0x39, 0x3c, 0x38, 0x3b, 79 0x38, 0x3e, 0x38, 0x3e, 0x3a, 0x3f, 0x3a, 0x41, 0x37, 0x3c, 0x3d, 0x3c, 80 0x42, 0x3c, 0x40, 0x02, 0x04, 0x46, 0x3c, 0x46, 0x3e, 0x46, 0x3a, 0x48, 81 0x3a, 0x46, 0x3a, 0x4a, 0x3a, 0x4a, 0x3c, 0x4a, 0x3a, 0x4a, 0x3e, 0x48, 82 0x3e, 0x4a, 0x3e, 0x46, 0x3e, 0x0a, 0x04, 0x45, 0x42, 0x42, 0x45, 0x45, 83 0x47, 0x48, 0x44, 0x0a, 0x03, 0x4e, 0x43, 0x4d, 0x3f, 0x48, 0x44, 0x0a, 84 0x04, 0x32, 0x4b, 0x36, 0x48, 0x32, 0x46, 0x2e, 0x4a, 0x0d, 0x0a, 0x01, 85 0x01, 0x00, 0x20, 0x1e, 0x20, 0x0a, 0x00, 0x01, 0x01, 0x30, 0x1e, 0x20, 86 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x02, 0x01, 0x02, 0x20, 0x1e, 0x20, 87 0x0a, 0x05, 0x01, 0x03, 0x20, 0x1e, 0x20, 0x0a, 0x06, 0x01, 0x04, 0x20, 88 0x1e, 0x20, 0x0a, 0x03, 0x01, 0x05, 0x20, 0x1e, 0x20, 0x0a, 0x07, 0x01, 89 0x07, 0x20, 0x1e, 0x20, 0x0a, 0x08, 0x01, 0x06, 0x20, 0x1e, 0x20, 0x0a, 90 0x09, 0x01, 0x08, 0x20, 0x1e, 0x20, 0x0a, 0x0a, 0x01, 0x09, 0x20, 0x1e, 91 0x20, 0x0a, 0x0c, 0x03, 0x0a, 0x0b, 0x0c, 0x1a, 0x40, 0x1d, 0x05, 0x00, 92 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9d, 0xc9, 0xc2, 0x91, 0x98, 0x43, 93 0x6d, 0xc2, 0x20, 0xff, 0x01, 0x17, 0x81, 0x00, 0x04, 0x0a, 0x0c, 0x04, 94 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x3f, 0xff, 0xbd, 0x34, 0xaf, 0xbc, 0xb4, 95 0xe0, 0x2c, 0x3f, 0xbc, 0x62, 0x3e, 0x74, 0x62, 0x41, 0xfe, 0xe7, 0x20, 96 0xff, 0x0a, 0x02, 0x01, 0x11, 0x20, 0x1e, 0x20 97}; 98 99 100// 101//#pragma mark - Forward Declarations 102// 103 104 105static void usb_disk_callback(void *cookie, status_t status, void *data, 106 size_t actualLength); 107 108status_t usb_disk_mass_storage_reset(disk_device *device); 109uint8 usb_disk_get_max_lun(disk_device *device); 110void usb_disk_reset_recovery(disk_device *device); 111status_t usb_disk_transfer_data(disk_device *device, bool directionIn, 112 void *data, size_t dataLength); 113status_t usb_disk_receive_csw(disk_device *device, 114 command_status_wrapper *status); 115status_t usb_disk_operation(device_lun *lun, uint8* operation, 116 void *data, uint32 *dataLength, 117 bool directionIn); 118 119status_t usb_disk_send_diagnostic(device_lun *lun); 120status_t usb_disk_request_sense(device_lun *lun); 121status_t usb_disk_mode_sense(device_lun *lun); 122status_t usb_disk_test_unit_ready(device_lun *lun); 123status_t usb_disk_inquiry(device_lun *lun); 124status_t usb_disk_reset_capacity(device_lun *lun); 125status_t usb_disk_update_capacity(device_lun *lun); 126status_t usb_disk_synchronize(device_lun *lun, bool force); 127 128 129// 130//#pragma mark - Device Allocation Helper Functions 131// 132 133 134void 135usb_disk_free_device_and_luns(disk_device *device) 136{ 137 mutex_lock(&device->lock); 138 mutex_destroy(&device->lock); 139 delete_sem(device->notify); 140 delete_sem(device->interruptLock); 141 for (uint8 i = 0; i < device->lun_count; i++) 142 free(device->luns[i]); 143 free(device->luns); 144 free(device); 145} 146 147 148// 149//#pragma mark - Bulk-only Mass Storage Functions 150// 151 152 153void 154usb_disk_reset_recovery(disk_device *device) 155{ 156 gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); 157 gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 158 gUSBModule->clear_feature(device->interrupt, USB_FEATURE_ENDPOINT_HALT); 159} 160 161 162status_t 163usb_disk_transfer_data(disk_device *device, bool directionIn, void *data, 164 size_t dataLength) 165{ 166 status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in 167 : device->bulk_out, data, dataLength, usb_disk_callback, device); 168 if (result != B_OK) { 169 TRACE_ALWAYS("failed to queue data transfer\n"); 170 return result; 171 } 172 173 do { 174 result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 175 10 * 1000 * 1000); 176 if (result == B_TIMED_OUT) { 177 // Cancel the transfer and collect the sem that should now be 178 // released through the callback on cancel. Handling of device 179 // reset is done in usb_disk_operation() when it detects that 180 // the transfer failed. 181 gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in 182 : device->bulk_out); 183 acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0); 184 } 185 } while (result == B_INTERRUPTED); 186 187 if (result != B_OK) { 188 TRACE_ALWAYS("acquire_sem failed while waiting for data transfer\n"); 189 return result; 190 } 191 192 return B_OK; 193} 194 195 196void 197usb_disk_interrupt(void* cookie, int32 status, void* data, uint32 length) 198{ 199 disk_device* dev = (disk_device*)cookie; 200 // We release the lock even if the interrupt is invalid. This way there 201 // is at least a chance for the driver to terminate properly. 202 release_sem(dev->interruptLock); 203 204 if (length != 2) { 205 TRACE_ALWAYS("interrupt of length %ld! (expected 2)\n", length); 206 // In this case we do not reschedule the interrupt. This means the 207 // driver will be locked. The interrupt should perhaps be scheduled 208 // when starting a transfer instead. But getting there means something 209 // is really broken, so... 210 return; 211 } 212 213 // Reschedule the interrupt for next time 214 gUSBModule->queue_interrupt(dev->interrupt, dev->interruptBuffer, 2, 215 usb_disk_interrupt, cookie); 216} 217 218 219status_t 220usb_disk_receive_csw(disk_device *device, command_status_wrapper *status) 221{ 222 TRACE("Waiting for result...\n"); 223 gUSBModule->queue_interrupt(device->interrupt, 224 device->interruptBuffer, 2, usb_disk_interrupt, device); 225 226 acquire_sem(device->interruptLock); 227 228 status->status = device->interruptBuffer[0]; 229 status->misc = device->interruptBuffer[1]; 230 231 return B_OK; 232} 233 234 235status_t 236usb_disk_operation(device_lun *lun, uint8* operation, 237 void *data, uint32 *dataLength, bool directionIn) 238{ 239 // TODO: remove transferLength 240 TRACE("operation: lun: %u; op: 0x%x; data: %p; dlen: %p (%lu); in: %c\n", 241 lun->logical_unit_number, operation[0], data, dataLength, 242 dataLength ? *dataLength : 0, directionIn ? 'y' : 'n'); 243 244 disk_device* device = lun->device; 245 246 // Step 1 : send the SCSI operation as a class specific request 247 size_t actualLength = 12; 248 status_t result = gUSBModule->send_request(device->device, 249 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, 0 /*request*/, 0/*value*/, 250 device->interface/*index*/, 12, operation, &actualLength); 251 252 if (result != B_OK || actualLength != 12) { 253 TRACE("Command stage: wrote %ld bytes (error: %s)\n", 254 actualLength, strerror(result)); 255 256 // There was an error, we have to do a request sense to reset the device 257 if (operation[0] != SCSI_REQUEST_SENSE_6) { 258 usb_disk_request_sense(lun); 259 } 260 return result; 261 } 262 263 // Step 2 : data phase : send or receive data 264 size_t transferedData = 0; 265 if (data != NULL && dataLength != NULL && *dataLength > 0) { 266 // we have data to transfer in a data stage 267 result = usb_disk_transfer_data(device, directionIn, data, *dataLength); 268 if (result != B_OK) { 269 TRACE("Error %s in data phase\n", strerror(result)); 270 return result; 271 } 272 273 transferedData = device->actual_length; 274 if (device->status != B_OK || transferedData != *dataLength) { 275 // sending or receiving of the data failed 276 if (device->status == B_DEV_STALLED) { 277 TRACE("stall while transfering data\n"); 278 gUSBModule->clear_feature(directionIn ? device->bulk_in 279 : device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 280 } else { 281 TRACE_ALWAYS("sending or receiving of the data failed\n"); 282 usb_disk_reset_recovery(device); 283 return B_ERROR; 284 } 285 } 286 } 287 288 // step 3 : wait for the device to send the interrupt ACK 289 if (operation[0] != SCSI_REQUEST_SENSE_6) { 290 command_status_wrapper status; 291 result = usb_disk_receive_csw(device, &status); 292 if (result != B_OK) { 293 // in case of a stall or error clear the stall and try again 294 TRACE("Error receiving interrupt: %s. Retrying...\n", strerror(result)); 295 gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); 296 result = usb_disk_receive_csw(device, &status); 297 } 298 299 if (result != B_OK) { 300 TRACE_ALWAYS("receiving the command status interrupt failed\n"); 301 usb_disk_reset_recovery(device); 302 return result; 303 } 304 305 // wait for the device to finish the operation. 306 result = usb_disk_request_sense(lun); 307 } 308 return result; 309} 310 311 312// 313//#pragma mark - Helper/Convenience Functions 314// 315 316 317status_t 318usb_disk_send_diagnostic(device_lun *lun) 319{ 320 uint8 commandBlock[12]; 321 memset(commandBlock, 0, sizeof(commandBlock)); 322 323 commandBlock[0] = SCSI_SEND_DIAGNOSTIC; 324 commandBlock[1] = (lun->logical_unit_number << 5) | 4; 325 326 status_t result = usb_disk_operation(lun, commandBlock, NULL, 327 NULL, false); 328 329 int retry = 100; 330 while(result == B_DEV_NO_MEDIA && retry > 0) { 331 snooze(10000); 332 result = usb_disk_request_sense(lun); 333 retry--; 334 } 335 336 if (result != B_OK) 337 TRACE("Send Diagnostic failed: %s\n", strerror(result)); 338 return result; 339} 340 341 342status_t 343usb_disk_request_sense(device_lun *lun) 344{ 345 uint32 dataLength = sizeof(scsi_request_sense_6_parameter); 346 uint8 commandBlock[12]; 347 memset(commandBlock, 0, sizeof(commandBlock)); 348 349 commandBlock[0] = SCSI_REQUEST_SENSE_6; 350 commandBlock[1] = lun->logical_unit_number << 5; 351 commandBlock[2] = 0; // page code 352 commandBlock[4] = dataLength; 353 354 scsi_request_sense_6_parameter parameter; 355 status_t result = usb_disk_operation(lun, commandBlock, ¶meter, 356 &dataLength, true); 357 if (result != B_OK) { 358 TRACE_ALWAYS("getting request sense data failed\n"); 359 return result; 360 } 361 362 if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY 363 && parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) { 364 TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: 0x%02x;\n", 365 parameter.sense_key, parameter.additional_sense_code, 366 parameter.additional_sense_code_qualifier); 367 } 368 369 switch (parameter.sense_key) { 370 case SCSI_SENSE_KEY_NO_SENSE: 371 case SCSI_SENSE_KEY_RECOVERED_ERROR: 372 return B_OK; 373 374 case SCSI_SENSE_KEY_HARDWARE_ERROR: 375 case SCSI_SENSE_KEY_MEDIUM_ERROR: 376 TRACE_ALWAYS("request_sense: media or hardware error\n"); 377 return B_DEV_UNREADABLE; 378 379 case SCSI_SENSE_KEY_ILLEGAL_REQUEST: 380 TRACE_ALWAYS("request_sense: illegal request\n"); 381 return B_DEV_INVALID_IOCTL; 382 383 case SCSI_SENSE_KEY_UNIT_ATTENTION: 384 if (parameter.additional_sense_code != SCSI_ASC_MEDIUM_NOT_PRESENT) { 385 TRACE_ALWAYS("request_sense: media changed\n"); 386 lun->media_changed = true; 387 lun->media_present = true; 388 return B_DEV_MEDIA_CHANGED; 389 } 390 // fall through 391 392 case SCSI_SENSE_KEY_NOT_READY: 393 TRACE("request_sense: device not ready (asc 0x%02x ascq 0x%02x)\n", 394 parameter.additional_sense_code, 395 parameter.additional_sense_code_qualifier); 396 lun->media_present = false; 397 usb_disk_reset_capacity(lun); 398 return B_DEV_NO_MEDIA; 399 400 case SCSI_SENSE_KEY_DATA_PROTECT: 401 TRACE_ALWAYS("request_sense: write protected\n"); 402 return B_READ_ONLY_DEVICE; 403 404 case SCSI_SENSE_KEY_ABORTED_COMMAND: 405 TRACE_ALWAYS("request_sense: command aborted\n"); 406 return B_CANCELED; 407 } 408 409 return B_ERROR; 410} 411 412 413status_t 414usb_disk_mode_sense(device_lun *lun) 415{ 416 uint32 dataLength = sizeof(scsi_mode_sense_6_parameter); 417 418 uint8 commandBlock[12]; 419 memset(commandBlock, 0, sizeof(commandBlock)); 420 421 commandBlock[0] = SCSI_MODE_SENSE_6; 422 commandBlock[1] = lun->logical_unit_number << 5; 423 commandBlock[2] = 0; // Current values 424 commandBlock[7] = dataLength >> 8; 425 commandBlock[8] = dataLength; 426 427 scsi_mode_sense_6_parameter parameter; 428 status_t result = usb_disk_operation(lun, commandBlock, 429 ¶meter, &dataLength, true); 430 if (result != B_OK) { 431 TRACE_ALWAYS("getting mode sense data failed\n"); 432 return result; 433 } 434 435 lun->write_protected 436 = (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT) != 0; 437 TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no"); 438 return B_OK; 439} 440 441 442status_t 443usb_disk_test_unit_ready(device_lun *lun) 444{ 445 return B_OK; 446 447 uint8 commandBlock[12]; 448 memset(commandBlock, 0, sizeof(commandBlock)); 449 450 commandBlock[0] = SCSI_TEST_UNIT_READY_6; 451 commandBlock[1] = lun->logical_unit_number << 5; 452 453 status_t result = usb_disk_operation(lun, commandBlock, NULL, NULL, false); 454 455 return result; 456} 457 458 459status_t 460usb_disk_inquiry(device_lun *lun) 461{ 462 uint32 dataLength = sizeof(scsi_inquiry_6_parameter); 463 464 uint8 commandBlock[12]; 465 memset(commandBlock, 0, sizeof(commandBlock)); 466 467 commandBlock[0] = SCSI_INQUIRY_6; 468 commandBlock[1] = lun->logical_unit_number << 5; 469 commandBlock[2] = 0; // page code 470 commandBlock[4] = dataLength; 471 472 scsi_inquiry_6_parameter parameter; 473 status_t result = B_ERROR; 474 for (uint32 tries = 0; tries < 3; tries++) { 475 result = usb_disk_operation(lun, commandBlock, ¶meter, &dataLength, 476 true); 477 if (result == B_OK) 478 break; 479 } 480 if (result != B_OK) { 481 TRACE_ALWAYS("getting inquiry data failed\n"); 482 lun->device_type = B_DISK; 483 lun->removable = true; 484 return result; 485 } 486 487 TRACE("peripherial_device_type 0x%02x\n", 488 parameter.peripherial_device_type); 489 TRACE("peripherial_qualifier 0x%02x\n", 490 parameter.peripherial_qualifier); 491 TRACE("removable_medium %s\n", 492 parameter.removable_medium ? "yes" : "no"); 493 TRACE("version 0x%02x\n", parameter.version); 494 TRACE("response_data_format 0x%02x\n", parameter.response_data_format); 495 TRACE_ALWAYS("vendor_identification \"%.8s\"\n", 496 parameter.vendor_identification); 497 TRACE_ALWAYS("product_identification \"%.16s\"\n", 498 parameter.product_identification); 499 TRACE_ALWAYS("product_revision_level \"%.4s\"\n", 500 parameter.product_revision_level); 501 502 memcpy(lun->vendor_name, parameter.vendor_identification, 503 MIN(sizeof(lun->vendor_name), sizeof(parameter.vendor_identification))); 504 memcpy(lun->product_name, parameter.product_identification, 505 MIN(sizeof(lun->product_name), 506 sizeof(parameter.product_identification))); 507 memcpy(lun->product_revision, parameter.product_revision_level, 508 MIN(sizeof(lun->product_revision), 509 sizeof(parameter.product_revision_level))); 510 511 lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ 512 lun->removable = (parameter.removable_medium == 1); 513 return B_OK; 514} 515 516 517status_t 518usb_disk_reset_capacity(device_lun *lun) 519{ 520 lun->block_size = 512; 521 lun->block_count = 0; 522 return B_OK; 523} 524 525 526status_t 527usb_disk_update_capacity(device_lun *lun) 528{ 529 uint32 dataLength = sizeof(scsi_read_capacity_10_parameter); 530 scsi_read_capacity_10_parameter parameter; 531 status_t result = B_ERROR; 532 533 uint8 commandBlock[12]; 534 memset(commandBlock, 0, sizeof(commandBlock)); 535 536 commandBlock[0] = SCSI_READ_CAPACITY_10; 537 commandBlock[1] = lun->logical_unit_number << 5; 538 539 for (int tries = 0; tries < 5; tries++) { 540 result = usb_disk_operation(lun, commandBlock, ¶meter, &dataLength, 541 true); 542 if (result == B_DEV_NO_MEDIA || result == B_TIMED_OUT 543 || result == B_DEV_STALLED) 544 snooze(10000); 545 else 546 break; 547 } 548 549 if (result != B_OK) { 550 TRACE_ALWAYS("failed to update capacity\n"); 551 lun->media_present = false; 552 lun->media_changed = false; 553 usb_disk_reset_capacity(lun); 554 return result; 555 } 556 557 lun->media_present = true; 558 lun->media_changed = false; 559 lun->block_size = ntohl(parameter.logical_block_length); 560 lun->block_count = ntohl(parameter.last_logical_block_address) + 1; 561 return B_OK; 562} 563 564 565status_t 566usb_disk_synchronize(device_lun *lun, bool force) 567{ 568 return B_UNSUPPORTED; 569} 570 571 572// 573//#pragma mark - Device Attach/Detach Notifications and Callback 574// 575 576 577static void 578usb_disk_callback(void *cookie, status_t status, void *data, 579 size_t actualLength) 580{ 581 //TRACE("callback()\n"); 582 disk_device *device = (disk_device *)cookie; 583 device->status = status; 584 device->actual_length = actualLength; 585 release_sem(device->notify); 586} 587 588 589static status_t 590usb_disk_device_added(usb_device newDevice, void **cookie) 591{ 592 TRACE("device_added(0x%08lx)\n", newDevice); 593 disk_device *device = (disk_device *)malloc(sizeof(disk_device)); 594 device->device = newDevice; 595 device->removed = false; 596 device->open_count = 0; 597 device->interface = 0xff; 598 device->current_tag = 0; 599 device->sync_support = SYNC_SUPPORT_RELOAD; 600 device->is_atapi = false; 601 device->luns = NULL; 602 603 // scan through the interfaces to find our data interface 604 const usb_configuration_info *configuration 605 = gUSBModule->get_configuration(newDevice); 606 if (configuration == NULL) { 607 free(device); 608 return B_ERROR; 609 } 610 611 for (size_t i = 0; i < configuration->interface_count; i++) { 612 usb_interface_info *interface = configuration->interface[i].active; 613 if (interface == NULL) 614 continue; 615 616 if (interface->descr->interface_class == 0x08 /* mass storage */ 617 && interface->descr->interface_subclass == 0x04 /* UFI (floppy) */ 618 && interface->descr->interface_protocol == 0x00) { 619 620 bool hasIn = false; 621 bool hasOut = false; 622 bool hasInt = false; 623 for (size_t j = 0; j < interface->endpoint_count; j++) { 624 usb_endpoint_info *endpoint = &interface->endpoint[j]; 625 if (endpoint == NULL) 626 continue; 627 628 if (!hasIn && (endpoint->descr->endpoint_address 629 & USB_ENDPOINT_ADDR_DIR_IN) 630 && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 631 device->bulk_in = endpoint->handle; 632 hasIn = true; 633 } else if (!hasOut && (endpoint->descr->endpoint_address 634 & USB_ENDPOINT_ADDR_DIR_IN) == 0 635 && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 636 device->bulk_out = endpoint->handle; 637 hasOut = true; 638 } else if (!hasInt && (endpoint->descr->endpoint_address 639 & USB_ENDPOINT_ADDR_DIR_IN) 640 && endpoint->descr->attributes 641 == USB_ENDPOINT_ATTR_INTERRUPT) { 642 // TODO:ensure there is only one interrupt endpoint and 643 // stop enumerating 644 device->interrupt = endpoint->handle; 645 hasInt = true; 646 } 647 648 if (hasIn && hasOut && hasInt) 649 break; 650 } 651 652 if (!(hasIn && hasOut && hasInt)) { 653 TRACE("in: %d, out: %d, int: %d\n", hasIn, hasOut, hasInt); 654 continue; 655 } 656 657 device->interface = interface->descr->interface_number; 658 device->is_atapi = interface->descr->interface_subclass != 0x06; 659 break; 660 } 661 } 662 663 if (device->interface == 0xff) { 664 TRACE_ALWAYS("no valid CBI interface found\n"); 665 free(device); 666 return B_ERROR; 667 } 668 669 mutex_init(&device->lock, "usb_disk device lock"); 670 671 status_t result = device->notify = 672 create_sem(0, "usb_disk callback notify"); 673 674 if (result < B_OK) { 675 mutex_destroy(&device->lock); 676 free(device); 677 return result; 678 } 679 680 result = device->interruptLock = create_sem(0, "usb_disk interrupt lock"); 681 if (result < B_OK) { 682 mutex_destroy(&device->lock); 683 free(device); 684 return result; 685 } 686 687 // TODO: handle more than 1 unit 688 device->lun_count = 1; 689 device->luns = (device_lun **)malloc(device->lun_count 690 * sizeof(device_lun *)); 691 for (uint8 i = 0; i < device->lun_count; i++) 692 device->luns[i] = NULL; 693 694 result = B_OK; 695 696 TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count); 697 for (uint8 i = 0; i < device->lun_count; i++) { 698 // create the individual luns present on this device 699 device_lun *lun = (device_lun *)malloc(sizeof(device_lun)); 700 if (lun == NULL) { 701 result = B_NO_MEMORY; 702 break; 703 } 704 705 device->luns[i] = lun; 706 lun->device = device; 707 lun->logical_unit_number = i; 708 lun->should_sync = false; 709 lun->media_present = true; 710 lun->media_changed = true; 711 usb_disk_reset_capacity(lun); 712 713 // initialize this lun 714 result = usb_disk_inquiry(lun); 715 716 // Reset the device 717 // If we don't do it all the other commands except inquiry and send 718 // diagnostics will be stalled. 719 result = usb_disk_send_diagnostic(lun); 720 for (uint32 tries = 0; tries < 3; tries++) { 721 status_t ready = usb_disk_test_unit_ready(lun); 722 if (ready == B_OK || ready == B_DEV_NO_MEDIA) { 723 if (ready == B_OK) { 724 if (lun->device_type == B_CD) 725 lun->write_protected = true; 726 // TODO: check for write protection; disabled since 727 // some devices lock up when getting the mode sense 728 else if (/*usb_disk_mode_sense(lun) != B_OK*/true) 729 lun->write_protected = false; 730 } 731 732 break; 733 } 734 735 snooze(10000); 736 } 737 738 if (result != B_OK) 739 break; 740 } 741 742 if (result != B_OK) { 743 TRACE_ALWAYS("failed to initialize logical units\n"); 744 usb_disk_free_device_and_luns(device); 745 return result; 746 } 747 748 mutex_lock(&gDeviceListLock); 749 device->device_number = 0; 750 disk_device *other = gDeviceList; 751 while (other != NULL) { 752 if (other->device_number >= device->device_number) 753 device->device_number = other->device_number + 1; 754 755 other = (disk_device *)other->link; 756 } 757 758 device->link = (void *)gDeviceList; 759 gDeviceList = device; 760 gLunCount += device->lun_count; 761 for (uint8 i = 0; i < device->lun_count; i++) 762 sprintf(device->luns[i]->name, DEVICE_NAME, device->device_number, i); 763 mutex_unlock(&gDeviceListLock); 764 765 TRACE("new device: 0x%08lx\n", (uint32)device); 766 *cookie = (void *)device; 767 return B_OK; 768} 769 770 771static status_t 772usb_disk_device_removed(void *cookie) 773{ 774 TRACE("device_removed(0x%08lx)\n", (uint32)cookie); 775 disk_device *device = (disk_device *)cookie; 776 777 mutex_lock(&gDeviceListLock); 778 if (gDeviceList == device) { 779 gDeviceList = (disk_device *)device->link; 780 } else { 781 disk_device *element = gDeviceList; 782 while (element) { 783 if (element->link == device) { 784 element->link = device->link; 785 break; 786 } 787 788 element = (disk_device *)element->link; 789 } 790 } 791 gLunCount -= device->lun_count; 792 gDeviceCount--; 793 794 device->removed = true; 795 gUSBModule->cancel_queued_transfers(device->bulk_in); 796 gUSBModule->cancel_queued_transfers(device->bulk_out); 797 if (device->open_count == 0) 798 usb_disk_free_device_and_luns(device); 799 800 mutex_unlock(&gDeviceListLock); 801 return B_OK; 802} 803 804 805// 806//#pragma mark - Partial Buffer Functions 807// 808 809 810static bool 811usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length, 812 uint32 &blockPosition, uint16 &blockCount) 813{ 814 blockPosition = (uint32)(position / lun->block_size); 815 if ((off_t)blockPosition * lun->block_size != position) 816 return true; 817 818 blockCount = (uint16)(length / lun->block_size); 819 if ((size_t)blockCount * lun->block_size != length) 820 return true; 821 822 return false; 823} 824 825 826static status_t 827usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, 828 void *buffer, size_t *length) 829{ 830 uint8 commandBlock[12]; 831 memset(commandBlock, 0, sizeof(commandBlock)); 832 833 commandBlock[0] = SCSI_READ_12; 834 commandBlock[1] = lun->logical_unit_number << 5; 835 commandBlock[2] = blockPosition >> 24; 836 commandBlock[3] = blockPosition >> 16; 837 commandBlock[4] = blockPosition >> 8; 838 commandBlock[5] = blockPosition; 839 commandBlock[6] = blockCount >> 24; 840 commandBlock[7] = blockCount >> 16; 841 commandBlock[8] = blockCount >> 8; 842 commandBlock[9] = blockCount; 843 844 status_t result = B_OK; 845 for (int tries = 0; tries < 5; tries++) { 846 result = usb_disk_operation(lun, commandBlock, buffer, length, 847 true); 848 if (result == B_OK) 849 break; 850 else 851 snooze(10000); 852 } 853 return result; 854} 855 856 857static status_t 858usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, 859 void *buffer, size_t *length) 860{ 861 uint8 commandBlock[12]; 862 memset(commandBlock, 0, sizeof(commandBlock)); 863 864 commandBlock[0] = SCSI_WRITE_12; 865 commandBlock[1] = lun->logical_unit_number << 5; 866 commandBlock[2] = blockPosition >> 24; 867 commandBlock[3] = blockPosition >> 16; 868 commandBlock[4] = blockPosition >> 8; 869 commandBlock[5] = blockPosition; 870 commandBlock[6] = blockCount >> 24; 871 commandBlock[7] = blockCount >> 16; 872 commandBlock[8] = blockCount >> 8; 873 commandBlock[9] = blockCount; 874 875 status_t result; 876 result = usb_disk_operation(lun, commandBlock, buffer, length, 877 false); 878 879 int retry = 10; 880 while (result == B_DEV_NO_MEDIA && retry > 0) { 881 snooze(10000); 882 result = usb_disk_request_sense(lun); 883 retry--; 884 } 885 886 if (result == B_OK) 887 lun->should_sync = true; 888 return result; 889} 890 891 892static status_t 893usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length, 894 void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition, 895 uint16 &blockCount) 896{ 897 blockPosition = (uint32)(position / lun->block_size); 898 blockCount = (uint16)((uint32)((position + length + lun->block_size - 1) 899 / lun->block_size) - blockPosition); 900 size_t blockLength = blockCount * lun->block_size; 901 blockBuffer = malloc(blockLength); 902 if (blockBuffer == NULL) { 903 TRACE_ALWAYS("no memory to allocate partial buffer\n"); 904 return B_NO_MEMORY; 905 } 906 907 status_t result = usb_disk_block_read(lun, blockPosition, blockCount, 908 blockBuffer, &blockLength); 909 if (result != B_OK) { 910 TRACE_ALWAYS("block read failed when filling partial buffer\n"); 911 free(blockBuffer); 912 return result; 913 } 914 915 off_t offset = position - (blockPosition * lun->block_size); 916 partialBuffer = (uint8 *)blockBuffer + offset; 917 return B_OK; 918} 919 920 921// 922//#pragma mark - Driver Hooks 923// 924 925 926static status_t 927usb_disk_open(const char *name, uint32 flags, void **cookie) 928{ 929 TRACE("open(%s)\n", name); 930 if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0) 931 return B_NAME_NOT_FOUND; 932 933 int32 lastPart = 0; 934 size_t nameLength = strlen(name); 935 for (int32 i = nameLength - 1; i >= 0; i--) { 936 if (name[i] == '/') { 937 lastPart = i; 938 break; 939 } 940 } 941 942 char rawName[nameLength + 4]; 943 strncpy(rawName, name, lastPart + 1); 944 rawName[lastPart + 1] = 0; 945 strcat(rawName, "raw"); 946 TRACE("opening raw device %s for %s\n", rawName, name); 947 948 mutex_lock(&gDeviceListLock); 949 disk_device *device = gDeviceList; 950 while (device) { 951 for (uint8 i = 0; i < device->lun_count; i++) { 952 device_lun *lun = device->luns[i]; 953 if (strncmp(rawName, lun->name, 32) == 0) { 954 // found the matching device/lun 955 if (device->removed) { 956 mutex_unlock(&gDeviceListLock); 957 return B_ERROR; 958 } 959 960 device->open_count++; 961 *cookie = lun; 962 mutex_unlock(&gDeviceListLock); 963 return B_OK; 964 } 965 } 966 967 device = (disk_device *)device->link; 968 } 969 970 mutex_unlock(&gDeviceListLock); 971 return B_NAME_NOT_FOUND; 972} 973 974 975static status_t 976usb_disk_close(void *cookie) 977{ 978 TRACE("close()\n"); 979 device_lun *lun = (device_lun *)cookie; 980 disk_device *device = lun->device; 981 982 mutex_lock(&device->lock); 983 if (!device->removed) 984 usb_disk_synchronize(lun, false); 985 mutex_unlock(&device->lock); 986 987 return B_OK; 988} 989 990 991static status_t 992usb_disk_free(void *cookie) 993{ 994 TRACE("free()\n"); 995 mutex_lock(&gDeviceListLock); 996 997 device_lun *lun = (device_lun *)cookie; 998 disk_device *device = lun->device; 999 device->open_count--; 1000 if (device->open_count == 0 && device->removed) { 1001 // we can simply free the device here as it has been removed from 1002 // the device list in the device removed notification hook 1003 usb_disk_free_device_and_luns(device); 1004 } 1005 1006 mutex_unlock(&gDeviceListLock); 1007 return B_OK; 1008} 1009 1010 1011static inline void 1012normalize_name(char *name, size_t nameLength) 1013{ 1014 bool wasSpace = false; 1015 size_t insertIndex = 0; 1016 for (size_t i = 0; i < nameLength; i++) { 1017 bool isSpace = name[i] == ' '; 1018 if (isSpace && wasSpace) 1019 continue; 1020 1021 name[insertIndex++] = name[i]; 1022 wasSpace = isSpace; 1023 } 1024 1025 if (insertIndex > 0 && name[insertIndex - 1] == ' ') 1026 insertIndex--; 1027 1028 name[insertIndex] = 0; 1029} 1030 1031 1032static status_t 1033usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) 1034{ 1035 device_lun *lun = (device_lun *)cookie; 1036 disk_device *device = lun->device; 1037 mutex_lock(&device->lock); 1038 if (device->removed) { 1039 mutex_unlock(&device->lock); 1040 return B_DEV_NOT_READY; 1041 } 1042 1043 status_t result = B_DEV_INVALID_IOCTL; 1044 switch (op) { 1045 case B_GET_DEVICE_SIZE: { 1046 if (lun->media_changed) { 1047 result = usb_disk_update_capacity(lun); 1048 if (result != B_OK) 1049 break; 1050 } 1051 1052 size_t size = lun->block_size * lun->block_count; 1053 result = user_memcpy(buffer, &size, sizeof(size)); 1054 1055 break; 1056 } 1057 1058 case B_GET_MEDIA_STATUS: { 1059 *(status_t *)buffer = usb_disk_test_unit_ready(lun); 1060 TRACE("B_GET_MEDIA_STATUS: 0x%08lx\n", *(status_t *)buffer); 1061 result = B_OK; 1062 break; 1063 } 1064 1065 case B_GET_GEOMETRY: { 1066 if (lun->media_changed) { 1067 result = usb_disk_update_capacity(lun); 1068 if (result != B_OK) 1069 break; 1070 } 1071 1072 device_geometry *geometry = (device_geometry *)buffer; 1073 geometry->bytes_per_sector = lun->block_size; 1074 geometry->cylinder_count = lun->block_count; 1075 geometry->sectors_per_track = geometry->head_count = 1; 1076 geometry->device_type = lun->device_type; 1077 geometry->removable = lun->removable; 1078 geometry->read_only = lun->write_protected; 1079 geometry->write_once = (lun->device_type == B_WORM); 1080 TRACE("B_GET_GEOMETRY: %ld sectors at %ld bytes per sector\n", 1081 geometry->cylinder_count, geometry->bytes_per_sector); 1082 result = B_OK; 1083 break; 1084 } 1085 1086 case B_FLUSH_DRIVE_CACHE: 1087 TRACE("B_FLUSH_DRIVE_CACHE\n"); 1088 result = usb_disk_synchronize(lun, true); 1089 break; 1090 1091 case B_EJECT_DEVICE: 1092 { 1093 uint8 commandBlock[12]; 1094 memset(commandBlock, 0, sizeof(commandBlock)); 1095 1096 commandBlock[0] = SCSI_START_STOP_UNIT_6; 1097 commandBlock[1] = lun->logical_unit_number << 5; 1098 commandBlock[4] = 2; 1099 1100 result = usb_disk_operation(lun, commandBlock, NULL, NULL, false); 1101 break; 1102 } 1103 1104 case B_LOAD_MEDIA: 1105 { 1106 uint8 commandBlock[12]; 1107 memset(commandBlock, 0, sizeof(commandBlock)); 1108 1109 commandBlock[0] = SCSI_START_STOP_UNIT_6; 1110 commandBlock[1] = lun->logical_unit_number << 5; 1111 commandBlock[4] = 3; 1112 1113 result = usb_disk_operation(lun, commandBlock, NULL, NULL, false); 1114 break; 1115 } 1116 1117#if HAIKU_TARGET_PLATFORM_HAIKU 1118 case B_GET_ICON: 1119 // We don't support this legacy ioctl anymore, but the two other 1120 // icon ioctls below instead. 1121 break; 1122 1123 case B_GET_ICON_NAME: 1124 result = user_strlcpy((char *)buffer, 1125 "devices/drive-removable-media-usb", B_FILE_NAME_LENGTH); 1126 break; 1127 1128 case B_GET_VECTOR_ICON: 1129 { 1130 if (length != sizeof(device_icon)) { 1131 result = B_BAD_VALUE; 1132 break; 1133 } 1134 1135 device_icon iconData; 1136 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) { 1137 result = B_BAD_ADDRESS; 1138 break; 1139 } 1140 1141 if (iconData.icon_size >= (int32)sizeof(kDeviceIcon)) { 1142 if (user_memcpy(iconData.icon_data, kDeviceIcon, 1143 sizeof(kDeviceIcon)) != B_OK) { 1144 result = B_BAD_ADDRESS; 1145 break; 1146 } 1147 } 1148 1149 iconData.icon_size = sizeof(kDeviceIcon); 1150 result = user_memcpy(buffer, &iconData, sizeof(device_icon)); 1151 break; 1152 } 1153 1154 case B_GET_DEVICE_NAME: 1155 { 1156 size_t nameLength = sizeof(lun->vendor_name) 1157 + sizeof(lun->product_name) + sizeof(lun->product_revision) + 3; 1158 1159 char name[nameLength]; 1160 snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name, 1161 lun->product_name, lun->product_revision); 1162 1163 normalize_name(name, nameLength); 1164 1165 result = user_strlcpy((char *)buffer, name, length); 1166 if (result > 0) 1167 result = B_OK; 1168 1169 TRACE_ALWAYS("got device name: \"%s\" = %s\n", name, strerror(result)); 1170 break; 1171 } 1172#endif 1173 1174 default: 1175 TRACE_ALWAYS("unhandled ioctl %ld\n", op); 1176 break; 1177 } 1178 1179 mutex_unlock(&device->lock); 1180 return result; 1181} 1182 1183 1184static status_t 1185usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) 1186{ 1187 if (buffer == NULL || length == NULL) 1188 return B_BAD_VALUE; 1189 1190 TRACE("read(%lld, %ld)\n", position, *length); 1191 device_lun *lun = (device_lun *)cookie; 1192 disk_device *device = lun->device; 1193 mutex_lock(&device->lock); 1194 if (device->removed) { 1195 *length = 0; 1196 mutex_unlock(&device->lock); 1197 return B_DEV_NOT_READY; 1198 } 1199 1200 status_t result = B_ERROR; 1201 uint32 blockPosition = 0; 1202 uint16 blockCount = 0; 1203 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length, 1204 blockPosition, blockCount); 1205 if (needsPartial) { 1206 void *partialBuffer = NULL; 1207 void *blockBuffer = NULL; 1208 result = usb_disk_prepare_partial_buffer(lun, position, *length, 1209 partialBuffer, blockBuffer, blockPosition, blockCount); 1210 if (result == B_OK) { 1211 memcpy(buffer, partialBuffer, *length); 1212 free(blockBuffer); 1213 } 1214 } else { 1215 result = usb_disk_block_read(lun, blockPosition, blockCount, buffer, 1216 length); 1217 } 1218 1219 mutex_unlock(&device->lock); 1220 if (result == B_OK) { 1221 TRACE("read successful with %ld bytes\n", *length); 1222 return B_OK; 1223 } 1224 1225 *length = 0; 1226 TRACE_ALWAYS("read fails with 0x%08lx\n", result); 1227 return result; 1228} 1229 1230 1231static status_t 1232usb_disk_write(void *cookie, off_t position, const void *buffer, 1233 size_t *length) 1234{ 1235 if (buffer == NULL || length == NULL) 1236 return B_BAD_VALUE; 1237 1238 TRACE("write(%lld, %ld)\n", position, *length); 1239 device_lun *lun = (device_lun *)cookie; 1240 disk_device *device = lun->device; 1241 mutex_lock(&device->lock); 1242 if (device->removed) { 1243 *length = 0; 1244 mutex_unlock(&device->lock); 1245 return B_DEV_NOT_READY; 1246 } 1247 1248 status_t result = B_ERROR; 1249 uint32 blockPosition = 0; 1250 uint16 blockCount = 0; 1251 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, 1252 *length, blockPosition, blockCount); 1253 if (needsPartial) { 1254 void *partialBuffer = NULL; 1255 void *blockBuffer = NULL; 1256 result = usb_disk_prepare_partial_buffer(lun, position, *length, 1257 partialBuffer, blockBuffer, blockPosition, blockCount); 1258 if (result == B_OK) { 1259 memcpy(partialBuffer, buffer, *length); 1260 size_t blockLength = blockCount * lun->block_size; 1261 result = usb_disk_block_write(lun, blockPosition, blockCount, 1262 blockBuffer, &blockLength); 1263 free(blockBuffer); 1264 } 1265 } else { 1266 result = usb_disk_block_write(lun, blockPosition, blockCount, 1267 (void *)buffer, length); 1268 } 1269 1270 mutex_unlock(&device->lock); 1271 if (result == B_OK) { 1272 TRACE("write successful with %ld bytes\n", *length); 1273 return B_OK; 1274 } 1275 1276 *length = 0; 1277 TRACE_ALWAYS("write fails with 0x%08lx\n", result); 1278 return result; 1279} 1280 1281 1282// 1283//#pragma mark - Driver Entry Points 1284// 1285 1286 1287status_t 1288init_hardware() 1289{ 1290 TRACE("init_hardware()\n"); 1291 return B_OK; 1292} 1293 1294 1295status_t 1296init_driver() 1297{ 1298 TRACE("init_driver()\n"); 1299 static usb_notify_hooks notifyHooks = { 1300 &usb_disk_device_added, 1301 &usb_disk_device_removed 1302 }; 1303 1304 static usb_support_descriptor supportedDevices[] = { 1305 { 0x08 /* mass storage */, 0x04 /* UFI */, 0x00, 0, 0 } 1306 }; 1307 1308 gDeviceList = NULL; 1309 gDeviceCount = 0; 1310 gLunCount = 0; 1311 mutex_init(&gDeviceListLock, "usb_disk device list lock"); 1312 1313 TRACE("trying module %s\n", B_USB_MODULE_NAME); 1314 status_t result = get_module(B_USB_MODULE_NAME, 1315 (module_info **)&gUSBModule); 1316 if (result < B_OK) { 1317 TRACE_ALWAYS("getting module failed 0x%08lx\n", result); 1318 mutex_destroy(&gDeviceListLock); 1319 return result; 1320 } 1321 1322 gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 1, NULL); 1323 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 1324 return B_OK; 1325} 1326 1327 1328void 1329uninit_driver() 1330{ 1331 TRACE("uninit_driver()\n"); 1332 gUSBModule->uninstall_notify(DRIVER_NAME); 1333 mutex_lock(&gDeviceListLock); 1334 1335 if (gDeviceNames) { 1336 for (int32 i = 0; gDeviceNames[i]; i++) 1337 free(gDeviceNames[i]); 1338 free(gDeviceNames); 1339 gDeviceNames = NULL; 1340 } 1341 1342 mutex_destroy(&gDeviceListLock); 1343 put_module(B_USB_MODULE_NAME); 1344} 1345 1346 1347const char ** 1348publish_devices() 1349{ 1350 TRACE("publish_devices()\n"); 1351 if (gDeviceNames) { 1352 for (int32 i = 0; gDeviceNames[i]; i++) 1353 free(gDeviceNames[i]); 1354 free(gDeviceNames); 1355 gDeviceNames = NULL; 1356 } 1357 1358 gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1)); 1359 if (gDeviceNames == NULL) 1360 return NULL; 1361 1362 int32 index = 0; 1363 mutex_lock(&gDeviceListLock); 1364 disk_device *device = gDeviceList; 1365 while (device) { 1366 for (uint8 i = 0; i < device->lun_count; i++) 1367 gDeviceNames[index++] = strdup(device->luns[i]->name); 1368 1369 device = (disk_device *)device->link; 1370 } 1371 1372 gDeviceNames[index++] = NULL; 1373 mutex_unlock(&gDeviceListLock); 1374 return (const char **)gDeviceNames; 1375} 1376 1377 1378device_hooks * 1379find_device(const char *name) 1380{ 1381 TRACE("find_device()\n"); 1382 static device_hooks hooks = { 1383 &usb_disk_open, 1384 &usb_disk_close, 1385 &usb_disk_free, 1386 &usb_disk_ioctl, 1387 &usb_disk_read, 1388 &usb_disk_write, 1389 NULL, 1390 NULL, 1391 NULL, 1392 NULL 1393 }; 1394 1395 return &hooks; 1396} 1397