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