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 // the operation is complete but has failed at the SCSI level 390 if (operation != SCSI_TEST_UNIT_READY_6) { 391 TRACE_ALWAYS("operation 0x%02x failed at the SCSI level\n", 392 operation); 393 } 394 395 result = usb_disk_request_sense(lun); 396 return result == B_OK ? B_ERROR : result; 397 } 398 } 399 400 case CSW_STATUS_PHASE_ERROR: 401 { 402 // a protocol or device error occured 403 TRACE_ALWAYS("phase error in operation 0x%02x\n", operation); 404 usb_disk_reset_recovery(device); 405 return B_ERROR; 406 } 407 408 default: 409 { 410 // command status wrapper is not meaningful 411 TRACE_ALWAYS("command status wrapper has invalid status\n"); 412 usb_disk_reset_recovery(device); 413 return B_ERROR; 414 } 415 } 416 } 417 418 419 // 420 //#pragma mark - Helper/Convenience Functions 421 // 422 423 424 status_t 425 usb_disk_request_sense(device_lun *lun) 426 { 427 uint32 dataLength = sizeof(scsi_request_sense_6_parameter); 428 scsi_request_sense_6_parameter parameter; 429 status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0, 430 dataLength, ¶meter, &dataLength, true); 431 if (result != B_OK) { 432 TRACE_ALWAYS("getting request sense data failed\n"); 433 return result; 434 } 435 436 if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY 437 && parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) { 438 TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: " 439 "0x%02x;\n", parameter.sense_key, parameter.additional_sense_code, 440 parameter.additional_sense_code_qualifier); 441 } 442 443 switch (parameter.sense_key) { 444 case SCSI_SENSE_KEY_NO_SENSE: 445 case SCSI_SENSE_KEY_RECOVERED_ERROR: 446 return B_OK; 447 448 case SCSI_SENSE_KEY_HARDWARE_ERROR: 449 case SCSI_SENSE_KEY_MEDIUM_ERROR: 450 TRACE_ALWAYS("request_sense: media or hardware error\n"); 451 return B_DEV_UNREADABLE; 452 453 case SCSI_SENSE_KEY_ILLEGAL_REQUEST: 454 TRACE_ALWAYS("request_sense: illegal request\n"); 455 return B_DEV_INVALID_IOCTL; 456 457 case SCSI_SENSE_KEY_UNIT_ATTENTION: 458 if (parameter.additional_sense_code 459 != SCSI_ASC_MEDIUM_NOT_PRESENT) { 460 TRACE_ALWAYS("request_sense: media changed\n"); 461 lun->media_changed = true; 462 lun->media_present = true; 463 return B_DEV_MEDIA_CHANGED; 464 } 465 // fall through 466 467 case SCSI_SENSE_KEY_NOT_READY: 468 TRACE("request_sense: device not ready (asc 0x%02x ascq 0x%02x)\n", 469 parameter.additional_sense_code, 470 parameter.additional_sense_code_qualifier); 471 lun->media_present = false; 472 usb_disk_reset_capacity(lun); 473 return B_DEV_NO_MEDIA; 474 475 case SCSI_SENSE_KEY_DATA_PROTECT: 476 TRACE_ALWAYS("request_sense: write protected\n"); 477 return B_READ_ONLY_DEVICE; 478 479 case SCSI_SENSE_KEY_ABORTED_COMMAND: 480 TRACE_ALWAYS("request_sense: command aborted\n"); 481 return B_CANCELED; 482 } 483 484 return B_ERROR; 485 } 486 487 488 status_t 489 usb_disk_mode_sense(device_lun *lun) 490 { 491 uint32 dataLength = sizeof(scsi_mode_sense_6_parameter); 492 scsi_mode_sense_6_parameter parameter; 493 status_t result = usb_disk_operation(lun, SCSI_MODE_SENSE_6, 6, 494 SCSI_MODE_PAGE_DEVICE_CONFIGURATION, dataLength, ¶meter, 495 &dataLength, true); 496 if (result != B_OK) { 497 TRACE_ALWAYS("getting mode sense data failed\n"); 498 return result; 499 } 500 501 lun->write_protected 502 = (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT) 503 != 0; 504 TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no"); 505 return B_OK; 506 } 507 508 509 status_t 510 usb_disk_test_unit_ready(device_lun *lun) 511 { 512 // if unsupported we assume the unit is fixed and therefore always ok 513 if (!lun->device->tur_supported) 514 return B_OK; 515 516 status_t result; 517 if (lun->device->is_atapi) { 518 result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 1, 519 NULL, NULL, false); 520 } else { 521 result = usb_disk_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0, 522 NULL, NULL, true); 523 } 524 525 if (result == B_DEV_INVALID_IOCTL) { 526 lun->device->tur_supported = false; 527 return B_OK; 528 } 529 530 return result; 531 } 532 533 534 status_t 535 usb_disk_inquiry(device_lun *lun) 536 { 537 uint32 dataLength = sizeof(scsi_inquiry_6_parameter); 538 scsi_inquiry_6_parameter parameter; 539 status_t result = B_ERROR; 540 for (uint32 tries = 0; tries < 3; tries++) { 541 result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength, 542 ¶meter, &dataLength, true); 543 if (result == B_OK) 544 break; 545 } 546 if (result != B_OK) { 547 TRACE_ALWAYS("getting inquiry data failed\n"); 548 lun->device_type = B_DISK; 549 lun->removable = true; 550 return result; 551 } 552 553 TRACE("peripherial_device_type 0x%02x\n", 554 parameter.peripherial_device_type); 555 TRACE("peripherial_qualifier 0x%02x\n", 556 parameter.peripherial_qualifier); 557 TRACE("removable_medium %s\n", 558 parameter.removable_medium ? "yes" : "no"); 559 TRACE("version 0x%02x\n", parameter.version); 560 TRACE("response_data_format 0x%02x\n", parameter.response_data_format); 561 TRACE_ALWAYS("vendor_identification \"%.8s\"\n", 562 parameter.vendor_identification); 563 TRACE_ALWAYS("product_identification \"%.16s\"\n", 564 parameter.product_identification); 565 TRACE_ALWAYS("product_revision_level \"%.4s\"\n", 566 parameter.product_revision_level); 567 lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ 568 lun->removable = (parameter.removable_medium == 1); 569 return B_OK; 570 } 571 572 573 status_t 574 usb_disk_reset_capacity(device_lun *lun) 575 { 576 lun->block_size = 512; 577 lun->block_count = 0; 578 return B_OK; 579 } 580 581 582 status_t 583 usb_disk_update_capacity(device_lun *lun) 584 { 585 uint32 dataLength = sizeof(scsi_read_capacity_10_parameter); 586 scsi_read_capacity_10_parameter parameter; 587 status_t result = B_ERROR; 588 589 // Retry reading the capacity up to three times. The first try might only 590 // yield a unit attention telling us that the device or media status 591 // changed, which is more or less expected if it is the first operation 592 // on the device or the device only clears the unit atention for capacity 593 // reads. 594 for (int32 i = 0; i < 3; i++) { 595 result = usb_disk_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0, 596 ¶meter, &dataLength, true); 597 if (result == B_OK) 598 break; 599 } 600 601 if (result != B_OK) { 602 TRACE_ALWAYS("failed to update capacity\n"); 603 lun->media_present = false; 604 lun->media_changed = false; 605 usb_disk_reset_capacity(lun); 606 return result; 607 } 608 609 lun->media_present = true; 610 lun->media_changed = false; 611 lun->block_size = ntohl(parameter.logical_block_length); 612 lun->block_count = ntohl(parameter.last_logical_block_address) + 1; 613 return B_OK; 614 } 615 616 617 status_t 618 usb_disk_synchronize(device_lun *lun, bool force) 619 { 620 if (lun->device->sync_support == 0) { 621 // this device reported an illegal request when syncing or repeatedly 622 // returned an other error, it apparently does not support syncing... 623 return B_UNSUPPORTED; 624 } 625 626 if (!lun->should_sync && !force) 627 return B_OK; 628 629 status_t result = usb_disk_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 10, 630 0, 0, NULL, NULL, false); 631 632 if (result == B_OK) { 633 lun->device->sync_support = SYNC_SUPPORT_RELOAD; 634 lun->should_sync = false; 635 return B_OK; 636 } 637 638 if (result == B_DEV_INVALID_IOCTL) 639 lun->device->sync_support = 0; 640 else 641 lun->device->sync_support--; 642 643 return result; 644 } 645 646 647 // 648 //#pragma mark - Device Attach/Detach Notifications and Callback 649 // 650 651 652 static void 653 usb_disk_callback(void *cookie, status_t status, void *data, 654 size_t actualLength) 655 { 656 //TRACE("callback()\n"); 657 disk_device *device = (disk_device *)cookie; 658 device->status = status; 659 device->actual_length = actualLength; 660 release_sem(device->notify); 661 } 662 663 664 static status_t 665 usb_disk_device_added(usb_device newDevice, void **cookie) 666 { 667 TRACE("device_added(0x%08lx)\n", newDevice); 668 disk_device *device = (disk_device *)malloc(sizeof(disk_device)); 669 device->device = newDevice; 670 device->removed = false; 671 device->open_count = 0; 672 device->interface = 0xff; 673 device->current_tag = 0; 674 device->sync_support = SYNC_SUPPORT_RELOAD; 675 device->tur_supported = true; 676 device->is_atapi = false; 677 device->luns = NULL; 678 679 // scan through the interfaces to find our bulk-only data interface 680 const usb_configuration_info *configuration 681 = gUSBModule->get_configuration(newDevice); 682 if (configuration == NULL) { 683 free(device); 684 return B_ERROR; 685 } 686 687 for (size_t i = 0; i < configuration->interface_count; i++) { 688 usb_interface_info *interface = configuration->interface[i].active; 689 if (interface == NULL) 690 continue; 691 692 if (interface->descr->interface_class == 0x08 /* mass storage */ 693 && (interface->descr->interface_subclass == 0x06 /* SCSI */ 694 || interface->descr->interface_subclass == 0x02 /* ATAPI */ 695 || interface->descr->interface_subclass == 0x05 /* ATAPI */) 696 && interface->descr->interface_protocol == 0x50 /* bulk-only */) { 697 698 bool hasIn = false; 699 bool hasOut = false; 700 for (size_t j = 0; j < interface->endpoint_count; j++) { 701 usb_endpoint_info *endpoint = &interface->endpoint[j]; 702 if (endpoint == NULL 703 || endpoint->descr->attributes != USB_ENDPOINT_ATTR_BULK) 704 continue; 705 706 if (!hasIn && (endpoint->descr->endpoint_address 707 & USB_ENDPOINT_ADDR_DIR_IN)) { 708 device->bulk_in = endpoint->handle; 709 hasIn = true; 710 } else if (!hasOut && (endpoint->descr->endpoint_address 711 & USB_ENDPOINT_ADDR_DIR_IN) == 0) { 712 device->bulk_out = endpoint->handle; 713 hasOut = true; 714 } 715 716 if (hasIn && hasOut) 717 break; 718 } 719 720 if (!(hasIn && hasOut)) 721 continue; 722 723 device->interface = interface->descr->interface_number; 724 device->is_atapi = interface->descr->interface_subclass != 0x06; 725 break; 726 } 727 } 728 729 if (device->interface == 0xff) { 730 TRACE_ALWAYS("no valid bulk-only interface found\n"); 731 free(device); 732 return B_ERROR; 733 } 734 735 mutex_init(&device->lock, "usb_disk device lock"); 736 737 device->notify = create_sem(0, "usb_disk callback notify"); 738 if (device->notify < B_OK) { 739 mutex_destroy(&device->lock); 740 free(device); 741 return device->notify; 742 } 743 744 device->lun_count = usb_disk_get_max_lun(device) + 1; 745 device->luns = (device_lun **)malloc(device->lun_count 746 * sizeof(device_lun *)); 747 for (uint8 i = 0; i < device->lun_count; i++) 748 device->luns[i] = NULL; 749 750 status_t result = B_OK; 751 752 TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count); 753 for (uint8 i = 0; i < device->lun_count; i++) { 754 // create the individual luns present on this device 755 device_lun *lun = (device_lun *)malloc(sizeof(device_lun)); 756 if (lun == NULL) { 757 result = B_NO_MEMORY; 758 break; 759 } 760 761 device->luns[i] = lun; 762 lun->device = device; 763 lun->logical_unit_number = i; 764 lun->should_sync = false; 765 lun->media_present = true; 766 lun->media_changed = true; 767 usb_disk_reset_capacity(lun); 768 769 // initialize this lun 770 result = usb_disk_inquiry(lun); 771 for (uint32 tries = 0; tries < 3; tries++) { 772 status_t ready = usb_disk_test_unit_ready(lun); 773 if (ready == B_OK || ready == B_DEV_NO_MEDIA) { 774 if (ready == B_OK) { 775 if (lun->device_type == B_CD) 776 lun->write_protected = true; 777 // TODO: check for write protection; disabled since 778 // some devices lock up when getting the mode sense 779 else if (/*usb_disk_mode_sense(lun) != B_OK*/true) 780 lun->write_protected = false; 781 } 782 783 break; 784 } 785 786 snooze(10000); 787 } 788 789 if (result != B_OK) 790 break; 791 } 792 793 if (result != B_OK) { 794 TRACE_ALWAYS("failed to initialize logical units\n"); 795 usb_disk_free_device_and_luns(device); 796 return result; 797 } 798 799 mutex_lock(&gDeviceListLock); 800 device->device_number = 0; 801 disk_device *other = gDeviceList; 802 while (other != NULL) { 803 if (other->device_number >= device->device_number) 804 device->device_number = other->device_number + 1; 805 806 other = (disk_device *)other->link; 807 } 808 809 device->link = (void *)gDeviceList; 810 gDeviceList = device; 811 gLunCount += device->lun_count; 812 for (uint8 i = 0; i < device->lun_count; i++) 813 sprintf(device->luns[i]->name, DEVICE_NAME, device->device_number, i); 814 mutex_unlock(&gDeviceListLock); 815 816 TRACE("new device: 0x%08lx\n", (uint32)device); 817 *cookie = (void *)device; 818 return B_OK; 819 } 820 821 822 static status_t 823 usb_disk_device_removed(void *cookie) 824 { 825 TRACE("device_removed(0x%08lx)\n", (uint32)cookie); 826 disk_device *device = (disk_device *)cookie; 827 828 mutex_lock(&gDeviceListLock); 829 if (gDeviceList == device) { 830 gDeviceList = (disk_device *)device->link; 831 } else { 832 disk_device *element = gDeviceList; 833 while (element) { 834 if (element->link == device) { 835 element->link = device->link; 836 break; 837 } 838 839 element = (disk_device *)element->link; 840 } 841 } 842 gLunCount -= device->lun_count; 843 gDeviceCount--; 844 845 device->removed = true; 846 gUSBModule->cancel_queued_transfers(device->bulk_in); 847 gUSBModule->cancel_queued_transfers(device->bulk_out); 848 if (device->open_count == 0) 849 usb_disk_free_device_and_luns(device); 850 851 mutex_unlock(&gDeviceListLock); 852 return B_OK; 853 } 854 855 856 // 857 //#pragma mark - Partial Buffer Functions 858 // 859 860 861 static bool 862 usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length, 863 uint32 &blockPosition, uint16 &blockCount) 864 { 865 blockPosition = (uint32)(position / lun->block_size); 866 if ((off_t)blockPosition * lun->block_size != position) 867 return true; 868 869 blockCount = (uint16)(length / lun->block_size); 870 if ((size_t)blockCount * lun->block_size != length) 871 return true; 872 873 return false; 874 } 875 876 877 static status_t 878 usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, 879 void *buffer, size_t *length) 880 { 881 status_t result = usb_disk_operation(lun, SCSI_READ_10, 10, blockPosition, 882 blockCount, buffer, length, true); 883 return result; 884 } 885 886 887 static status_t 888 usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, 889 void *buffer, size_t *length) 890 { 891 status_t result = usb_disk_operation(lun, SCSI_WRITE_10, 10, blockPosition, 892 blockCount, buffer, length, false); 893 if (result == B_OK) 894 lun->should_sync = true; 895 return result; 896 } 897 898 899 static status_t 900 usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length, 901 void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition, 902 uint16 &blockCount) 903 { 904 blockPosition = (uint32)(position / lun->block_size); 905 blockCount = (uint16)((uint32)((position + length + lun->block_size - 1) 906 / lun->block_size) - blockPosition); 907 size_t blockLength = blockCount * lun->block_size; 908 blockBuffer = malloc(blockLength); 909 if (blockBuffer == NULL) { 910 TRACE_ALWAYS("no memory to allocate partial buffer\n"); 911 return B_NO_MEMORY; 912 } 913 914 status_t result = usb_disk_block_read(lun, blockPosition, blockCount, 915 blockBuffer, &blockLength); 916 if (result != B_OK) { 917 TRACE_ALWAYS("block read failed when filling partial buffer\n"); 918 free(blockBuffer); 919 return result; 920 } 921 922 off_t offset = position - (blockPosition * lun->block_size); 923 partialBuffer = (uint8 *)blockBuffer + offset; 924 return B_OK; 925 } 926 927 928 // 929 //#pragma mark - Driver Hooks 930 // 931 932 933 static status_t 934 usb_disk_open(const char *name, uint32 flags, void **cookie) 935 { 936 TRACE("open(%s)\n", name); 937 if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0) 938 return B_NAME_NOT_FOUND; 939 940 int32 lastPart = 0; 941 size_t nameLength = strlen(name); 942 for (int32 i = nameLength - 1; i >= 0; i--) { 943 if (name[i] == '/') { 944 lastPart = i; 945 break; 946 } 947 } 948 949 char rawName[nameLength + 4]; 950 strncpy(rawName, name, lastPart + 1); 951 rawName[lastPart + 1] = 0; 952 strcat(rawName, "raw"); 953 TRACE("opening raw device %s for %s\n", rawName, name); 954 955 mutex_lock(&gDeviceListLock); 956 disk_device *device = gDeviceList; 957 while (device) { 958 for (uint8 i = 0; i < device->lun_count; i++) { 959 device_lun *lun = device->luns[i]; 960 if (strncmp(rawName, lun->name, 32) == 0) { 961 // found the matching device/lun 962 if (device->removed) { 963 mutex_unlock(&gDeviceListLock); 964 return B_ERROR; 965 } 966 967 device->open_count++; 968 *cookie = lun; 969 mutex_unlock(&gDeviceListLock); 970 return B_OK; 971 } 972 } 973 974 device = (disk_device *)device->link; 975 } 976 977 mutex_unlock(&gDeviceListLock); 978 return B_NAME_NOT_FOUND; 979 } 980 981 982 static status_t 983 usb_disk_close(void *cookie) 984 { 985 TRACE("close()\n"); 986 device_lun *lun = (device_lun *)cookie; 987 disk_device *device = lun->device; 988 989 mutex_lock(&device->lock); 990 if (!device->removed) 991 usb_disk_synchronize(lun, false); 992 mutex_unlock(&device->lock); 993 994 return B_OK; 995 } 996 997 998 static status_t 999 usb_disk_free(void *cookie) 1000 { 1001 TRACE("free()\n"); 1002 mutex_lock(&gDeviceListLock); 1003 1004 device_lun *lun = (device_lun *)cookie; 1005 disk_device *device = lun->device; 1006 device->open_count--; 1007 if (device->open_count == 0 && device->removed) { 1008 // we can simply free the device here as it has been removed from 1009 // the device list in the device removed notification hook 1010 usb_disk_free_device_and_luns(device); 1011 } 1012 1013 mutex_unlock(&gDeviceListLock); 1014 return B_OK; 1015 } 1016 1017 1018 static status_t 1019 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) 1020 { 1021 device_lun *lun = (device_lun *)cookie; 1022 disk_device *device = lun->device; 1023 mutex_lock(&device->lock); 1024 if (device->removed) { 1025 mutex_unlock(&device->lock); 1026 return B_DEV_NOT_READY; 1027 } 1028 1029 status_t result = B_DEV_INVALID_IOCTL; 1030 switch (op) { 1031 case B_GET_MEDIA_STATUS: 1032 { 1033 *(status_t *)buffer = usb_disk_test_unit_ready(lun); 1034 TRACE("B_GET_MEDIA_STATUS: 0x%08lx\n", *(status_t *)buffer); 1035 result = B_OK; 1036 break; 1037 } 1038 1039 case B_GET_GEOMETRY: 1040 { 1041 if (lun->media_changed) { 1042 result = usb_disk_update_capacity(lun); 1043 if (result != B_OK) 1044 break; 1045 } 1046 1047 device_geometry *geometry = (device_geometry *)buffer; 1048 geometry->bytes_per_sector = lun->block_size; 1049 geometry->cylinder_count = lun->block_count; 1050 geometry->sectors_per_track = geometry->head_count = 1; 1051 geometry->device_type = lun->device_type; 1052 geometry->removable = lun->removable; 1053 geometry->read_only = lun->write_protected; 1054 geometry->write_once = (lun->device_type == B_WORM); 1055 TRACE("B_GET_GEOMETRY: %ld sectors at %ld bytes per sector\n", 1056 geometry->cylinder_count, geometry->bytes_per_sector); 1057 result = B_OK; 1058 break; 1059 } 1060 1061 case B_FLUSH_DRIVE_CACHE: 1062 TRACE("B_FLUSH_DRIVE_CACHE\n"); 1063 result = usb_disk_synchronize(lun, true); 1064 break; 1065 1066 case B_EJECT_DEVICE: 1067 result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 2, 1068 NULL, NULL, false); 1069 break; 1070 1071 case B_LOAD_MEDIA: 1072 result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 3, 1073 NULL, NULL, false); 1074 break; 1075 1076 #if HAIKU_TARGET_PLATFORM_HAIKU 1077 case B_GET_ICON: 1078 // We don't support this legacy ioctl anymore, but the two other 1079 // icon ioctls below instead. 1080 break; 1081 1082 case B_GET_ICON_NAME: 1083 result = user_strlcpy((char *)buffer, 1084 "devices/drive-removable-media-usb", B_FILE_NAME_LENGTH); 1085 break; 1086 1087 case B_GET_VECTOR_ICON: 1088 { 1089 if (length != sizeof(device_icon)) { 1090 result = B_BAD_VALUE; 1091 break; 1092 } 1093 1094 device_icon iconData; 1095 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) { 1096 result = B_BAD_ADDRESS; 1097 break; 1098 } 1099 1100 if (iconData.icon_size >= (int32)sizeof(kDeviceIcon)) { 1101 if (user_memcpy(iconData.icon_data, kDeviceIcon, 1102 sizeof(kDeviceIcon)) != B_OK) { 1103 result = B_BAD_ADDRESS; 1104 break; 1105 } 1106 } 1107 1108 iconData.icon_size = sizeof(kDeviceIcon); 1109 result = user_memcpy(buffer, &iconData, sizeof(device_icon)); 1110 break; 1111 } 1112 #endif 1113 1114 default: 1115 TRACE_ALWAYS("unhandled ioctl %ld\n", op); 1116 break; 1117 } 1118 1119 mutex_unlock(&device->lock); 1120 return result; 1121 } 1122 1123 1124 static status_t 1125 usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) 1126 { 1127 if (buffer == NULL || length == NULL) 1128 return B_BAD_VALUE; 1129 1130 TRACE("read(%lld, %ld)\n", position, *length); 1131 device_lun *lun = (device_lun *)cookie; 1132 disk_device *device = lun->device; 1133 mutex_lock(&device->lock); 1134 if (device->removed) { 1135 *length = 0; 1136 mutex_unlock(&device->lock); 1137 return B_DEV_NOT_READY; 1138 } 1139 1140 status_t result = B_ERROR; 1141 uint32 blockPosition = 0; 1142 uint16 blockCount = 0; 1143 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length, 1144 blockPosition, blockCount); 1145 if (needsPartial) { 1146 void *partialBuffer = NULL; 1147 void *blockBuffer = NULL; 1148 result = usb_disk_prepare_partial_buffer(lun, position, *length, 1149 partialBuffer, blockBuffer, blockPosition, blockCount); 1150 if (result == B_OK) { 1151 memcpy(buffer, partialBuffer, *length); 1152 free(blockBuffer); 1153 } 1154 } else { 1155 result = usb_disk_block_read(lun, blockPosition, blockCount, buffer, 1156 length); 1157 } 1158 1159 mutex_unlock(&device->lock); 1160 if (result == B_OK) { 1161 TRACE("read successful with %ld bytes\n", *length); 1162 return B_OK; 1163 } 1164 1165 *length = 0; 1166 TRACE_ALWAYS("read fails with 0x%08lx\n", result); 1167 return result; 1168 } 1169 1170 1171 static status_t 1172 usb_disk_write(void *cookie, off_t position, const void *buffer, 1173 size_t *length) 1174 { 1175 if (buffer == NULL || length == NULL) 1176 return B_BAD_VALUE; 1177 1178 TRACE("write(%lld, %ld)\n", position, *length); 1179 device_lun *lun = (device_lun *)cookie; 1180 disk_device *device = lun->device; 1181 mutex_lock(&device->lock); 1182 if (device->removed) { 1183 *length = 0; 1184 mutex_unlock(&device->lock); 1185 return B_DEV_NOT_READY; 1186 } 1187 1188 status_t result = B_ERROR; 1189 uint32 blockPosition = 0; 1190 uint16 blockCount = 0; 1191 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, 1192 *length, blockPosition, blockCount); 1193 if (needsPartial) { 1194 void *partialBuffer = NULL; 1195 void *blockBuffer = NULL; 1196 result = usb_disk_prepare_partial_buffer(lun, position, *length, 1197 partialBuffer, blockBuffer, blockPosition, blockCount); 1198 if (result == B_OK) { 1199 memcpy(partialBuffer, buffer, *length); 1200 size_t blockLength = blockCount * lun->block_size; 1201 result = usb_disk_block_write(lun, blockPosition, blockCount, 1202 blockBuffer, &blockLength); 1203 free(blockBuffer); 1204 } 1205 } else { 1206 result = usb_disk_block_write(lun, blockPosition, blockCount, 1207 (void *)buffer, length); 1208 } 1209 1210 mutex_unlock(&device->lock); 1211 if (result == B_OK) { 1212 TRACE("write successful with %ld bytes\n", *length); 1213 return B_OK; 1214 } 1215 1216 *length = 0; 1217 TRACE_ALWAYS("write fails with 0x%08lx\n", result); 1218 return result; 1219 } 1220 1221 1222 // 1223 //#pragma mark - Driver Entry Points 1224 // 1225 1226 1227 status_t 1228 init_hardware() 1229 { 1230 TRACE("init_hardware()\n"); 1231 return B_OK; 1232 } 1233 1234 1235 status_t 1236 init_driver() 1237 { 1238 TRACE("init_driver()\n"); 1239 static usb_notify_hooks notifyHooks = { 1240 &usb_disk_device_added, 1241 &usb_disk_device_removed 1242 }; 1243 1244 static usb_support_descriptor supportedDevices[] = { 1245 { 0x08 /* mass storage */, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 }, 1246 { 0x08 /* mass storage */, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 }, 1247 { 0x08 /* mass storage */, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 } 1248 }; 1249 1250 gDeviceList = NULL; 1251 gDeviceCount = 0; 1252 gLunCount = 0; 1253 mutex_init(&gDeviceListLock, "usb_disk device list lock"); 1254 1255 TRACE("trying module %s\n", B_USB_MODULE_NAME); 1256 status_t result = get_module(B_USB_MODULE_NAME, 1257 (module_info **)&gUSBModule); 1258 if (result < B_OK) { 1259 TRACE_ALWAYS("getting module failed 0x%08lx\n", result); 1260 mutex_destroy(&gDeviceListLock); 1261 return result; 1262 } 1263 1264 gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 3, NULL); 1265 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 1266 return B_OK; 1267 } 1268 1269 1270 void 1271 uninit_driver() 1272 { 1273 TRACE("uninit_driver()\n"); 1274 gUSBModule->uninstall_notify(DRIVER_NAME); 1275 mutex_lock(&gDeviceListLock); 1276 1277 if (gDeviceNames) { 1278 for (int32 i = 0; gDeviceNames[i]; i++) 1279 free(gDeviceNames[i]); 1280 free(gDeviceNames); 1281 gDeviceNames = NULL; 1282 } 1283 1284 mutex_destroy(&gDeviceListLock); 1285 put_module(B_USB_MODULE_NAME); 1286 } 1287 1288 1289 const char ** 1290 publish_devices() 1291 { 1292 TRACE("publish_devices()\n"); 1293 if (gDeviceNames) { 1294 for (int32 i = 0; gDeviceNames[i]; i++) 1295 free(gDeviceNames[i]); 1296 free(gDeviceNames); 1297 gDeviceNames = NULL; 1298 } 1299 1300 gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1)); 1301 if (gDeviceNames == NULL) 1302 return NULL; 1303 1304 int32 index = 0; 1305 mutex_lock(&gDeviceListLock); 1306 disk_device *device = gDeviceList; 1307 while (device) { 1308 for (uint8 i = 0; i < device->lun_count; i++) 1309 gDeviceNames[index++] = strdup(device->luns[i]->name); 1310 1311 device = (disk_device *)device->link; 1312 } 1313 1314 gDeviceNames[index++] = NULL; 1315 mutex_unlock(&gDeviceListLock); 1316 return (const char **)gDeviceNames; 1317 } 1318 1319 1320 device_hooks * 1321 find_device(const char *name) 1322 { 1323 TRACE("find_device()\n"); 1324 static device_hooks hooks = { 1325 &usb_disk_open, 1326 &usb_disk_close, 1327 &usb_disk_free, 1328 &usb_disk_ioctl, 1329 &usb_disk_read, 1330 &usb_disk_write, 1331 NULL, 1332 NULL, 1333 NULL, 1334 NULL 1335 }; 1336 1337 return &hooks; 1338 } 1339