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