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