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