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 const unsigned char kCDIcon[] = { 122 0x6e, 0x63, 0x69, 0x66, 0x05, 0x05, 0x00, 0x02, 0x03, 0x06, 0x05, 0xb8, 123 0x12, 0xa5, 0xbe, 0x03, 0xe1, 0x3d, 0xe7, 0x84, 0xb8, 0x02, 0x10, 0x49, 124 0xf7, 0x9f, 0x49, 0xed, 0xd8, 0x00, 0xf1, 0xf1, 0xf1, 0x36, 0xd9, 0xdd, 125 0xf4, 0x8a, 0x99, 0x96, 0xb9, 0xb4, 0xb8, 0xbe, 0xdb, 0xff, 0xf4, 0xf4, 126 0xf4, 0x04, 0xeb, 0xd0, 0x02, 0x00, 0x06, 0x02, 0x3c, 0x92, 0xc0, 0x38, 127 0x8f, 0x5f, 0xb8, 0x54, 0x50, 0x3c, 0x57, 0x63, 0x48, 0xd8, 0xdf, 0x48, 128 0x89, 0x5b, 0x00, 0x41, 0x37, 0xa9, 0xff, 0xb9, 0xb9, 0xb9, 0x04, 0x01, 129 0x7e, 0x04, 0x02, 0x04, 0x3f, 0x2c, 0x4e, 0x2c, 0x30, 0x2c, 0x22, 0x40, 130 0x22, 0x34, 0x22, 0x4c, 0x3f, 0x54, 0x30, 0x54, 0x4e, 0x54, 0x5c, 0x40, 131 0x5c, 0x4c, 0x5c, 0x34, 0x02, 0x04, 0x3f, 0x3a, 0x43, 0x3a, 0x3b, 0x3a, 132 0x39, 0x3e, 0x39, 0x3c, 0x39, 0x40, 0x3f, 0x42, 0x3b, 0x42, 0x43, 0x42, 133 0x45, 0x3e, 0x45, 0x40, 0x45, 0x3c, 0x02, 0x04, 0x4b, 0x3e, 0x4b, 0x3a, 134 0x4b, 0x42, 0x3f, 0x46, 0x47, 0x46, 0x37, 0x46, 0x33, 0x3e, 0x33, 0x42, 135 0x33, 0x3a, 0x3f, 0xbb, 0xf7, 0x37, 0xbb, 0xf7, 0x47, 0xbb, 0xf7, 0x02, 136 0x04, 0x40, 0x2a, 0x54, 0x2a, 0x50, 0x2c, 0x5c, 0x40, 0x5c, 0x34, 0x5c, 137 0x4c, 0x40, 0x56, 0x50, 0x54, 0x54, 0x56, 0x60, 0x40, 0x60, 0x4c, 0x60, 138 0x34, 0x06, 0x0a, 0x04, 0x01, 0x03, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x01, 139 0x18, 0x15, 0xff, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x00, 0x02, 0x00, 140 0x01, 0x18, 0x00, 0x15, 0x01, 0x17, 0x86, 0x00, 0x04, 0x0a, 0x01, 0x02, 141 0x00, 0x02, 0x00, 0x0a, 0x02, 0x02, 0x02, 0x01, 0x00, 0x0a, 0x03, 0x01, 142 0x02, 0x10, 0x01, 0x17, 0x82, 0x00, 0x04 143 }; 144 145 const unsigned char kMemoryStickIcon[] = { 146 0x6e, 0x63, 0x69, 0x66, 0x09, 0x05, 0x00, 0x04, 0x00, 0x63, 0x02, 0x00, 147 0x06, 0x02, 0x3a, 0x9c, 0xfb, 0x3b, 0x07, 0x44, 0xbd, 0x68, 0x2d, 0x3c, 148 0xf0, 0x9a, 0x49, 0x8c, 0xd7, 0x4a, 0x02, 0xf0, 0x00, 0x67, 0x72, 0xc0, 149 0xff, 0x5e, 0x68, 0xae, 0x02, 0x00, 0x06, 0x02, 0x39, 0xd8, 0xc8, 0x38, 150 0x57, 0x6f, 0xbb, 0x1e, 0xa3, 0x3c, 0x90, 0x06, 0x4b, 0x3b, 0x28, 0x49, 151 0x91, 0x9a, 0x00, 0x55, 0x55, 0x84, 0xff, 0x73, 0x79, 0xaa, 0x02, 0x00, 152 0x06, 0x02, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 153 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0xbf, 0xed, 154 0xff, 0x81, 0x8b, 0xd9, 0x02, 0x00, 0x06, 0x02, 0x3d, 0x00, 0x00, 0x00, 155 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x4a, 0x00, 0x00, 0xa1, 156 0x24, 0x8d, 0x00, 0xbd, 0xc1, 0xe9, 0xfe, 0x83, 0x8d, 0xdc, 0x03, 0xc3, 157 0xca, 0xff, 0x03, 0x08, 0x13, 0x47, 0x03, 0x08, 0x13, 0x47, 0x0d, 0x0a, 158 0x04, 0x5e, 0xbc, 0x52, 0x3c, 0x5a, 0x42, 0x5a, 0x62, 0xbd, 0x1e, 0x0a, 159 0x06, 0x22, 0x46, 0x22, 0x4b, 0x3c, 0x58, 0x5e, 0x36, 0x5e, 0x32, 0x46, 160 0x2a, 0x06, 0x08, 0xfe, 0x9b, 0x3c, 0x52, 0xbc, 0xae, 0xc6, 0x3d, 0xbd, 161 0x92, 0xc6, 0xa6, 0xbc, 0x79, 0xc6, 0x25, 0x37, 0x52, 0xbc, 0x66, 0xc7, 162 0x08, 0xba, 0x74, 0xc6, 0x22, 0x26, 0x4a, 0xb7, 0x26, 0xc4, 0x8c, 0xb5, 163 0x34, 0xc3, 0xa6, 0xb5, 0x9e, 0xc2, 0xfb, 0xb5, 0xc9, 0xc3, 0x0f, 0xb4, 164 0x89, 0xc2, 0x7b, 0x22, 0x46, 0x4b, 0x3c, 0x58, 0x0a, 0x04, 0x3c, 0x52, 165 0x5e, 0x32, 0x5e, 0x36, 0x3c, 0x58, 0x0a, 0x04, 0x3c, 0x52, 0x5e, 0x32, 166 0x46, 0x2a, 0x22, 0x47, 0x06, 0x07, 0xaa, 0x39, 0xc4, 0x10, 0xbf, 0x1a, 167 0xbc, 0xac, 0xc5, 0xbc, 0x37, 0x50, 0x38, 0x51, 0x50, 0xc4, 0xbc, 0xbe, 168 0xcb, 0x40, 0x38, 0xbf, 0xe4, 0xbc, 0x7f, 0xbf, 0x8f, 0xbc, 0xa6, 0x06, 169 0x08, 0xaa, 0xab, 0xb5, 0xeb, 0xc3, 0x48, 0xbe, 0x7b, 0xbc, 0x6a, 0xbe, 170 0x67, 0xbb, 0xbb, 0xb5, 0x3f, 0xc3, 0x31, 0x26, 0x4a, 0xb5, 0x2e, 0xc3, 171 0xa5, 0xb6, 0x74, 0xc4, 0x2f, 0x37, 0x52, 0x38, 0x51, 0x30, 0x4d, 0x0a, 172 0x04, 0x38, 0x50, 0x4a, 0x3e, 0x3c, 0x38, 0xb5, 0xeb, 0xc3, 0x48, 0x06, 173 0x0d, 0xf6, 0xff, 0xff, 0x03, 0xcc, 0x52, 0xbd, 0x0d, 0xbd, 0x16, 0xca, 174 0xee, 0xbd, 0x16, 0xca, 0xee, 0xbd, 0x16, 0xca, 0x64, 0xbd, 0x01, 0xc9, 175 0xf8, 0xbc, 0x36, 0xca, 0x10, 0xbc, 0xb6, 0xc9, 0xbc, 0xbb, 0xb5, 0xc8, 176 0xf4, 0xbc, 0x36, 0xc8, 0xf4, 0xbb, 0xd9, 0xc9, 0x21, 0xbc, 0xb6, 0xc8, 177 0x70, 0xbd, 0x16, 0xc8, 0xf7, 0xbd, 0x01, 0xc7, 0xff, 0xbd, 0x13, 0xc7, 178 0xea, 0xbc, 0x36, 0xc7, 0xbd, 0xbc, 0xda, 0xc7, 0xea, 0xbb, 0xd9, 0xc6, 179 0xd3, 0xbc, 0x36, 0xc7, 0x24, 0xbb, 0xbb, 0xc6, 0xa6, 0xbc, 0xb0, 0xc5, 180 0xdb, 0xbd, 0x16, 0xc6, 0x56, 0xbc, 0xfb, 0xc5, 0xdb, 0xbd, 0x16, 0xc4, 181 0x5f, 0xbd, 0x16, 0xc4, 0x5f, 0xbd, 0x16, 0xc5, 0x24, 0xbc, 0xcb, 0xc6, 182 0x2f, 0xbb, 0xd9, 0xc5, 0xcf, 0xbc, 0x6c, 0xc7, 0xa8, 0xbb, 0x82, 0xca, 183 0x94, 0xbb, 0xd9, 0xc9, 0x1e, 0xbb, 0x7c, 0xca, 0xfa, 0xbc, 0x69, 0xcc, 184 0x52, 0xbd, 0x0d, 0xcb, 0x92, 0xbc, 0xcb, 0xcc, 0x52, 0xbd, 0x0d, 0x06, 185 0x04, 0xfe, 0xcc, 0x52, 0xbd, 0x91, 0xcc, 0x52, 0xbd, 0x94, 0xcc, 0x52, 186 0xbd, 0x94, 0xc9, 0xa7, 0xbd, 0xee, 0xc4, 0x5f, 0xbd, 0x91, 0xc7, 0x00, 187 0xbd, 0xee, 0xc7, 0x12, 0xbd, 0x55, 0xcc, 0x52, 0xbd, 0x91, 0xc9, 0xb3, 188 0xbd, 0x52, 0xcc, 0x52, 0xbd, 0x91, 0x02, 0x03, 0xc5, 0x75, 0xbe, 0x50, 189 0xc5, 0x75, 0xbe, 0x50, 0xc7, 0x75, 0xbe, 0x24, 0xcb, 0x50, 0xbe, 0x50, 190 0xc9, 0x63, 0xbe, 0x24, 0xc9, 0x5a, 0xbe, 0x92, 0xc5, 0x75, 0xbe, 0x50, 191 0xc7, 0x66, 0xbe, 0x92, 0xc5, 0x75, 0xbe, 0x50, 0x02, 0x02, 0xc6, 0x2f, 192 0xbe, 0xdd, 0xc7, 0xa5, 0xbf, 0x22, 0xc7, 0xae, 0xbe, 0xb3, 0xca, 0x97, 193 0xbe, 0xdd, 0xc9, 0x24, 0xbe, 0xb0, 0xc9, 0x1e, 0xbf, 0x22, 0x0a, 0x03, 194 0x45, 0x2d, 0x4a, 0x2f, 0x4a, 0x2c, 0x0a, 0x0a, 0x01, 0x01, 0x00, 0x00, 195 0x0a, 0x00, 0x01, 0x01, 0x10, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x02, 196 0x01, 0x02, 0x00, 0x0a, 0x03, 0x01, 0x03, 0x00, 0x0a, 0x04, 0x01, 0x04, 197 0x00, 0x0a, 0x03, 0x01, 0x06, 0x00, 0x0a, 0x06, 0x01, 0x05, 0x00, 0x0a, 198 0x05, 0x01, 0x07, 0x00, 0x0a, 0x07, 0x04, 0x09, 0x0a, 0x0b, 0x08, 0x02, 199 0xbe, 0x56, 0x60, 0x3e, 0x5e, 0xcf, 0xbe, 0x5e, 0xcf, 0xbe, 0x56, 0x60, 200 0x4c, 0xe9, 0x91, 0x41, 0xdd, 0x95, 0x0a, 0x08, 0x01, 0x0c, 0x00 201 }; 202 203 204 const unsigned char kSDIcon[] = { 205 0x6e, 0x63, 0x69, 0x66, 0x09, 0x05, 0x00, 0x04, 0x00, 0x63, 0x02, 0x00, 206 0x06, 0x02, 0x3a, 0x9c, 0xfb, 0x3b, 0x07, 0x44, 0xbd, 0x68, 0x2d, 0x3c, 207 0xf0, 0x9a, 0x49, 0x8c, 0xd7, 0x4a, 0x02, 0xf0, 0x00, 0xa4, 0xa4, 0xa4, 208 0xff, 0x5a, 0x5b, 0x65, 0x02, 0x00, 0x16, 0x02, 0x39, 0xd8, 0xc8, 0x38, 209 0x57, 0x6f, 0xbb, 0x1e, 0xa3, 0x3c, 0x90, 0x06, 0x4b, 0x3b, 0x28, 0x49, 210 0x91, 0x9a, 0x00, 0x55, 0xff, 0x39, 0x02, 0x00, 0x16, 0x02, 0x3d, 0x00, 211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x4a, 0x00, 212 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xff, 0x5b, 0x02, 0x00, 0x06, 0x02, 213 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 214 0x4a, 0x00, 0x00, 0xa1, 0x24, 0x8d, 0x00, 0xe5, 0xe7, 0xf9, 0xfe, 0xb3, 215 0xb5, 0xc3, 0x05, 0xc6, 0x03, 0x08, 0x13, 0x47, 0x05, 0xff, 0x0e, 0x0a, 216 0x04, 0x60, 0xc0, 0x4e, 0x44, 0x5e, 0x4a, 0x5e, 0x60, 0x47, 0x0a, 0x0c, 217 0x22, 0x46, 0x22, 0x48, 0x22, 0x4b, 0x44, 0x5c, 0xca, 0x15, 0xc2, 0x2a, 218 0x59, 0x45, 0x5b, 0x43, 0x5c, 0x44, 0x5e, 0x42, 0x5e, 0x3e, 0xcb, 0x07, 219 0x33, 0x46, 0x2a, 0x06, 0x08, 0xfe, 0x9b, 0x44, 0x56, 0xbf, 0xde, 0xc7, 220 0xd5, 0xc0, 0xc2, 0xc8, 0x3e, 0xbf, 0xa9, 0xc7, 0xbd, 0x3f, 0x56, 0xbf, 221 0x96, 0xc8, 0xa0, 0xbd, 0xa4, 0xc7, 0xba, 0x26, 0x4a, 0xb7, 0x26, 0xc4, 222 0x8c, 0xb5, 0x34, 0xc3, 0xa6, 0xb5, 0x9e, 0xc2, 0xfb, 0xb5, 0xc9, 0xc3, 223 0x0f, 0xb4, 0x89, 0xc2, 0x7b, 0x22, 0x46, 0x4b, 0x44, 0x5c, 0x0a, 0x0c, 224 0x44, 0x56, 0xca, 0x87, 0xbf, 0xe4, 0x5a, 0xbf, 0x83, 0x5b, 0xbf, 0x1d, 225 0xca, 0xe7, 0xbf, 0x92, 0x5e, 0x3e, 0x5e, 0x42, 0xca, 0xeb, 0xc1, 0x54, 226 0xca, 0x85, 0xc0, 0xf5, 0x5a, 0x44, 0xca, 0x86, 0xc1, 0xb9, 0x44, 0x5c, 227 0x0a, 0x0d, 0x44, 0x56, 0xca, 0x8f, 0xbf, 0xf3, 0x5a, 0xbf, 0x93, 0xca, 228 0x90, 0xbf, 0x22, 0xca, 0xf3, 0xbf, 0x9e, 0x5e, 0x3e, 0xcb, 0x09, 0xba, 229 0x91, 0x46, 0x2a, 0xc0, 0x1e, 0xb8, 0x9c, 0x41, 0x2f, 0x3b, 0x34, 0xbd, 230 0x91, 0xba, 0xab, 0x22, 0x47, 0x06, 0x07, 0xaa, 0x39, 0xc9, 0xa4, 0xbf, 231 0x80, 0xc0, 0xa8, 0xc7, 0xba, 0x41, 0x55, 0x42, 0x56, 0x55, 0xca, 0x50, 232 0xbf, 0x31, 0x44, 0x34, 0xc1, 0x7c, 0xba, 0xe7, 0xc1, 0x27, 0xbb, 0x0e, 233 0x06, 0x08, 0xaa, 0xab, 0xb5, 0x1f, 0xc2, 0xe2, 0xbf, 0xad, 0xba, 0xd2, 234 0xbf, 0x99, 0xba, 0x23, 0xb4, 0x73, 0xc2, 0xcb, 0x24, 0x49, 0xb4, 0x62, 235 0xc3, 0x3f, 0xb5, 0xa8, 0xc3, 0xc9, 0x40, 0x57, 0x41, 0x56, 0x32, 0x4e, 236 0x0a, 0x04, 0x40, 0x55, 0x58, 0x3f, 0x40, 0x33, 0xb5, 0x85, 0xc2, 0xe2, 237 0x0a, 0x03, 0x44, 0x2d, 0x46, 0x2f, 0x42, 0x31, 0x0a, 0x08, 0x47, 0x30, 238 0x47, 0x31, 0x49, 0x32, 0x4a, 0x32, 0x4a, 0x34, 0x49, 0x34, 0x47, 0x33, 239 0x45, 0x32, 0x04, 0x0f, 0xaf, 0xff, 0xeb, 0x3f, 0xc9, 0x8a, 0xc3, 0xb2, 240 0xc9, 0x8a, 0xc3, 0xb2, 0xc9, 0x8a, 0xc4, 0xc4, 0xc3, 0x50, 0xc4, 0xc4, 241 0xc7, 0xed, 0xc4, 0xda, 0xbc, 0x23, 0xc4, 0xa6, 0xb6, 0x1e, 0xc3, 0xee, 242 0xb3, 0x4d, 0xcb, 0xb1, 0xc1, 0x6c, 0xcc, 0x29, 0xba, 0x22, 0xcc, 0x29, 243 0xcb, 0xd2, 0xcc, 0x29, 0xd5, 0xf5, 0xc5, 0xb4, 0xd4, 0x64, 0xcc, 0x92, 244 0xd7, 0x12, 0xc0, 0xdb, 0xcd, 0xcd, 0xbd, 0x13, 0xd2, 0xd7, 0xbe, 0x92, 245 0xca, 0x67, 0xbc, 0x11, 0xc4, 0x35, 0xb9, 0x75, 0xc4, 0x35, 0xba, 0xac, 246 0xc4, 0x35, 0xb7, 0xe8, 0xcb, 0x40, 0xb7, 0xdc, 0xc8, 0x5e, 0xb7, 0xf3, 247 0xce, 0x66, 0xb7, 0xc6, 0xda, 0x9a, 0xb7, 0xc2, 0xdc, 0x27, 0xb3, 0x5d, 248 0xca, 0xaa, 0xb3, 0x8e, 0xd3, 0x61, 0xb3, 0x21, 0xbe, 0x1d, 0xb4, 0x2f, 249 0xbb, 0x7a, 0xb9, 0xa2, 0xbb, 0xc5, 0xb6, 0xf8, 0xbb, 0x18, 0xbd, 0x17, 250 0xc2, 0x95, 0xc0, 0x93, 0xbf, 0xc1, 0xbf, 0x7e, 0xc5, 0x46, 0xc1, 0x9a, 251 0xc9, 0x8a, 0xc3, 0xb2, 0xc9, 0x8a, 0xc2, 0x5d, 0xc9, 0x8a, 0xc3, 0xb2, 252 0x00, 0x0c, 0xeb, 0x0d, 0xbb, 0x77, 0xeb, 0x0d, 0xbb, 0x77, 0xea, 0xfe, 253 0xbb, 0x59, 0xea, 0xd8, 0xbb, 0x1d, 0xea, 0xeb, 0xbb, 0x3b, 0xea, 0xd8, 254 0xbb, 0x1d, 0xf9, 0xf9, 0xb7, 0x4e, 0xf9, 0xf9, 0xb7, 0x4e, 0xfc, 0x60, 255 0xb8, 0x7a, 0xff, 0x6c, 0xbb, 0xeb, 0xfe, 0x62, 0xb9, 0xfc, 0xff, 0x80, 256 0xbd, 0x9e, 0xff, 0x16, 0xc1, 0x17, 0xff, 0x80, 0xbf, 0x60, 0xf6, 0x6e, 257 0xcb, 0xd7, 0xd7, 0xca, 0xcc, 0x22, 0xdf, 0xeb, 0xcb, 0xc4, 0xd7, 0xca, 258 0xcc, 0x22, 0xdb, 0x52, 0xc2, 0x30, 0xdb, 0x52, 0xc2, 0x30, 0xdd, 0x79, 259 0xc2, 0x1d, 0xe2, 0x70, 0xc1, 0x71, 0xe0, 0x94, 0xc1, 0xce, 0xe4, 0x48, 260 0xc1, 0x13, 0xe7, 0x49, 0xc0, 0x05, 0xe5, 0xf0, 0xc0, 0x97, 0xe8, 0xa2, 261 0xbf, 0x73, 0xea, 0x5c, 0xbe, 0x1d, 0xe9, 0xb0, 0xbe, 0xce, 0xeb, 0x05, 262 0xbd, 0x6d, 0xeb, 0x36, 0xbb, 0xfe, 0xeb, 0x58, 0xbc, 0xb9, 0xeb, 0x2e, 263 0xbb, 0xd1, 0xeb, 0x0d, 0xbb, 0x77, 0xeb, 0x1f, 0xbb, 0xa4, 0xeb, 0x0d, 264 0xbb, 0x77, 0x04, 0x06, 0xff, 0x0b, 0xf6, 0xc4, 0xb5, 0xfc, 0xf6, 0xc4, 265 0xb5, 0xfc, 0xf5, 0xe3, 0xb5, 0x9f, 0xf3, 0xc7, 0xb4, 0xee, 0xf4, 0xac, 266 0xb5, 0x2a, 0xf3, 0xc7, 0xb4, 0xee, 0xe8, 0xb5, 0xb9, 0x66, 0xe8, 0xb5, 267 0xb9, 0x66, 0xe9, 0x07, 0xb9, 0x8f, 0xe9, 0xc3, 0xba, 0x16, 0xe9, 0x83, 268 0xb9, 0xed, 0xe9, 0xd5, 0xba, 0x25, 0xe9, 0xf7, 0xba, 0x3c, 0xe9, 0xe4, 269 0xba, 0x31, 0xe9, 0xf7, 0xba, 0x3c, 0xf6, 0xc4, 0xb5, 0xfc, 0x04, 0x07, 270 0xff, 0x2f, 0xed, 0xb0, 0xb3, 0xe8, 0xed, 0xb0, 0xb3, 0xe8, 0xeb, 0xdb, 271 0xb3, 0xa5, 0xe9, 0x70, 0xb3, 0x7f, 0xea, 0x55, 0xb3, 0x87, 0xe5, 0xe8, 272 0xb3, 0x69, 0xe0, 0x97, 0xb3, 0x5a, 0xe4, 0x84, 0xb3, 0x56, 0xe0, 0x97, 273 0xb3, 0x5a, 0xdf, 0x06, 0xb7, 0xc6, 0xdf, 0x06, 0xb7, 0xc6, 0xdf, 0xfe, 274 0xb7, 0xcd, 0xe2, 0x0e, 0xb7, 0xeb, 0xe0, 0x6e, 0xb7, 0xc2, 0xe3, 0x8d, 275 0xb8, 0x11, 0xe6, 0x24, 0xb8, 0x9c, 0xe4, 0xed, 0xb8, 0x49, 0xe6, 0x24, 276 0xb8, 0x9c, 0xed, 0xb0, 0xb3, 0xe8, 0x0d, 0x0a, 0x01, 0x01, 0x00, 0x00, 277 0x0a, 0x00, 0x01, 0x01, 0x10, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x02, 278 0x01, 0x02, 0x00, 0x0a, 0x03, 0x01, 0x03, 0x00, 0x0a, 0x04, 0x01, 0x04, 279 0x00, 0x0a, 0x03, 0x01, 0x06, 0x00, 0x0a, 0x06, 0x01, 0x05, 0x00, 0x0a, 280 0x05, 0x01, 0x07, 0x00, 0x0a, 0x00, 0x01, 0x0a, 0x02, 0x3a, 0x19, 0xca, 281 0x38, 0x20, 0xc9, 0xb8, 0x20, 0xc9, 0x3a, 0x19, 0xca, 0x49, 0x04, 0x3f, 282 0x48, 0xbc, 0x82, 0x0a, 0x00, 0x01, 0x0b, 0x02, 0x3a, 0x19, 0xca, 0x38, 283 0x20, 0xc9, 0xb8, 0x20, 0xc9, 0x3a, 0x19, 0xca, 0x49, 0x04, 0x3f, 0x48, 284 0xbc, 0x82, 0x0a, 0x00, 0x01, 0x0c, 0x02, 0x3a, 0x19, 0xca, 0x38, 0x20, 285 0xc9, 0xb8, 0x20, 0xc9, 0x3a, 0x19, 0xca, 0x49, 0x04, 0x3f, 0x48, 0xbc, 286 0x82, 0x0a, 0x00, 0x01, 0x0d, 0x02, 0x3a, 0x19, 0xca, 0x38, 0x20, 0xc9, 287 0xb8, 0x20, 0xc9, 0x3a, 0x19, 0xca, 0x49, 0x04, 0x3f, 0x48, 0xbc, 0x82, 288 0x0a, 0x08, 0x02, 0x08, 0x09, 0x00 289 }; 290 291 const unsigned char kMobileIcon[] = { 292 0x6e, 0x63, 0x69, 0x66, 0x09, 0x05, 0x00, 0x04, 0x00, 0x66, 0x02, 0x00, 293 0x06, 0x02, 0x38, 0xf1, 0x86, 0x38, 0x62, 0x09, 0xba, 0xd4, 0x58, 0x3b, 294 0x7e, 0xb7, 0x4a, 0x28, 0x8f, 0x47, 0xaf, 0x7c, 0x00, 0xee, 0xef, 0xf3, 295 0xff, 0xce, 0xd2, 0xd9, 0x02, 0x00, 0x06, 0x03, 0x39, 0x3a, 0x47, 0xba, 296 0x81, 0x7b, 0x3f, 0x5c, 0xe7, 0x3e, 0x2a, 0x74, 0xc5, 0xab, 0xe0, 0x49, 297 0x3b, 0x67, 0x00, 0xff, 0xff, 0xff, 0x42, 0xd9, 0xde, 0xe5, 0xff, 0xb5, 298 0xb8, 0xbf, 0x02, 0x00, 0x06, 0x02, 0x38, 0xdc, 0xc0, 0x32, 0xb6, 0x96, 299 0xb9, 0xc3, 0xec, 0x3f, 0xf8, 0xe2, 0x4a, 0x00, 0x51, 0xb9, 0x4b, 0xdc, 300 0x00, 0xce, 0xd2, 0xd9, 0xff, 0x95, 0x9a, 0xa6, 0x02, 0x03, 0x06, 0x04, 301 0xba, 0x6c, 0x40, 0xb8, 0x55, 0xde, 0xbb, 0x7a, 0x07, 0x3d, 0x9b, 0x59, 302 0x49, 0xea, 0xb7, 0x49, 0x0b, 0x3e, 0x20, 0xda, 0xde, 0xe5, 0x52, 0xff, 303 0xff, 0xff, 0xa4, 0xff, 0xff, 0xff, 0xff, 0x95, 0x9a, 0xa6, 0x05, 0xff, 304 0x02, 0x00, 0x06, 0x03, 0x38, 0x2d, 0xf0, 0x3a, 0x3d, 0xb3, 0xbf, 0x98, 305 0xe5, 0x3d, 0x7f, 0x98, 0x4b, 0xc7, 0x2b, 0x44, 0x03, 0xbe, 0x00, 0x9e, 306 0xc9, 0xff, 0xb2, 0x60, 0x99, 0xde, 0xff, 0x7f, 0xb0, 0xef, 0x03, 0x73, 307 0x79, 0x80, 0x15, 0x0a, 0x0a, 0x29, 0x54, 0x39, 0x5e, 0x3c, 0x5c, 0x3d, 308 0x5a, 0x46, 0x53, 0x47, 0x53, 0x59, 0x44, 0x59, 0x43, 0x4a, 0x3c, 0x29, 309 0x52, 0x0a, 0x08, 0x4a, 0x39, 0x4b, 0x3a, 0x3a, 0x5c, 0x38, 0x5c, 0x27, 310 0x52, 0x29, 0x4e, 0x2a, 0x4d, 0x38, 0x31, 0x0a, 0x0a, 0x4a, 0x39, 0x3b, 311 0x57, 0x39, 0x59, 0x37, 0x59, 0x36, 0x5a, 0x29, 0x52, 0x27, 0x52, 0x29, 312 0x4e, 0x2a, 0x4d, 0x38, 0x31, 0x0a, 0x0a, 0x27, 0x52, 0x29, 0x52, 0x36, 313 0x5a, 0x37, 0x59, 0x39, 0x59, 0x3b, 0x57, 0x4a, 0x39, 0x4b, 0x3a, 0x3a, 314 0x5c, 0x38, 0x5c, 0x08, 0x02, 0x35, 0x45, 0x2e, 0x51, 0x08, 0x02, 0x3b, 315 0x48, 0x34, 0x54, 0x08, 0x02, 0x3b, 0x53, 0x2d, 0x4b, 0x08, 0x02, 0x2f, 316 0x47, 0x3d, 0x4e, 0x0a, 0x08, 0x31, 0x42, 0x30, 0x40, 0x3f, 0x22, 0x52, 317 0x29, 0x52, 0x2a, 0x43, 0x48, 0x42, 0x49, 0x3f, 0x49, 0x0a, 0x0a, 0x31, 318 0x42, 0x30, 0x40, 0x3f, 0x22, 0x52, 0x29, 0x52, 0x2a, 0x43, 0x48, 0x42, 319 0x49, 0x3f, 0x49, 0x50, 0x29, 0x3f, 0x23, 0x0a, 0x04, 0x31, 0x42, 0x3f, 320 0x23, 0x50, 0x29, 0x3f, 0x49, 0x0a, 0x04, 0x48, 0x28, 0x47, 0x29, 0x44, 321 0x28, 0x45, 0x27, 0x0a, 0x04, 0x43, 0x26, 0x44, 0x25, 0x4b, 0x28, 0x4a, 322 0x29, 0x0a, 0x04, 0x4c, 0x2c, 0x44, 0x3c, 0x38, 0x36, 0x3f, 0x27, 0x0a, 323 0x04, 0x39, 0x3e, 0x3c, 0x40, 0x3d, 0x3e, 0xbd, 0x62, 0xbe, 0x44, 0x08, 324 0x02, 0x37, 0x40, 0x3c, 0x43, 0x08, 0x02, 0x36, 0x42, 0x3a, 0x39, 0x08, 325 0x02, 0x35, 0x3d, 0x37, 0x3e, 0x08, 0x02, 0x3b, 0x45, 0x40, 0x3c, 0x08, 326 0x02, 0x40, 0x43, 0x3d, 0x41, 0x08, 0x03, 0x38, 0x36, 0x3f, 0x27, 0x4c, 327 0x2c, 0x0f, 0x0a, 0x01, 0x01, 0x00, 0x10, 0x01, 0x15, 0x84, 0x00, 0x04, 328 0x0a, 0x00, 0x01, 0x01, 0x18, 0x00, 0x15, 0x01, 0x17, 0x86, 0x02, 0x04, 329 0x0a, 0x00, 0x01, 0x01, 0x18, 0x15, 0xff, 0x01, 0x17, 0x84, 0x02, 0x04, 330 0x0a, 0x03, 0x01, 0x02, 0x00, 0x0a, 0x04, 0x01, 0x03, 0x00, 0x0a, 0x08, 331 0x04, 0x04, 0x05, 0x06, 0x07, 0x18, 0x15, 0xff, 0x01, 0x17, 0x81, 0x00, 332 0x04, 0x0a, 0x00, 0x01, 0x08, 0x18, 0x00, 0x15, 0x01, 0x17, 0x86, 0x02, 333 0x04, 0x0a, 0x00, 0x01, 0x08, 0x18, 0x15, 0xff, 0x01, 0x17, 0x84, 0x02, 334 0x04, 0x0a, 0x05, 0x01, 0x09, 0x00, 0x0a, 0x02, 0x01, 0x0a, 0x00, 0x0a, 335 0x00, 0x01, 0x0b, 0x08, 0x15, 0xff, 0x0a, 0x06, 0x01, 0x0c, 0x08, 0x15, 336 0xff, 0x0a, 0x07, 0x01, 0x0d, 0x00, 0x0a, 0x06, 0x01, 0x0e, 0x08, 0x15, 337 0xff, 0x0a, 0x08, 0x06, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x14, 0x18, 0x15, 338 0xff, 0x01, 0x17, 0x81, 0x00, 0x04 339 }; 340 341 device_icon kKeyIconData = { (int32)sizeof(kDeviceIcon), (void *)kDeviceIcon }; 342 device_icon kCDIconData = { (int32)sizeof(kCDIcon), (void *)kCDIcon }; 343 device_icon kMSIconData = { (int32)sizeof(kMemoryStickIcon), 344 (void *)kMemoryStickIcon }; 345 device_icon kSDIconData = { (int32)sizeof(kSDIcon), (void *)kSDIcon }; 346 device_icon kMobileIconData = { (int32)sizeof(kMobileIcon), 347 (void *)kMobileIcon }; 348 349 350 struct { 351 const char *vendor; 352 const char *product; 353 device_icon *icon; 354 const char *name; 355 } kIconMatches[] = { 356 // matches for Hama USB 2.0 Card Reader 35 in 1 357 // vendor: "Transcend Information, Inc." 358 // product: "63-in-1 Multi-Card Reader/Writer" ver. 0100 359 // which report things like "Generic " "USB CF Reader " 360 // { NULL, " CF Reader", &kCFIconData, "devices/drive-removable-media-flash" }, 361 { NULL, " SD Reader", &kSDIconData, "devices/drive-removable-media-flash" }, 362 { NULL, " MS Reader", &kMSIconData, "devices/drive-removable-media-flash" }, 363 // { NULL, " SM Reader", &kSMIconData, "devices/drive-removable-media-flash" }, 364 // match for my Kazam mobile phone 365 // stupid thing says "MEDIATEK" " FLASH DISK " even for internal memory 366 { "MEDIATEK", NULL, &kMobileIconData, "devices/drive-removable-media-flash" }, 367 { NULL, NULL, NULL, NULL } 368 }; 369 370 371 // 372 //#pragma mark - Forward Declarations 373 // 374 375 376 static void usb_disk_callback(void *cookie, status_t status, void *data, 377 size_t actualLength); 378 379 status_t usb_disk_mass_storage_reset(disk_device *device); 380 uint8 usb_disk_get_max_lun(disk_device *device); 381 void usb_disk_reset_recovery(disk_device *device); 382 status_t usb_disk_transfer_data(disk_device *device, bool directionIn, 383 void *data, size_t dataLength); 384 status_t usb_disk_receive_csw(disk_device *device, 385 usb_massbulk_command_status_wrapper *status); 386 status_t usb_disk_operation(device_lun *lun, uint8 operation, 387 uint8 opLength, uint32 logicalBlockAddress, 388 uint16 transferLength, void *data, size_t *dataLength, 389 bool directionIn, err_act *action = NULL); 390 391 status_t usb_disk_request_sense(device_lun *lun, err_act *action); 392 status_t usb_disk_mode_sense(device_lun *lun); 393 status_t usb_disk_test_unit_ready(device_lun *lun, err_act *action = NULL); 394 status_t usb_disk_inquiry(device_lun *lun); 395 status_t usb_disk_reset_capacity(device_lun *lun); 396 status_t usb_disk_update_capacity(device_lun *lun); 397 status_t usb_disk_synchronize(device_lun *lun, bool force); 398 399 400 // 401 //#pragma mark - Device Allocation Helper Functions 402 // 403 404 405 void 406 usb_disk_free_device_and_luns(disk_device *device) 407 { 408 mutex_lock(&device->lock); 409 mutex_destroy(&device->lock); 410 delete_sem(device->notify); 411 for (uint8 i = 0; i < device->lun_count; i++) 412 free(device->luns[i]); 413 free(device->luns); 414 free(device); 415 } 416 417 418 // 419 //#pragma mark - Bulk-only Mass Storage Functions 420 // 421 422 423 status_t 424 usb_disk_mass_storage_reset(disk_device *device) 425 { 426 return gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_OUT 427 | USB_REQTYPE_CLASS, USB_MASSBULK_REQUEST_MASS_STORAGE_RESET, 0x0000, 428 device->interface, 0, NULL, NULL); 429 } 430 431 432 uint8 433 usb_disk_get_max_lun(disk_device *device) 434 { 435 uint8 result = 0; 436 size_t actualLength = 0; 437 438 // devices that do not support multiple LUNs may stall this request 439 if (gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_IN 440 | USB_REQTYPE_CLASS, USB_MASSBULK_REQUEST_GET_MAX_LUN, 0x0000, 441 device->interface, 1, &result, &actualLength) != B_OK 442 || actualLength != 1) { 443 return 0; 444 } 445 446 if (result > MAX_LOGICAL_UNIT_NUMBER) { 447 // invalid max lun 448 return 0; 449 } 450 451 return result; 452 } 453 454 455 void 456 usb_disk_reset_recovery(disk_device *device) 457 { 458 usb_disk_mass_storage_reset(device); 459 gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); 460 gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 461 } 462 463 464 status_t 465 usb_disk_transfer_data(disk_device *device, bool directionIn, void *data, 466 size_t dataLength) 467 { 468 status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in 469 : device->bulk_out, data, dataLength, usb_disk_callback, device); 470 if (result != B_OK) { 471 TRACE_ALWAYS("failed to queue data transfer: %s\n", strerror(result)); 472 return result; 473 } 474 475 do { 476 result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 477 10 * 1000 * 1000); 478 if (result == B_TIMED_OUT) { 479 // Cancel the transfer and collect the sem that should now be 480 // released through the callback on cancel. Handling of device 481 // reset is done in usb_disk_operation() when it detects that 482 // the transfer failed. 483 gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in 484 : device->bulk_out); 485 acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0); 486 } 487 } while (result == B_INTERRUPTED); 488 489 if (result != B_OK) { 490 TRACE_ALWAYS("acquire_sem failed while waiting for data transfer: %s\n", 491 strerror(result)); 492 return result; 493 } 494 495 return B_OK; 496 } 497 498 499 status_t 500 usb_disk_receive_csw(disk_device *device, 501 usb_massbulk_command_status_wrapper *status) 502 { 503 status_t result = usb_disk_transfer_data(device, true, status, 504 sizeof(usb_massbulk_command_status_wrapper)); 505 if (result != B_OK) 506 return result; 507 508 if (device->status != B_OK 509 || device->actual_length 510 != sizeof(usb_massbulk_command_status_wrapper)) { 511 // receiving the command status wrapper failed 512 return B_ERROR; 513 } 514 515 return B_OK; 516 } 517 518 519 status_t 520 usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, 521 uint32 logicalBlockAddress, uint16 transferLength, void *data, 522 size_t *dataLength, bool directionIn, err_act *_action) 523 { 524 TRACE("operation: lun: %u; op: %u; oplen: %u; lba: %" B_PRIu32 525 "; tlen: %u; data: %p; dlen: %p (%lu); in: %c\n", 526 lun->logical_unit_number, operation, opLength, logicalBlockAddress, 527 transferLength, data, dataLength, dataLength ? *dataLength : 0, 528 directionIn ? 'y' : 'n'); 529 530 disk_device *device = lun->device; 531 usb_massbulk_command_block_wrapper command; 532 command.signature = USB_MASSBULK_CBW_SIGNATURE; 533 command.tag = device->current_tag++; 534 command.data_transfer_length = (dataLength != NULL ? *dataLength : 0); 535 command.flags = (directionIn ? USB_MASSBULK_CBW_DATA_INPUT 536 : USB_MASSBULK_CBW_DATA_OUTPUT); 537 command.lun = lun->logical_unit_number; 538 command.command_block_length 539 = device->is_atapi ? ATAPI_COMMAND_LENGTH : opLength; 540 memset(command.command_block, 0, sizeof(command.command_block)); 541 542 switch (opLength) { 543 case 6: 544 { 545 scsi_command_6 *commandBlock 546 = (scsi_command_6 *)command.command_block; 547 commandBlock->operation = operation; 548 commandBlock->lun = lun->logical_unit_number << 5; 549 commandBlock->allocation_length = (uint8)transferLength; 550 if (operation == SCSI_MODE_SENSE_6) { 551 // we hijack the lba argument to transport the desired page 552 commandBlock->reserved[1] = (uint8)logicalBlockAddress; 553 } 554 break; 555 } 556 557 case 10: 558 { 559 scsi_command_10 *commandBlock 560 = (scsi_command_10 *)command.command_block; 561 commandBlock->operation = operation; 562 commandBlock->lun_flags = lun->logical_unit_number << 5; 563 commandBlock->logical_block_address = htonl(logicalBlockAddress); 564 commandBlock->transfer_length = htons(transferLength); 565 break; 566 } 567 568 default: 569 TRACE_ALWAYS("unsupported operation length %d\n", opLength); 570 return B_BAD_VALUE; 571 } 572 573 status_t result = usb_disk_transfer_data(device, false, &command, 574 sizeof(usb_massbulk_command_block_wrapper)); 575 if (result != B_OK) 576 return result; 577 578 if (device->status != B_OK || 579 device->actual_length != sizeof(usb_massbulk_command_block_wrapper)) { 580 // sending the command block wrapper failed 581 TRACE_ALWAYS("sending the command block wrapper failed: %s\n", 582 strerror(device->status)); 583 usb_disk_reset_recovery(device); 584 return B_ERROR; 585 } 586 587 size_t transferedData = 0; 588 if (data != NULL && dataLength != NULL && *dataLength > 0) { 589 // we have data to transfer in a data stage 590 result = usb_disk_transfer_data(device, directionIn, data, 591 *dataLength); 592 if (result != B_OK) 593 return result; 594 595 transferedData = device->actual_length; 596 if (device->status != B_OK || transferedData != *dataLength) { 597 // sending or receiving of the data failed 598 if (device->status == B_DEV_STALLED) { 599 TRACE("stall while transfering data\n"); 600 gUSBModule->clear_feature(directionIn ? device->bulk_in 601 : device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 602 } else { 603 TRACE_ALWAYS("sending or receiving of the data failed: %s\n", 604 strerror(device->status)); 605 usb_disk_reset_recovery(device); 606 return B_ERROR; 607 } 608 } 609 } 610 611 usb_massbulk_command_status_wrapper status; 612 result = usb_disk_receive_csw(device, &status); 613 if (result != B_OK) { 614 // in case of a stall or error clear the stall and try again 615 gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); 616 result = usb_disk_receive_csw(device, &status); 617 } 618 619 if (result != B_OK) { 620 TRACE_ALWAYS("receiving the command status wrapper failed: %s\n", 621 strerror(result)); 622 usb_disk_reset_recovery(device); 623 return result; 624 } 625 626 if (status.signature != USB_MASSBULK_CSW_SIGNATURE 627 || status.tag != command.tag) { 628 // the command status wrapper is not valid 629 TRACE_ALWAYS("command status wrapper is not valid: %#" B_PRIx32 "\n", 630 status.signature); 631 usb_disk_reset_recovery(device); 632 return B_ERROR; 633 } 634 635 switch (status.status) { 636 case USB_MASSBULK_CSW_STATUS_COMMAND_PASSED: 637 case USB_MASSBULK_CSW_STATUS_COMMAND_FAILED: 638 { 639 // The residue from "status.data_residue" is not maintained 640 // correctly by some devices, so calculate it instead. 641 uint32 residue = command.data_transfer_length - transferedData; 642 643 if (dataLength != NULL) { 644 *dataLength -= residue; 645 if (transferedData < *dataLength) { 646 TRACE_ALWAYS("less data transfered than indicated: %" 647 B_PRIuSIZE " vs. %" B_PRIuSIZE "\n", transferedData, 648 *dataLength); 649 *dataLength = transferedData; 650 } 651 } 652 653 if (status.status == USB_MASSBULK_CSW_STATUS_COMMAND_PASSED) { 654 // the operation is complete and has succeeded 655 return B_OK; 656 } else { 657 if (operation == SCSI_REQUEST_SENSE_6) 658 return B_ERROR; 659 660 // the operation is complete but has failed at the SCSI level 661 if (operation != SCSI_TEST_UNIT_READY_6) { 662 TRACE_ALWAYS("operation %#" B_PRIx8 663 " failed at the SCSI level\n", operation); 664 } 665 666 result = usb_disk_request_sense(lun, _action); 667 return result == B_OK ? B_ERROR : result; 668 } 669 } 670 671 case USB_MASSBULK_CSW_STATUS_PHASE_ERROR: 672 { 673 // a protocol or device error occured 674 TRACE_ALWAYS("phase error in operation %#" B_PRIx8 "\n", operation); 675 usb_disk_reset_recovery(device); 676 return B_ERROR; 677 } 678 679 default: 680 { 681 // command status wrapper is not meaningful 682 TRACE_ALWAYS("command status wrapper has invalid status\n"); 683 usb_disk_reset_recovery(device); 684 return B_ERROR; 685 } 686 } 687 } 688 689 690 // 691 //#pragma mark - Helper/Convenience Functions 692 // 693 694 695 status_t 696 usb_disk_request_sense(device_lun *lun, err_act *_action) 697 { 698 size_t dataLength = sizeof(scsi_request_sense_6_parameter); 699 scsi_request_sense_6_parameter parameter; 700 status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0, 701 dataLength, ¶meter, &dataLength, true); 702 if (result != B_OK) { 703 TRACE_ALWAYS("getting request sense data failed: %s\n", 704 strerror(result)); 705 return result; 706 } 707 708 const char *label = NULL; 709 err_act action = err_act_fail; 710 status_t status = B_ERROR; 711 scsi_get_sense_asc_info((parameter.additional_sense_code << 8) 712 | parameter.additional_sense_code_qualifier, &label, &action, 713 &status); 714 715 if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY 716 && parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) { 717 TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: " 718 "0x%02x; %s\n", parameter.sense_key, parameter.additional_sense_code, 719 parameter.additional_sense_code_qualifier, 720 label ? label : "(unknown)"); 721 } 722 723 if ((parameter.additional_sense_code == 0 724 && parameter.additional_sense_code_qualifier == 0) 725 || label == NULL) { 726 scsi_get_sense_key_info(parameter.sense_key, &label, &action, &status); 727 } 728 729 if (status == B_DEV_MEDIA_CHANGED) { 730 lun->media_changed = true; 731 lun->media_present = true; 732 } else if (parameter.sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION 733 && status != B_DEV_NO_MEDIA) { 734 lun->media_present = true; 735 } else if (status == B_DEV_NOT_READY) { 736 lun->media_present = false; 737 usb_disk_reset_capacity(lun); 738 } 739 740 if (_action != NULL) 741 *_action = action; 742 743 return status; 744 } 745 746 747 status_t 748 usb_disk_mode_sense(device_lun *lun) 749 { 750 size_t dataLength = sizeof(scsi_mode_sense_6_parameter); 751 scsi_mode_sense_6_parameter parameter; 752 status_t result = usb_disk_operation(lun, SCSI_MODE_SENSE_6, 6, 753 SCSI_MODE_PAGE_DEVICE_CONFIGURATION, dataLength, ¶meter, 754 &dataLength, true); 755 if (result != B_OK) { 756 TRACE_ALWAYS("getting mode sense data failed: %s\n", strerror(result)); 757 return result; 758 } 759 760 lun->write_protected 761 = (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT) 762 != 0; 763 TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no"); 764 return B_OK; 765 } 766 767 768 status_t 769 usb_disk_test_unit_ready(device_lun *lun, err_act *_action) 770 { 771 // if unsupported we assume the unit is fixed and therefore always ok 772 if (!lun->device->tur_supported) 773 return B_OK; 774 775 status_t result; 776 if (lun->device->is_atapi) { 777 result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 1, 778 NULL, NULL, false, _action); 779 } else { 780 result = usb_disk_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0, 781 NULL, NULL, true, _action); 782 } 783 784 if (result == B_DEV_INVALID_IOCTL) { 785 lun->device->tur_supported = false; 786 return B_OK; 787 } 788 789 return result; 790 } 791 792 793 status_t 794 usb_disk_inquiry(device_lun *lun) 795 { 796 size_t dataLength = sizeof(scsi_inquiry_6_parameter); 797 scsi_inquiry_6_parameter parameter; 798 status_t result = B_ERROR; 799 err_act action = err_act_ok; 800 for (uint32 tries = 0; tries < 3; tries++) { 801 result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength, 802 ¶meter, &dataLength, true, &action); 803 if (result == B_OK || (action != err_act_retry 804 && action != err_act_many_retries)) { 805 break; 806 } 807 } 808 if (result != B_OK) { 809 TRACE_ALWAYS("getting inquiry data failed: %s\n", strerror(result)); 810 lun->device_type = B_DISK; 811 lun->removable = true; 812 return result; 813 } 814 815 TRACE("peripherial_device_type 0x%02x\n", 816 parameter.peripherial_device_type); 817 TRACE("peripherial_qualifier 0x%02x\n", 818 parameter.peripherial_qualifier); 819 TRACE("removable_medium %s\n", 820 parameter.removable_medium ? "yes" : "no"); 821 TRACE("version 0x%02x\n", parameter.version); 822 TRACE("response_data_format 0x%02x\n", parameter.response_data_format); 823 TRACE_ALWAYS("vendor_identification \"%.8s\"\n", 824 parameter.vendor_identification); 825 TRACE_ALWAYS("product_identification \"%.16s\"\n", 826 parameter.product_identification); 827 TRACE_ALWAYS("product_revision_level \"%.4s\"\n", 828 parameter.product_revision_level); 829 830 memcpy(lun->vendor_name, parameter.vendor_identification, 831 MIN(sizeof(lun->vendor_name), sizeof(parameter.vendor_identification))); 832 memcpy(lun->product_name, parameter.product_identification, 833 MIN(sizeof(lun->product_name), 834 sizeof(parameter.product_identification))); 835 memcpy(lun->product_revision, parameter.product_revision_level, 836 MIN(sizeof(lun->product_revision), 837 sizeof(parameter.product_revision_level))); 838 839 lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ 840 lun->removable = (parameter.removable_medium == 1); 841 return B_OK; 842 } 843 844 845 status_t 846 usb_disk_reset_capacity(device_lun *lun) 847 { 848 lun->block_size = 512; 849 lun->block_count = 0; 850 return B_OK; 851 } 852 853 854 status_t 855 usb_disk_update_capacity(device_lun *lun) 856 { 857 size_t dataLength = sizeof(scsi_read_capacity_10_parameter); 858 scsi_read_capacity_10_parameter parameter; 859 status_t result = B_ERROR; 860 err_act action = err_act_ok; 861 862 // Retry reading the capacity up to three times. The first try might only 863 // yield a unit attention telling us that the device or media status 864 // changed, which is more or less expected if it is the first operation 865 // on the device or the device only clears the unit atention for capacity 866 // reads. 867 for (int32 i = 0; i < 3; i++) { 868 result = usb_disk_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0, 869 ¶meter, &dataLength, true, &action); 870 if (result == B_OK || (action != err_act_retry 871 && action != err_act_many_retries)) { 872 break; 873 } 874 } 875 876 if (result != B_OK) { 877 TRACE_ALWAYS("failed to update capacity: %s\n", strerror(result)); 878 lun->media_present = false; 879 lun->media_changed = false; 880 usb_disk_reset_capacity(lun); 881 return result; 882 } 883 884 lun->media_present = true; 885 lun->media_changed = false; 886 lun->block_size = ntohl(parameter.logical_block_length); 887 lun->block_count = ntohl(parameter.last_logical_block_address) + 1; 888 return B_OK; 889 } 890 891 892 status_t 893 usb_disk_synchronize(device_lun *lun, bool force) 894 { 895 if (lun->device->sync_support == 0) { 896 // this device reported an illegal request when syncing or repeatedly 897 // returned an other error, it apparently does not support syncing... 898 return B_UNSUPPORTED; 899 } 900 901 if (!lun->should_sync && !force) 902 return B_OK; 903 904 status_t result = usb_disk_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 10, 905 0, 0, NULL, NULL, false); 906 907 if (result == B_OK) { 908 lun->device->sync_support = SYNC_SUPPORT_RELOAD; 909 lun->should_sync = false; 910 return B_OK; 911 } 912 913 if (result == B_DEV_INVALID_IOCTL) 914 lun->device->sync_support = 0; 915 else 916 lun->device->sync_support--; 917 918 return result; 919 } 920 921 922 // 923 //#pragma mark - Device Attach/Detach Notifications and Callback 924 // 925 926 927 static void 928 usb_disk_callback(void *cookie, status_t status, void *data, 929 size_t actualLength) 930 { 931 //TRACE("callback()\n"); 932 disk_device *device = (disk_device *)cookie; 933 device->status = status; 934 device->actual_length = actualLength; 935 release_sem(device->notify); 936 } 937 938 939 static status_t 940 usb_disk_device_added(usb_device newDevice, void **cookie) 941 { 942 TRACE("device_added(0x%08" B_PRIx32 ")\n", newDevice); 943 disk_device *device = (disk_device *)malloc(sizeof(disk_device)); 944 device->device = newDevice; 945 device->removed = false; 946 device->open_count = 0; 947 device->interface = 0xff; 948 device->current_tag = 0; 949 device->sync_support = SYNC_SUPPORT_RELOAD; 950 device->tur_supported = true; 951 device->is_atapi = false; 952 device->luns = NULL; 953 954 // scan through the interfaces to find our bulk-only data interface 955 const usb_configuration_info *configuration 956 = gUSBModule->get_configuration(newDevice); 957 if (configuration == NULL) { 958 free(device); 959 return B_ERROR; 960 } 961 962 for (size_t i = 0; i < configuration->interface_count; i++) { 963 usb_interface_info *interface = configuration->interface[i].active; 964 if (interface == NULL) 965 continue; 966 967 if (interface->descr->interface_class == USB_MASS_STORAGE_DEVICE_CLASS 968 && (interface->descr->interface_subclass == 0x06 /* SCSI */ 969 || interface->descr->interface_subclass == 0x02 /* ATAPI */ 970 || interface->descr->interface_subclass == 0x05 /* ATAPI */) 971 && interface->descr->interface_protocol == 0x50 /* bulk-only */) { 972 973 bool hasIn = false; 974 bool hasOut = false; 975 for (size_t j = 0; j < interface->endpoint_count; j++) { 976 usb_endpoint_info *endpoint = &interface->endpoint[j]; 977 if (endpoint == NULL 978 || endpoint->descr->attributes != USB_ENDPOINT_ATTR_BULK) 979 continue; 980 981 if (!hasIn && (endpoint->descr->endpoint_address 982 & USB_ENDPOINT_ADDR_DIR_IN) != 0) { 983 device->bulk_in = endpoint->handle; 984 hasIn = true; 985 } else if (!hasOut && (endpoint->descr->endpoint_address 986 & USB_ENDPOINT_ADDR_DIR_IN) == 0) { 987 device->bulk_out = endpoint->handle; 988 hasOut = true; 989 } 990 991 if (hasIn && hasOut) 992 break; 993 } 994 995 if (!(hasIn && hasOut)) 996 continue; 997 998 device->interface = interface->descr->interface_number; 999 device->is_atapi = interface->descr->interface_subclass != 0x06; 1000 break; 1001 } 1002 } 1003 1004 if (device->interface == 0xff) { 1005 TRACE_ALWAYS("no valid bulk-only interface found\n"); 1006 free(device); 1007 return B_ERROR; 1008 } 1009 1010 mutex_init(&device->lock, "usb_disk device lock"); 1011 1012 device->notify = create_sem(0, "usb_disk callback notify"); 1013 if (device->notify < B_OK) { 1014 mutex_destroy(&device->lock); 1015 status_t result = device->notify; 1016 free(device); 1017 return result; 1018 } 1019 1020 device->lun_count = usb_disk_get_max_lun(device) + 1; 1021 device->luns = (device_lun **)malloc(device->lun_count 1022 * sizeof(device_lun *)); 1023 for (uint8 i = 0; i < device->lun_count; i++) 1024 device->luns[i] = NULL; 1025 1026 status_t result = B_OK; 1027 1028 TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count); 1029 for (uint8 i = 0; i < device->lun_count; i++) { 1030 // create the individual luns present on this device 1031 device_lun *lun = (device_lun *)malloc(sizeof(device_lun)); 1032 if (lun == NULL) { 1033 result = B_NO_MEMORY; 1034 break; 1035 } 1036 1037 device->luns[i] = lun; 1038 lun->device = device; 1039 lun->logical_unit_number = i; 1040 lun->should_sync = false; 1041 lun->media_present = true; 1042 lun->media_changed = true; 1043 1044 memset(lun->vendor_name, 0, sizeof(lun->vendor_name)); 1045 memset(lun->product_name, 0, sizeof(lun->product_name)); 1046 memset(lun->product_revision, 0, sizeof(lun->product_revision)); 1047 1048 usb_disk_reset_capacity(lun); 1049 1050 // initialize this lun 1051 result = usb_disk_inquiry(lun); 1052 err_act action = err_act_ok; 1053 for (uint32 tries = 0; tries < 8; tries++) { 1054 TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " begin\n", 1055 i, tries); 1056 status_t ready = usb_disk_test_unit_ready(lun, &action); 1057 if (ready == B_OK || ready == B_DEV_NO_MEDIA 1058 || ready == B_DEV_MEDIA_CHANGED) { 1059 if (lun->device_type == B_CD) 1060 lun->write_protected = true; 1061 // TODO: check for write protection; disabled since some 1062 // devices lock up when getting the mode sense 1063 else if (/*usb_disk_mode_sense(lun) != B_OK*/true) 1064 lun->write_protected = false; 1065 1066 TRACE("usb lun %" B_PRIu8 " ready. write protected = %c%s\n", i, 1067 lun->write_protected ? 'y' : 'n', 1068 ready == B_DEV_NO_MEDIA ? " (no media inserted)" : ""); 1069 1070 break; 1071 } 1072 TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " failed\n", 1073 i, tries); 1074 if (action != err_act_retry && action != err_act_many_retries) 1075 break; 1076 bigtime_t snoozeTime = 1000000 * tries; 1077 TRACE("snoozing %" B_PRIu64 " microseconds for usb lun\n", 1078 snoozeTime); 1079 snooze(snoozeTime); 1080 } 1081 1082 if (result != B_OK) 1083 break; 1084 } 1085 1086 if (result != B_OK) { 1087 TRACE_ALWAYS("failed to initialize logical units: %s\n", 1088 strerror(result)); 1089 usb_disk_free_device_and_luns(device); 1090 return result; 1091 } 1092 1093 mutex_lock(&gDeviceListLock); 1094 device->device_number = 0; 1095 disk_device *other = gDeviceList; 1096 while (other != NULL) { 1097 if (other->device_number >= device->device_number) 1098 device->device_number = other->device_number + 1; 1099 1100 other = (disk_device *)other->link; 1101 } 1102 1103 device->link = (void *)gDeviceList; 1104 gDeviceList = device; 1105 gLunCount += device->lun_count; 1106 for (uint8 i = 0; i < device->lun_count; i++) 1107 sprintf(device->luns[i]->name, DEVICE_NAME, device->device_number, i); 1108 mutex_unlock(&gDeviceListLock); 1109 1110 TRACE("new device: 0x%p\n", device); 1111 *cookie = (void *)device; 1112 return B_OK; 1113 } 1114 1115 1116 static status_t 1117 usb_disk_device_removed(void *cookie) 1118 { 1119 TRACE("device_removed(0x%p)\n", cookie); 1120 disk_device *device = (disk_device *)cookie; 1121 1122 mutex_lock(&gDeviceListLock); 1123 if (gDeviceList == device) { 1124 gDeviceList = (disk_device *)device->link; 1125 } else { 1126 disk_device *element = gDeviceList; 1127 while (element) { 1128 if (element->link == device) { 1129 element->link = device->link; 1130 break; 1131 } 1132 1133 element = (disk_device *)element->link; 1134 } 1135 } 1136 gLunCount -= device->lun_count; 1137 gDeviceCount--; 1138 1139 device->removed = true; 1140 gUSBModule->cancel_queued_transfers(device->bulk_in); 1141 gUSBModule->cancel_queued_transfers(device->bulk_out); 1142 if (device->open_count == 0) 1143 usb_disk_free_device_and_luns(device); 1144 1145 mutex_unlock(&gDeviceListLock); 1146 return B_OK; 1147 } 1148 1149 1150 // 1151 //#pragma mark - Partial Buffer Functions 1152 // 1153 1154 1155 static bool 1156 usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length, 1157 uint32 &blockPosition, uint16 &blockCount) 1158 { 1159 blockPosition = (uint32)(position / lun->block_size); 1160 if ((off_t)blockPosition * lun->block_size != position) 1161 return true; 1162 1163 blockCount = (uint16)(length / lun->block_size); 1164 if ((size_t)blockCount * lun->block_size != length) 1165 return true; 1166 1167 return false; 1168 } 1169 1170 1171 static status_t 1172 usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, 1173 void *buffer, size_t *length) 1174 { 1175 status_t result = usb_disk_operation(lun, SCSI_READ_10, 10, blockPosition, 1176 blockCount, buffer, length, true); 1177 return result; 1178 } 1179 1180 1181 static status_t 1182 usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, 1183 void *buffer, size_t *length) 1184 { 1185 status_t result = usb_disk_operation(lun, SCSI_WRITE_10, 10, blockPosition, 1186 blockCount, buffer, length, false); 1187 if (result == B_OK) 1188 lun->should_sync = true; 1189 return result; 1190 } 1191 1192 1193 static status_t 1194 usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length, 1195 void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition, 1196 uint16 &blockCount) 1197 { 1198 blockPosition = (uint32)(position / lun->block_size); 1199 blockCount = (uint16)((uint32)((position + length + lun->block_size - 1) 1200 / lun->block_size) - blockPosition); 1201 size_t blockLength = blockCount * lun->block_size; 1202 blockBuffer = malloc(blockLength); 1203 if (blockBuffer == NULL) { 1204 TRACE_ALWAYS("no memory to allocate partial buffer\n"); 1205 return B_NO_MEMORY; 1206 } 1207 1208 status_t result = usb_disk_block_read(lun, blockPosition, blockCount, 1209 blockBuffer, &blockLength); 1210 if (result != B_OK) { 1211 TRACE_ALWAYS("block read failed when filling partial buffer: %s\n", 1212 strerror(result)); 1213 free(blockBuffer); 1214 return result; 1215 } 1216 1217 off_t offset = position - (off_t)blockPosition * lun->block_size; 1218 partialBuffer = (uint8 *)blockBuffer + offset; 1219 return B_OK; 1220 } 1221 1222 1223 // 1224 //#pragma mark - Driver Hooks 1225 // 1226 1227 1228 static status_t 1229 usb_disk_open(const char *name, uint32 flags, void **cookie) 1230 { 1231 TRACE("open(%s)\n", name); 1232 if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0) 1233 return B_NAME_NOT_FOUND; 1234 1235 int32 lastPart = 0; 1236 size_t nameLength = strlen(name); 1237 for (int32 i = nameLength - 1; i >= 0; i--) { 1238 if (name[i] == '/') { 1239 lastPart = i; 1240 break; 1241 } 1242 } 1243 1244 char rawName[nameLength + 4]; 1245 strncpy(rawName, name, lastPart + 1); 1246 rawName[lastPart + 1] = 0; 1247 strcat(rawName, "raw"); 1248 TRACE("opening raw device %s for %s\n", rawName, name); 1249 1250 mutex_lock(&gDeviceListLock); 1251 disk_device *device = gDeviceList; 1252 while (device) { 1253 for (uint8 i = 0; i < device->lun_count; i++) { 1254 device_lun *lun = device->luns[i]; 1255 if (strncmp(rawName, lun->name, 32) == 0) { 1256 // found the matching device/lun 1257 if (device->removed) { 1258 mutex_unlock(&gDeviceListLock); 1259 return B_ERROR; 1260 } 1261 1262 device->open_count++; 1263 *cookie = lun; 1264 mutex_unlock(&gDeviceListLock); 1265 return B_OK; 1266 } 1267 } 1268 1269 device = (disk_device *)device->link; 1270 } 1271 1272 mutex_unlock(&gDeviceListLock); 1273 return B_NAME_NOT_FOUND; 1274 } 1275 1276 1277 static status_t 1278 usb_disk_close(void *cookie) 1279 { 1280 TRACE("close()\n"); 1281 device_lun *lun = (device_lun *)cookie; 1282 disk_device *device = lun->device; 1283 1284 mutex_lock(&device->lock); 1285 if (!device->removed) 1286 usb_disk_synchronize(lun, false); 1287 mutex_unlock(&device->lock); 1288 1289 return B_OK; 1290 } 1291 1292 1293 static status_t 1294 usb_disk_free(void *cookie) 1295 { 1296 TRACE("free()\n"); 1297 mutex_lock(&gDeviceListLock); 1298 1299 device_lun *lun = (device_lun *)cookie; 1300 disk_device *device = lun->device; 1301 device->open_count--; 1302 if (device->open_count == 0 && device->removed) { 1303 // we can simply free the device here as it has been removed from 1304 // the device list in the device removed notification hook 1305 usb_disk_free_device_and_luns(device); 1306 } 1307 1308 mutex_unlock(&gDeviceListLock); 1309 return B_OK; 1310 } 1311 1312 1313 static inline void 1314 normalize_name(char *name, size_t nameLength) 1315 { 1316 bool wasSpace = false; 1317 size_t insertIndex = 0; 1318 for (size_t i = 0; i < nameLength; i++) { 1319 bool isSpace = name[i] == ' '; 1320 if (isSpace && wasSpace) 1321 continue; 1322 1323 name[insertIndex++] = name[i]; 1324 wasSpace = isSpace; 1325 } 1326 1327 if (insertIndex > 0 && name[insertIndex - 1] == ' ') 1328 insertIndex--; 1329 1330 name[insertIndex] = 0; 1331 } 1332 1333 1334 static status_t 1335 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) 1336 { 1337 device_lun *lun = (device_lun *)cookie; 1338 disk_device *device = lun->device; 1339 mutex_lock(&device->lock); 1340 if (device->removed) { 1341 mutex_unlock(&device->lock); 1342 return B_DEV_NOT_READY; 1343 } 1344 1345 status_t result = B_DEV_INVALID_IOCTL; 1346 switch (op) { 1347 case B_GET_MEDIA_STATUS: 1348 { 1349 err_act action = err_act_ok; 1350 for (uint32 tries = 0; tries < 3; tries++) { 1351 status_t ready = usb_disk_test_unit_ready(lun, &action); 1352 if (ready == B_OK || ready == B_DEV_NO_MEDIA 1353 || (action != err_act_retry 1354 && action != err_act_many_retries)) { 1355 *(status_t *)buffer = ready; 1356 break; 1357 } 1358 snooze(500000); 1359 } 1360 TRACE("B_GET_MEDIA_STATUS: 0x%08" B_PRIx32 "\n", 1361 *(status_t *)buffer); 1362 result = B_OK; 1363 break; 1364 } 1365 1366 case B_GET_GEOMETRY: 1367 { 1368 if (lun->media_changed) { 1369 result = usb_disk_update_capacity(lun); 1370 if (result != B_OK) 1371 break; 1372 } 1373 1374 device_geometry geometry; 1375 devfs_compute_geometry_size(&geometry, lun->block_count, 1376 lun->block_size); 1377 1378 geometry.device_type = lun->device_type; 1379 geometry.removable = lun->removable; 1380 geometry.read_only = lun->write_protected; 1381 geometry.write_once = lun->device_type == B_WORM; 1382 TRACE("B_GET_GEOMETRY: %" B_PRId32 " sectors at %" B_PRId32 1383 " bytes per sector\n", geometry.cylinder_count, 1384 geometry.bytes_per_sector); 1385 result = user_memcpy(buffer, &geometry, sizeof(device_geometry)); 1386 break; 1387 } 1388 1389 case B_FLUSH_DRIVE_CACHE: 1390 TRACE("B_FLUSH_DRIVE_CACHE\n"); 1391 result = usb_disk_synchronize(lun, true); 1392 break; 1393 1394 case B_EJECT_DEVICE: 1395 result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 2, 1396 NULL, NULL, false); 1397 break; 1398 1399 case B_LOAD_MEDIA: 1400 result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 3, 1401 NULL, NULL, false); 1402 break; 1403 1404 #if HAIKU_TARGET_PLATFORM_HAIKU 1405 case B_GET_ICON: 1406 // We don't support this legacy ioctl anymore, but the two other 1407 // icon ioctls below instead. 1408 break; 1409 1410 case B_GET_ICON_NAME: 1411 { 1412 const char *iconName = "devices/drive-removable-media-usb"; 1413 char vendor[sizeof(lun->vendor_name)+1]; 1414 char product[sizeof(lun->product_name)+1]; 1415 1416 switch (lun->device_type) { 1417 case B_CD: 1418 case B_OPTICAL: 1419 iconName = "devices/drive-optical"; 1420 break; 1421 case B_TAPE: // TODO 1422 default: 1423 snprintf(vendor, sizeof(vendor), "%.8s", 1424 lun->vendor_name); 1425 snprintf(product, sizeof(product), "%.16s", 1426 lun->product_name); 1427 for (int i = 0; kIconMatches[i].icon; i++) { 1428 if (kIconMatches[i].vendor != NULL 1429 && strstr(vendor, kIconMatches[i].vendor) == NULL) 1430 continue; 1431 if (kIconMatches[i].product != NULL 1432 && strstr(product, kIconMatches[i].product) == NULL) 1433 continue; 1434 iconName = kIconMatches[i].name; 1435 } 1436 break; 1437 } 1438 result = user_strlcpy((char *)buffer, iconName, 1439 B_FILE_NAME_LENGTH); 1440 break; 1441 } 1442 1443 case B_GET_VECTOR_ICON: 1444 { 1445 device_icon *icon = &kKeyIconData; 1446 char vendor[sizeof(lun->vendor_name)+1]; 1447 char product[sizeof(lun->product_name)+1]; 1448 1449 if (length != sizeof(device_icon)) { 1450 result = B_BAD_VALUE; 1451 break; 1452 } 1453 1454 switch (lun->device_type) { 1455 case B_CD: 1456 case B_OPTICAL: 1457 icon = &kCDIconData; 1458 break; 1459 case B_TAPE: // TODO 1460 default: 1461 snprintf(vendor, sizeof(vendor), "%.8s", 1462 lun->vendor_name); 1463 snprintf(product, sizeof(product), "%.16s", 1464 lun->product_name); 1465 for (int i = 0; kIconMatches[i].icon; i++) { 1466 if (kIconMatches[i].vendor != NULL 1467 && strstr(vendor, kIconMatches[i].vendor) == NULL) 1468 continue; 1469 if (kIconMatches[i].product != NULL 1470 && strstr(product, kIconMatches[i].product) == NULL) 1471 continue; 1472 icon = kIconMatches[i].icon; 1473 } 1474 break; 1475 } 1476 1477 device_icon iconData; 1478 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) { 1479 result = B_BAD_ADDRESS; 1480 break; 1481 } 1482 1483 if (iconData.icon_size >= icon->icon_size) { 1484 if (user_memcpy(iconData.icon_data, icon->icon_data, 1485 (size_t)icon->icon_size) != B_OK) { 1486 result = B_BAD_ADDRESS; 1487 break; 1488 } 1489 } 1490 1491 iconData.icon_size = icon->icon_size; 1492 result = user_memcpy(buffer, &iconData, sizeof(device_icon)); 1493 break; 1494 } 1495 1496 case B_GET_DEVICE_NAME: 1497 { 1498 size_t nameLength = sizeof(lun->vendor_name) 1499 + sizeof(lun->product_name) + sizeof(lun->product_revision) + 3; 1500 1501 char name[nameLength]; 1502 snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name, 1503 lun->product_name, lun->product_revision); 1504 1505 normalize_name(name, nameLength); 1506 1507 result = user_strlcpy((char *)buffer, name, length); 1508 if (result > 0) 1509 result = B_OK; 1510 1511 TRACE_ALWAYS("got device name \"%s\": %s\n", name, 1512 strerror(result)); 1513 break; 1514 } 1515 #endif 1516 1517 default: 1518 TRACE_ALWAYS("unhandled ioctl %" B_PRId32 "\n", op); 1519 break; 1520 } 1521 1522 mutex_unlock(&device->lock); 1523 return result; 1524 } 1525 1526 1527 static status_t 1528 usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) 1529 { 1530 if (buffer == NULL || length == NULL) 1531 return B_BAD_VALUE; 1532 1533 TRACE("read(%" B_PRIdOFF ", %ld)\n", position, *length); 1534 device_lun *lun = (device_lun *)cookie; 1535 disk_device *device = lun->device; 1536 mutex_lock(&device->lock); 1537 if (device->removed) { 1538 *length = 0; 1539 mutex_unlock(&device->lock); 1540 return B_DEV_NOT_READY; 1541 } 1542 1543 status_t result = B_ERROR; 1544 uint32 blockPosition = 0; 1545 uint16 blockCount = 0; 1546 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length, 1547 blockPosition, blockCount); 1548 if (needsPartial) { 1549 void *partialBuffer = NULL; 1550 void *blockBuffer = NULL; 1551 result = usb_disk_prepare_partial_buffer(lun, position, *length, 1552 partialBuffer, blockBuffer, blockPosition, blockCount); 1553 if (result == B_OK) { 1554 memcpy(buffer, partialBuffer, *length); 1555 free(blockBuffer); 1556 } 1557 } else { 1558 result = usb_disk_block_read(lun, blockPosition, blockCount, buffer, 1559 length); 1560 } 1561 1562 mutex_unlock(&device->lock); 1563 if (result == B_OK) { 1564 TRACE("read successful with %ld bytes\n", *length); 1565 return B_OK; 1566 } 1567 1568 *length = 0; 1569 TRACE_ALWAYS("read failed: %s\n", strerror(result)); 1570 return result; 1571 } 1572 1573 1574 static status_t 1575 usb_disk_write(void *cookie, off_t position, const void *buffer, 1576 size_t *length) 1577 { 1578 if (buffer == NULL || length == NULL) 1579 return B_BAD_VALUE; 1580 1581 TRACE("write(%" B_PRIdOFF", %ld)\n", position, *length); 1582 device_lun *lun = (device_lun *)cookie; 1583 disk_device *device = lun->device; 1584 mutex_lock(&device->lock); 1585 if (device->removed) { 1586 *length = 0; 1587 mutex_unlock(&device->lock); 1588 return B_DEV_NOT_READY; 1589 } 1590 1591 status_t result = B_ERROR; 1592 uint32 blockPosition = 0; 1593 uint16 blockCount = 0; 1594 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, 1595 *length, blockPosition, blockCount); 1596 if (needsPartial) { 1597 void *partialBuffer = NULL; 1598 void *blockBuffer = NULL; 1599 result = usb_disk_prepare_partial_buffer(lun, position, *length, 1600 partialBuffer, blockBuffer, blockPosition, blockCount); 1601 if (result == B_OK) { 1602 memcpy(partialBuffer, buffer, *length); 1603 size_t blockLength = blockCount * lun->block_size; 1604 result = usb_disk_block_write(lun, blockPosition, blockCount, 1605 blockBuffer, &blockLength); 1606 free(blockBuffer); 1607 } 1608 } else { 1609 result = usb_disk_block_write(lun, blockPosition, blockCount, 1610 (void *)buffer, length); 1611 } 1612 1613 mutex_unlock(&device->lock); 1614 if (result == B_OK) { 1615 TRACE("write successful with %ld bytes\n", *length); 1616 return B_OK; 1617 } 1618 1619 *length = 0; 1620 TRACE_ALWAYS("write failed: %s\n", strerror(result)); 1621 return result; 1622 } 1623 1624 1625 // 1626 //#pragma mark - Driver Entry Points 1627 // 1628 1629 1630 status_t 1631 init_hardware() 1632 { 1633 TRACE("init_hardware()\n"); 1634 return B_OK; 1635 } 1636 1637 1638 status_t 1639 init_driver() 1640 { 1641 TRACE("init_driver()\n"); 1642 static usb_notify_hooks notifyHooks = { 1643 &usb_disk_device_added, 1644 &usb_disk_device_removed 1645 }; 1646 1647 static usb_support_descriptor supportedDevices[] = { 1648 { 0x08 /* mass storage */, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 }, 1649 { 0x08 /* mass storage */, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 }, 1650 { 0x08 /* mass storage */, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 } 1651 }; 1652 1653 gDeviceList = NULL; 1654 gDeviceCount = 0; 1655 gLunCount = 0; 1656 mutex_init(&gDeviceListLock, "usb_disk device list lock"); 1657 1658 TRACE("trying module %s\n", B_USB_MODULE_NAME); 1659 status_t result = get_module(B_USB_MODULE_NAME, 1660 (module_info **)&gUSBModule); 1661 if (result < B_OK) { 1662 TRACE_ALWAYS("getting module failed: %s\n", strerror(result)); 1663 mutex_destroy(&gDeviceListLock); 1664 return result; 1665 } 1666 1667 gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 3, NULL); 1668 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 1669 return B_OK; 1670 } 1671 1672 1673 void 1674 uninit_driver() 1675 { 1676 TRACE("uninit_driver()\n"); 1677 gUSBModule->uninstall_notify(DRIVER_NAME); 1678 mutex_lock(&gDeviceListLock); 1679 1680 if (gDeviceNames) { 1681 for (int32 i = 0; gDeviceNames[i]; i++) 1682 free(gDeviceNames[i]); 1683 free(gDeviceNames); 1684 gDeviceNames = NULL; 1685 } 1686 1687 mutex_destroy(&gDeviceListLock); 1688 put_module(B_USB_MODULE_NAME); 1689 } 1690 1691 1692 const char ** 1693 publish_devices() 1694 { 1695 TRACE("publish_devices()\n"); 1696 if (gDeviceNames) { 1697 for (int32 i = 0; gDeviceNames[i]; i++) 1698 free(gDeviceNames[i]); 1699 free(gDeviceNames); 1700 gDeviceNames = NULL; 1701 } 1702 1703 gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1)); 1704 if (gDeviceNames == NULL) 1705 return NULL; 1706 1707 int32 index = 0; 1708 mutex_lock(&gDeviceListLock); 1709 disk_device *device = gDeviceList; 1710 while (device) { 1711 for (uint8 i = 0; i < device->lun_count; i++) 1712 gDeviceNames[index++] = strdup(device->luns[i]->name); 1713 1714 device = (disk_device *)device->link; 1715 } 1716 1717 gDeviceNames[index++] = NULL; 1718 mutex_unlock(&gDeviceListLock); 1719 return (const char **)gDeviceNames; 1720 } 1721 1722 1723 device_hooks * 1724 find_device(const char *name) 1725 { 1726 TRACE("find_device()\n"); 1727 static device_hooks hooks = { 1728 &usb_disk_open, 1729 &usb_disk_close, 1730 &usb_disk_free, 1731 &usb_disk_ioctl, 1732 &usb_disk_read, 1733 &usb_disk_write, 1734 NULL, 1735 NULL, 1736 NULL, 1737 NULL 1738 }; 1739 1740 return &hooks; 1741 } 1742