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