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