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