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