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 const unsigned char kZipIcon[] = { 342 0x6e, 0x63, 0x69, 0x66, 0x0d, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 343 0x00, 0x6a, 0x02, 0x00, 0x06, 0x02, 0x38, 0x6a, 0xad, 0x38, 0xeb, 0x7a, 344 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, 0x75, 0xed, 345 0x00, 0x1e, 0x31, 0x8d, 0xff, 0x27, 0x29, 0x91, 0x02, 0x00, 0x06, 0x02, 346 0x38, 0x6a, 0xad, 0x38, 0xeb, 0x7a, 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 347 0x48, 0xce, 0xdc, 0x4a, 0x75, 0xed, 0x00, 0x8a, 0x8a, 0x8a, 0xff, 0x0f, 348 0x0d, 0x7a, 0x05, 0x7d, 0x02, 0x00, 0x06, 0x02, 0x39, 0xc6, 0x30, 0x36, 349 0xa8, 0x1b, 0xb9, 0x51, 0xe6, 0x3c, 0x5b, 0xb3, 0x4b, 0x4d, 0xa8, 0x4a, 350 0x1a, 0xa1, 0x00, 0x16, 0x34, 0x77, 0xff, 0x23, 0x23, 0x84, 0x02, 0x00, 351 0x06, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, 0x07, 0xb9, 352 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x01, 0x15, 0x37, 0xca, 353 0xfe, 0x5e, 0x5e, 0xf8, 0x02, 0x00, 0x06, 0x02, 0xb7, 0x16, 0xa4, 0xba, 354 0x87, 0xfe, 0x3c, 0xb2, 0x07, 0xb9, 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 355 0x1e, 0x62, 0x00, 0x24, 0x36, 0x95, 0xfe, 0x17, 0x14, 0x80, 0x02, 0x00, 356 0x16, 0x05, 0x36, 0xef, 0x60, 0x38, 0xe2, 0xe5, 0xbd, 0x22, 0x41, 0x3b, 357 0x2f, 0xce, 0x4a, 0x0e, 0x78, 0x4a, 0x5a, 0x6c, 0x00, 0xb8, 0x38, 0xe6, 358 0x77, 0xb8, 0xbd, 0xd2, 0xff, 0x93, 0x02, 0x00, 0x16, 0x05, 0x34, 0x0a, 359 0x8f, 0x38, 0xd2, 0xa2, 0xba, 0xb4, 0xc5, 0x35, 0xe9, 0xec, 0x49, 0xfd, 360 0x24, 0x4a, 0x64, 0x62, 0x00, 0xe1, 0x38, 0xff, 0x75, 0xd7, 0xba, 0xf3, 361 0xfd, 0xd0, 0x02, 0x00, 0x16, 0x02, 0x36, 0x67, 0xbe, 0x39, 0xdd, 0xbc, 362 0xbe, 0x50, 0x04, 0x3a, 0xe0, 0x9f, 0x4b, 0x85, 0x01, 0x49, 0x2a, 0x3f, 363 0x00, 0xff, 0xff, 0xd8, 0x03, 0x38, 0x6d, 0xbe, 0x02, 0x00, 0x16, 0x02, 364 0x3c, 0x40, 0xef, 0x3b, 0x82, 0xd1, 0xba, 0xeb, 0x42, 0x3b, 0xbf, 0x4d, 365 0x4a, 0xa7, 0xce, 0x49, 0x5d, 0xc1, 0xff, 0x01, 0x00, 0x4a, 0x12, 0x0a, 366 0x05, 0x44, 0x5a, 0x44, 0x40, 0x5e, 0x40, 0x5f, 0x45, 0x49, 0x5a, 0x0a, 367 0x06, 0x45, 0x58, 0x5c, 0x42, 0x5c, 0x40, 0x3d, 0x34, 0xb5, 0x6b, 0xc2, 368 0x2e, 0xb5, 0x63, 0xc3, 0xbb, 0x0a, 0x04, 0x44, 0x58, 0x26, 0x4a, 0x26, 369 0x47, 0x44, 0x54, 0x0a, 0x04, 0x44, 0x59, 0x5c, 0x42, 0x5c, 0x3e, 0x44, 370 0x54, 0x0a, 0x05, 0x44, 0x56, 0x5c, 0x40, 0x3d, 0x34, 0xb5, 0x6b, 0xc2, 371 0x2e, 0xb5, 0x43, 0xc3, 0x3b, 0x0a, 0x04, 0x2a, 0x4c, 0x3f, 0x56, 0x3f, 372 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x2a, 0x4b, 0x39, 0x52, 0x39, 0x50, 0x2a, 373 0x4a, 0x0a, 0x04, 0x31, 0x42, 0x45, 0x4c, 0x3f, 0x53, 0x2a, 0x4a, 0x0a, 374 0x04, 0x3f, 0x49, 0x38, 0x50, 0x2a, 0x4a, 0x31, 0x43, 0x0a, 0x04, 0x3f, 375 0x36, 0x57, 0x3e, 0x49, 0x4b, 0x32, 0x40, 0x08, 0x02, 0x3c, 0x3b, 0x4d, 376 0x43, 0x00, 0x02, 0x3b, 0x3b, 0x31, 0x36, 0x43, 0x3f, 0x48, 0x3d, 0x3f, 377 0x36, 0xc4, 0x82, 0xbf, 0xc7, 0x00, 0x02, 0x3e, 0x3c, 0xbc, 0x58, 0xbd, 378 0x93, 0x47, 0x3e, 0x45, 0x44, 0x3d, 0x43, 0x4d, 0x45, 0x02, 0x04, 0x39, 379 0x3b, 0x39, 0x3d, 0x39, 0x39, 0x3c, 0x38, 0x3b, 0x38, 0x3e, 0x38, 0x3e, 380 0x3a, 0x3f, 0x3a, 0x41, 0x37, 0x3c, 0x3d, 0x3c, 0x42, 0x3c, 0x40, 0x02, 381 0x04, 0x46, 0x3c, 0x46, 0x3e, 0x46, 0x3a, 0x48, 0x3a, 0x46, 0x3a, 0x4a, 382 0x3a, 0x4a, 0x3c, 0x4a, 0x3a, 0x4a, 0x3e, 0x48, 0x3e, 0x4a, 0x3e, 0x46, 383 0x3e, 0x0a, 0x04, 0x45, 0x42, 0x42, 0x45, 0x45, 0x47, 0x48, 0x44, 0x0a, 384 0x03, 0x4e, 0x43, 0x4d, 0x3f, 0x48, 0x44, 0x0a, 0x04, 0x32, 0x4b, 0x36, 385 0x48, 0x32, 0x46, 0x2e, 0x4a, 0x0d, 0x0a, 0x01, 0x01, 0x00, 0x20, 0x1e, 386 0x20, 0x0a, 0x00, 0x01, 0x01, 0x30, 0x1e, 0x20, 0x01, 0x17, 0x84, 0x00, 387 0x04, 0x0a, 0x02, 0x01, 0x02, 0x20, 0x1e, 0x20, 0x0a, 0x05, 0x01, 0x03, 388 0x20, 0x1e, 0x20, 0x0a, 0x06, 0x01, 0x04, 0x20, 0x1e, 0x20, 0x0a, 0x03, 389 0x01, 0x05, 0x20, 0x1e, 0x20, 0x0a, 0x07, 0x01, 0x07, 0x20, 0x1e, 0x20, 390 0x0a, 0x08, 0x01, 0x06, 0x20, 0x1e, 0x20, 0x0a, 0x09, 0x01, 0x08, 0x20, 391 0x1e, 0x20, 0x0a, 0x0a, 0x01, 0x09, 0x20, 0x1e, 0x20, 0x0a, 0x0c, 0x03, 392 0x0a, 0x0b, 0x0c, 0x1a, 0x40, 0x1d, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 393 0x00, 0x3f, 0x9d, 0xc9, 0xc2, 0x91, 0x98, 0x43, 0x6d, 0xc2, 0x20, 0xff, 394 0x01, 0x17, 0x81, 0x00, 0x04, 0x0a, 0x0c, 0x04, 0x0d, 0x0e, 0x0f, 0x10, 395 0x0a, 0x3f, 0xff, 0xbd, 0x34, 0xaf, 0xbc, 0xb4, 0xe0, 0x2c, 0x3f, 0xbc, 396 0x62, 0x3e, 0x74, 0x62, 0x41, 0xfe, 0xe7, 0x20, 0xff, 0x0a, 0x02, 0x01, 397 0x11, 0x20, 0x1e, 0x20 398 }; 399 400 401 static const uint8 kFloppyIcon[] = { 402 0x6e, 0x63, 0x69, 0x66, 0x0d, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 403 0x00, 0x6a, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, 0xeb, 0x7a, 404 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, 0x75, 0xed, 405 0x00, 0x7a, 0xff, 0x4b, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, 406 0xeb, 0x7a, 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, 407 0x75, 0xed, 0x00, 0x8a, 0xff, 0x2c, 0x05, 0x7d, 0x02, 0x00, 0x16, 0x02, 408 0x39, 0xc6, 0x30, 0x36, 0xa8, 0x1b, 0xb9, 0x51, 0xe6, 0x3c, 0x5b, 0xb3, 409 0x4b, 0x4d, 0xa8, 0x4a, 0x1a, 0xa1, 0x00, 0x3a, 0xff, 0x5d, 0x02, 0x00, 410 0x16, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, 0x07, 0xb9, 411 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x01, 0x75, 0xfe, 0xc4, 412 0x02, 0x00, 0x16, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, 413 0x07, 0xb9, 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x00, 0x5c, 414 0xfe, 0x9b, 0x02, 0x00, 0x16, 0x05, 0x36, 0xef, 0x60, 0x38, 0xe2, 0xe5, 415 0xbd, 0x22, 0x41, 0x3b, 0x2f, 0xce, 0x4a, 0x0e, 0x78, 0x4a, 0x5a, 0x6c, 416 0x00, 0xb8, 0x38, 0xe6, 0x77, 0xb8, 0xbd, 0xd2, 0xff, 0x93, 0x02, 0x00, 417 0x16, 0x05, 0x34, 0x0a, 0x8f, 0x38, 0xd2, 0xa2, 0xba, 0xb4, 0xc5, 0x35, 418 0xe9, 0xec, 0x49, 0xfd, 0x24, 0x4a, 0x64, 0x62, 0x00, 0xe1, 0x38, 0xff, 419 0x75, 0xd7, 0xba, 0xf3, 0xfd, 0xd0, 0x02, 0x00, 0x16, 0x02, 0x36, 0x67, 420 0xbe, 0x39, 0xdd, 0xbc, 0xbe, 0x50, 0x04, 0x3a, 0xe0, 0x9f, 0x4b, 0x85, 421 0x01, 0x49, 0x2a, 0x3f, 0x00, 0xff, 0xff, 0xd8, 0x03, 0x38, 0x6d, 0xbe, 422 0x02, 0x00, 0x16, 0x02, 0x3c, 0x40, 0xef, 0x3b, 0x82, 0xd1, 0xba, 0xeb, 423 0x42, 0x3b, 0xbf, 0x4d, 0x4a, 0xa7, 0xce, 0x49, 0x5d, 0xc1, 0xff, 0x01, 424 0x00, 0x4a, 0x12, 0x0a, 0x05, 0x44, 0x5a, 0x44, 0x40, 0x5e, 0x40, 0x5f, 425 0x45, 0x49, 0x5a, 0x0a, 0x06, 0x45, 0x58, 0x5c, 0x42, 0x5c, 0x40, 0x3d, 426 0x34, 0xb5, 0x6b, 0xc2, 0x2e, 0xb5, 0x63, 0xc3, 0xbb, 0x0a, 0x04, 0x44, 427 0x58, 0x26, 0x4a, 0x26, 0x47, 0x44, 0x54, 0x0a, 0x04, 0x44, 0x59, 0x5c, 428 0x42, 0x5c, 0x3e, 0x44, 0x54, 0x0a, 0x05, 0x44, 0x56, 0x5c, 0x40, 0x3d, 429 0x34, 0xb5, 0x6b, 0xc2, 0x2e, 0xb5, 0x43, 0xc3, 0x3b, 0x0a, 0x04, 0x2a, 430 0x4c, 0x3f, 0x56, 0x3f, 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x2a, 0x4b, 0x39, 431 0x52, 0x39, 0x50, 0x2a, 0x4a, 0x0a, 0x04, 0x31, 0x42, 0x45, 0x4c, 0x3f, 432 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x3f, 0x49, 0x38, 0x50, 0x2a, 0x4a, 0x31, 433 0x43, 0x0a, 0x04, 0x3f, 0x36, 0x57, 0x3e, 0x49, 0x4b, 0x32, 0x40, 0x08, 434 0x02, 0x3c, 0x3b, 0x4d, 0x43, 0x00, 0x02, 0x3b, 0x3b, 0x31, 0x36, 0x43, 435 0x3f, 0x48, 0x3d, 0x3f, 0x36, 0xc4, 0x82, 0xbf, 0xc7, 0x00, 0x02, 0x3e, 436 0x3c, 0xbc, 0x58, 0xbd, 0x93, 0x47, 0x3e, 0x45, 0x44, 0x3d, 0x43, 0x4d, 437 0x45, 0x02, 0x04, 0x39, 0x3b, 0x39, 0x3d, 0x39, 0x39, 0x3c, 0x38, 0x3b, 438 0x38, 0x3e, 0x38, 0x3e, 0x3a, 0x3f, 0x3a, 0x41, 0x37, 0x3c, 0x3d, 0x3c, 439 0x42, 0x3c, 0x40, 0x02, 0x04, 0x46, 0x3c, 0x46, 0x3e, 0x46, 0x3a, 0x48, 440 0x3a, 0x46, 0x3a, 0x4a, 0x3a, 0x4a, 0x3c, 0x4a, 0x3a, 0x4a, 0x3e, 0x48, 441 0x3e, 0x4a, 0x3e, 0x46, 0x3e, 0x0a, 0x04, 0x45, 0x42, 0x42, 0x45, 0x45, 442 0x47, 0x48, 0x44, 0x0a, 0x03, 0x4e, 0x43, 0x4d, 0x3f, 0x48, 0x44, 0x0a, 443 0x04, 0x32, 0x4b, 0x36, 0x48, 0x32, 0x46, 0x2e, 0x4a, 0x0d, 0x0a, 0x01, 444 0x01, 0x00, 0x20, 0x1e, 0x20, 0x0a, 0x00, 0x01, 0x01, 0x30, 0x1e, 0x20, 445 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x02, 0x01, 0x02, 0x20, 0x1e, 0x20, 446 0x0a, 0x05, 0x01, 0x03, 0x20, 0x1e, 0x20, 0x0a, 0x06, 0x01, 0x04, 0x20, 447 0x1e, 0x20, 0x0a, 0x03, 0x01, 0x05, 0x20, 0x1e, 0x20, 0x0a, 0x07, 0x01, 448 0x07, 0x20, 0x1e, 0x20, 0x0a, 0x08, 0x01, 0x06, 0x20, 0x1e, 0x20, 0x0a, 449 0x09, 0x01, 0x08, 0x20, 0x1e, 0x20, 0x0a, 0x0a, 0x01, 0x09, 0x20, 0x1e, 450 0x20, 0x0a, 0x0c, 0x03, 0x0a, 0x0b, 0x0c, 0x1a, 0x40, 0x1d, 0x05, 0x00, 451 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9d, 0xc9, 0xc2, 0x91, 0x98, 0x43, 452 0x6d, 0xc2, 0x20, 0xff, 0x01, 0x17, 0x81, 0x00, 0x04, 0x0a, 0x0c, 0x04, 453 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x3f, 0xff, 0xbd, 0x34, 0xaf, 0xbc, 0xb4, 454 0xe0, 0x2c, 0x3f, 0xbc, 0x62, 0x3e, 0x74, 0x62, 0x41, 0xfe, 0xe7, 0x20, 455 0xff, 0x0a, 0x02, 0x01, 0x11, 0x20, 0x1e, 0x20 456 }; 457 458 device_icon kKeyIconData = { (int32)sizeof(kDeviceIcon), (void *)kDeviceIcon }; 459 device_icon kCDIconData = { (int32)sizeof(kCDIcon), (void *)kCDIcon }; 460 device_icon kMSIconData = { (int32)sizeof(kMemoryStickIcon), 461 (void *)kMemoryStickIcon }; 462 device_icon kSDIconData = { (int32)sizeof(kSDIcon), (void *)kSDIcon }; 463 device_icon kMobileIconData = { (int32)sizeof(kMobileIcon), 464 (void *)kMobileIcon }; 465 device_icon kFloppyIconData = { (int32)sizeof(kFloppyIcon), 466 (void *)kFloppyIcon }; 467 468 469 struct { 470 const char *vendor; 471 const char *product; 472 device_icon *icon; 473 const char *name; 474 } kIconMatches[] = { 475 // matches for Hama USB 2.0 Card Reader 35 in 1 476 // vendor: "Transcend Information, Inc." 477 // product: "63-in-1 Multi-Card Reader/Writer" ver. 0100 478 // which report things like "Generic " "USB CF Reader " 479 // { NULL, " CF Reader", &kCFIconData, "devices/drive-removable-media-flash" }, 480 { NULL, " SD Reader", &kSDIconData, "devices/drive-removable-media-flash" }, 481 { NULL, " MS Reader", &kMSIconData, "devices/drive-removable-media-flash" }, 482 // { NULL, " SM Reader", &kSMIconData, "devices/drive-removable-media-flash" }, 483 // match for my Kazam mobile phone 484 // stupid thing says "MEDIATEK" " FLASH DISK " even for internal memory 485 { "MEDIATEK", NULL, &kMobileIconData, 486 "devices/drive-removable-media-flash" }, 487 { NULL, NULL, NULL, NULL } 488 }; 489 490 491 // 492 //#pragma mark - Forward Declarations 493 // 494 495 496 static void usb_disk_callback(void *cookie, status_t status, void *data, 497 size_t actualLength); 498 499 status_t usb_disk_mass_storage_reset(disk_device *device); 500 uint8 usb_disk_get_max_lun(disk_device *device); 501 void usb_disk_reset_recovery(disk_device *device); 502 status_t usb_disk_transfer_data(disk_device *device, bool directionIn, 503 void *data, size_t dataLength); 504 status_t usb_disk_receive_csw(disk_device *device, 505 usb_massbulk_command_status_wrapper *status); 506 status_t usb_disk_operation(device_lun *lun, uint8* operation, 507 size_t opLength, void *data, size_t *dataLength, 508 bool directionIn, err_act *action = NULL); 509 510 status_t usb_disk_send_diagnostic(device_lun *lun); 511 status_t usb_disk_request_sense(device_lun *lun, err_act *action); 512 status_t usb_disk_mode_sense(device_lun *lun); 513 status_t usb_disk_test_unit_ready(device_lun *lun, err_act *action = NULL); 514 status_t usb_disk_inquiry(device_lun *lun); 515 status_t usb_disk_reset_capacity(device_lun *lun); 516 status_t usb_disk_update_capacity(device_lun *lun); 517 status_t usb_disk_synchronize(device_lun *lun, bool force); 518 519 520 // 521 //#pragma mark - Device Allocation Helper Functions 522 // 523 524 525 void 526 usb_disk_free_device_and_luns(disk_device *device) 527 { 528 mutex_lock(&device->lock); 529 mutex_destroy(&device->lock); 530 delete_sem(device->notify); 531 delete_sem(device->interruptLock); 532 for (uint8 i = 0; i < device->lun_count; i++) 533 free(device->luns[i]); 534 free(device->luns); 535 free(device); 536 } 537 538 539 // 540 //#pragma mark - Bulk-only Mass Storage Functions 541 // 542 543 544 status_t 545 usb_disk_mass_storage_reset(disk_device *device) 546 { 547 return gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_OUT 548 | USB_REQTYPE_CLASS, USB_MASSBULK_REQUEST_MASS_STORAGE_RESET, 0x0000, 549 device->interface, 0, NULL, NULL); 550 } 551 552 553 uint8 554 usb_disk_get_max_lun(disk_device *device) 555 { 556 uint8 result = 0; 557 size_t actualLength = 0; 558 559 // devices that do not support multiple LUNs may stall this request 560 if (gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_IN 561 | USB_REQTYPE_CLASS, USB_MASSBULK_REQUEST_GET_MAX_LUN, 0x0000, 562 device->interface, 1, &result, &actualLength) != B_OK 563 || actualLength != 1) { 564 return 0; 565 } 566 567 if (result > MAX_LOGICAL_UNIT_NUMBER) { 568 // invalid max lun 569 return 0; 570 } 571 572 return result; 573 } 574 575 576 void 577 usb_disk_reset_recovery(disk_device *device) 578 { 579 usb_disk_mass_storage_reset(device); 580 gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); 581 gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 582 if (device->is_ufi) 583 gUSBModule->clear_feature(device->interrupt, USB_FEATURE_ENDPOINT_HALT); 584 } 585 586 587 status_t 588 usb_disk_transfer_data(disk_device *device, bool directionIn, void *data, 589 size_t dataLength) 590 { 591 status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in 592 : device->bulk_out, data, dataLength, usb_disk_callback, device); 593 if (result != B_OK) { 594 TRACE_ALWAYS("failed to queue data transfer: %s\n", strerror(result)); 595 return result; 596 } 597 598 do { 599 result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 600 10 * 1000 * 1000); 601 if (result == B_TIMED_OUT) { 602 // Cancel the transfer and collect the sem that should now be 603 // released through the callback on cancel. Handling of device 604 // reset is done in usb_disk_operation() when it detects that 605 // the transfer failed. 606 gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in 607 : device->bulk_out); 608 acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0); 609 } 610 } while (result == B_INTERRUPTED); 611 612 if (result != B_OK) { 613 TRACE_ALWAYS("acquire_sem failed while waiting for data transfer: %s\n", 614 strerror(result)); 615 return result; 616 } 617 618 return B_OK; 619 } 620 621 622 void 623 usb_disk_interrupt(void* cookie, int32 status, void* data, size_t length) 624 { 625 disk_device* device = (disk_device*)cookie; 626 // We release the lock even if the interrupt is invalid. This way there 627 // is at least a chance for the driver to terminate properly. 628 release_sem(device->interruptLock); 629 630 if (length != 2) { 631 TRACE_ALWAYS("interrupt of length %" B_PRIuSIZE "! (expected 2)\n", 632 length); 633 // In this case we do not reschedule the interrupt. This means the 634 // driver will be locked. The interrupt should perhaps be scheduled 635 // when starting a transfer instead. But getting there means something 636 // is really broken, so... 637 return; 638 } 639 640 // Reschedule the interrupt for next time 641 gUSBModule->queue_interrupt(device->interrupt, device->interruptBuffer, 2, 642 usb_disk_interrupt, cookie); 643 } 644 645 646 status_t 647 usb_disk_receive_csw_interrupt(disk_device *device, 648 interrupt_status_wrapper *status) 649 { 650 TRACE("Waiting for result...\n"); 651 gUSBModule->queue_interrupt(device->interrupt, 652 device->interruptBuffer, 2, usb_disk_interrupt, device); 653 654 acquire_sem(device->interruptLock); 655 656 status->status = device->interruptBuffer[0]; 657 status->misc = device->interruptBuffer[1]; 658 659 return B_OK; 660 } 661 662 status_t 663 usb_disk_receive_csw_bulk(disk_device *device, 664 usb_massbulk_command_status_wrapper *status) 665 { 666 status_t result = usb_disk_transfer_data(device, true, status, 667 sizeof(usb_massbulk_command_status_wrapper)); 668 if (result != B_OK) 669 return result; 670 671 if (device->status != B_OK 672 || device->actual_length 673 != sizeof(usb_massbulk_command_status_wrapper)) { 674 // receiving the command status wrapper failed 675 return B_ERROR; 676 } 677 678 return B_OK; 679 } 680 681 682 status_t 683 usb_disk_operation_interrupt(device_lun *lun, uint8* operation, 684 void *data, size_t *dataLength, bool directionIn, err_act *_action) 685 { 686 TRACE("operation: lun: %u; op: 0x%x; data: %p; dlen: %p (%lu); in: %c\n", 687 lun->logical_unit_number, operation[0], data, dataLength, 688 dataLength ? *dataLength : 0, directionIn ? 'y' : 'n'); 689 690 disk_device* device = lun->device; 691 692 // Step 1 : send the SCSI operation as a class specific request 693 size_t actualLength = 12; 694 status_t result = gUSBModule->send_request(device->device, 695 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, 0 /*request*/, 696 0/*value*/, device->interface/*index*/, 12, operation, &actualLength); 697 698 if (result != B_OK || actualLength != 12) { 699 TRACE("Command stage: wrote %ld bytes (error: %s)\n", 700 actualLength, strerror(result)); 701 702 // There was an error, we have to do a request sense to reset the device 703 if (operation[0] != SCSI_REQUEST_SENSE_6) { 704 usb_disk_request_sense(lun, _action); 705 } 706 return result; 707 } 708 709 // Step 2 : data phase : send or receive data 710 size_t transferedData = 0; 711 if (data != NULL && dataLength != NULL && *dataLength > 0) { 712 // we have data to transfer in a data stage 713 result = usb_disk_transfer_data(device, directionIn, data, *dataLength); 714 if (result != B_OK) { 715 TRACE("Error %s in data phase\n", strerror(result)); 716 return result; 717 } 718 719 transferedData = device->actual_length; 720 if (device->status != B_OK || transferedData != *dataLength) { 721 // sending or receiving of the data failed 722 if (device->status == B_DEV_STALLED) { 723 TRACE("stall while transfering data\n"); 724 gUSBModule->clear_feature(directionIn ? device->bulk_in 725 : device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 726 } else { 727 TRACE_ALWAYS("sending or receiving of the data failed\n"); 728 usb_disk_reset_recovery(device); 729 return B_ERROR; 730 } 731 } 732 } 733 734 // step 3 : wait for the device to send the interrupt ACK 735 if (operation[0] != SCSI_REQUEST_SENSE_6) { 736 interrupt_status_wrapper status; 737 result = usb_disk_receive_csw_interrupt(device, &status); 738 if (result != B_OK) { 739 // in case of a stall or error clear the stall and try again 740 TRACE("Error receiving interrupt: %s. Retrying...\n", 741 strerror(result)); 742 gUSBModule->clear_feature(device->bulk_in, 743 USB_FEATURE_ENDPOINT_HALT); 744 result = usb_disk_receive_csw_interrupt(device, &status); 745 } 746 747 if (result != B_OK) { 748 TRACE_ALWAYS("receiving the command status interrupt failed\n"); 749 usb_disk_reset_recovery(device); 750 return result; 751 } 752 753 // wait for the device to finish the operation. 754 result = usb_disk_request_sense(lun, _action); 755 } 756 return result; 757 } 758 759 760 status_t 761 usb_disk_operation_bulk(device_lun *lun, uint8* operation, 762 size_t operationLength, void *data, size_t *dataLength, bool directionIn, 763 err_act *_action) 764 { 765 TRACE("operation: lun: %u; op: %u; data: %p; dlen: %p (%lu); in: %c\n", 766 lun->logical_unit_number, operation[0], 767 data, dataLength, dataLength ? *dataLength : 0, 768 directionIn ? 'y' : 'n'); 769 770 disk_device *device = lun->device; 771 usb_massbulk_command_block_wrapper command; 772 command.signature = USB_MASSBULK_CBW_SIGNATURE; 773 command.tag = device->current_tag++; 774 command.data_transfer_length = (dataLength != NULL ? *dataLength : 0); 775 command.flags = (directionIn ? USB_MASSBULK_CBW_DATA_INPUT 776 : USB_MASSBULK_CBW_DATA_OUTPUT); 777 command.lun = lun->logical_unit_number; 778 command.command_block_length 779 = device->is_atapi ? ATAPI_COMMAND_LENGTH : operationLength; 780 memset(command.command_block, 0, sizeof(command.command_block)); 781 memcpy(command.command_block, operation, operationLength); 782 783 status_t result = usb_disk_transfer_data(device, false, &command, 784 sizeof(usb_massbulk_command_block_wrapper)); 785 if (result != B_OK) 786 return result; 787 788 if (device->status != B_OK || 789 device->actual_length != sizeof(usb_massbulk_command_block_wrapper)) { 790 // sending the command block wrapper failed 791 TRACE_ALWAYS("sending the command block wrapper failed: %s\n", 792 strerror(device->status)); 793 usb_disk_reset_recovery(device); 794 return B_ERROR; 795 } 796 797 size_t transferedData = 0; 798 if (data != NULL && dataLength != NULL && *dataLength > 0) { 799 // we have data to transfer in a data stage 800 result = usb_disk_transfer_data(device, directionIn, data, 801 *dataLength); 802 if (result != B_OK) 803 return result; 804 805 transferedData = device->actual_length; 806 if (device->status != B_OK || transferedData != *dataLength) { 807 // sending or receiving of the data failed 808 if (device->status == B_DEV_STALLED) { 809 TRACE("stall while transfering data\n"); 810 gUSBModule->clear_feature(directionIn ? device->bulk_in 811 : device->bulk_out, USB_FEATURE_ENDPOINT_HALT); 812 } else { 813 TRACE_ALWAYS("sending or receiving of the data failed: %s\n", 814 strerror(device->status)); 815 usb_disk_reset_recovery(device); 816 return B_ERROR; 817 } 818 } 819 } 820 821 usb_massbulk_command_status_wrapper status; 822 result = usb_disk_receive_csw_bulk(device, &status); 823 if (result != B_OK) { 824 // in case of a stall or error clear the stall and try again 825 gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); 826 result = usb_disk_receive_csw_bulk(device, &status); 827 } 828 829 if (result != B_OK) { 830 TRACE_ALWAYS("receiving the command status wrapper failed: %s\n", 831 strerror(result)); 832 usb_disk_reset_recovery(device); 833 return result; 834 } 835 836 if (status.signature != USB_MASSBULK_CSW_SIGNATURE 837 || status.tag != command.tag) { 838 // the command status wrapper is not valid 839 TRACE_ALWAYS("command status wrapper is not valid: %#" B_PRIx32 "\n", 840 status.signature); 841 usb_disk_reset_recovery(device); 842 return B_ERROR; 843 } 844 845 switch (status.status) { 846 case USB_MASSBULK_CSW_STATUS_COMMAND_PASSED: 847 case USB_MASSBULK_CSW_STATUS_COMMAND_FAILED: 848 { 849 // The residue from "status.data_residue" is not maintained 850 // correctly by some devices, so calculate it instead. 851 uint32 residue = command.data_transfer_length - transferedData; 852 853 if (dataLength != NULL) { 854 *dataLength -= residue; 855 if (transferedData < *dataLength) { 856 TRACE_ALWAYS("less data transfered than indicated: %" 857 B_PRIuSIZE " vs. %" B_PRIuSIZE "\n", transferedData, 858 *dataLength); 859 *dataLength = transferedData; 860 } 861 } 862 863 if (status.status == USB_MASSBULK_CSW_STATUS_COMMAND_PASSED) { 864 // the operation is complete and has succeeded 865 return B_OK; 866 } else { 867 if (operation[0] == SCSI_REQUEST_SENSE_6) 868 return B_ERROR; 869 870 // the operation is complete but has failed at the SCSI level 871 if (operation[0] != SCSI_TEST_UNIT_READY_6) { 872 TRACE_ALWAYS("operation %#" B_PRIx8 873 " failed at the SCSI level\n", operation[0]); 874 } 875 876 result = usb_disk_request_sense(lun, _action); 877 return result == B_OK ? B_ERROR : result; 878 } 879 } 880 881 case USB_MASSBULK_CSW_STATUS_PHASE_ERROR: 882 { 883 // a protocol or device error occured 884 TRACE_ALWAYS("phase error in operation %#" B_PRIx8 "\n", 885 operation[0]); 886 usb_disk_reset_recovery(device); 887 return B_ERROR; 888 } 889 890 default: 891 { 892 // command status wrapper is not meaningful 893 TRACE_ALWAYS("command status wrapper has invalid status\n"); 894 usb_disk_reset_recovery(device); 895 return B_ERROR; 896 } 897 } 898 } 899 900 901 status_t 902 usb_disk_operation(device_lun *lun, uint8* operation, size_t opLength, 903 void *data, size_t *dataLength, bool directionIn, err_act *_action) 904 { 905 if (lun->device->is_ufi) { 906 return usb_disk_operation_interrupt(lun, operation, data, dataLength, 907 directionIn, _action); 908 } else { 909 return usb_disk_operation_bulk(lun, operation, opLength, 910 data, dataLength, directionIn, _action); 911 } 912 } 913 914 915 // 916 //#pragma mark - Helper/Convenience Functions 917 // 918 919 920 status_t 921 usb_disk_send_diagnostic(device_lun *lun) 922 { 923 uint8 commandBlock[12]; 924 memset(commandBlock, 0, sizeof(commandBlock)); 925 926 commandBlock[0] = SCSI_SEND_DIAGNOSTIC; 927 commandBlock[1] = (lun->logical_unit_number << 5) | 4; 928 929 status_t result = usb_disk_operation(lun, commandBlock, 6, NULL, 930 NULL, false); 931 932 int retry = 100; 933 err_act action = err_act_ok; 934 while(result == B_DEV_NO_MEDIA && retry > 0) { 935 snooze(10000); 936 result = usb_disk_request_sense(lun, &action); 937 retry--; 938 } 939 940 if (result != B_OK) 941 TRACE("Send Diagnostic failed: %s\n", strerror(result)); 942 return result; 943 } 944 945 946 status_t 947 usb_disk_request_sense(device_lun *lun, err_act *_action) 948 { 949 size_t dataLength = sizeof(scsi_request_sense_6_parameter); 950 uint8 commandBlock[12]; 951 memset(commandBlock, 0, sizeof(commandBlock)); 952 953 commandBlock[0] = SCSI_REQUEST_SENSE_6; 954 commandBlock[1] = lun->logical_unit_number << 5; 955 commandBlock[2] = 0; // page code 956 commandBlock[4] = dataLength; 957 958 scsi_request_sense_6_parameter parameter; 959 status_t result = B_ERROR; 960 for (uint32 tries = 0; tries < 3; tries++) { 961 result = usb_disk_operation(lun, commandBlock, 6, ¶meter, 962 &dataLength, true); 963 if (result != B_TIMED_OUT) 964 break; 965 snooze(100000); 966 } 967 if (result != B_OK) { 968 TRACE_ALWAYS("getting request sense data failed: %s\n", 969 strerror(result)); 970 return result; 971 } 972 973 const char *label = NULL; 974 err_act action = err_act_fail; 975 status_t status = B_ERROR; 976 scsi_get_sense_asc_info((parameter.additional_sense_code << 8) 977 | parameter.additional_sense_code_qualifier, &label, &action, 978 &status); 979 980 if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY 981 && parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) { 982 TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: " 983 "0x%02x; %s\n", parameter.sense_key, 984 parameter.additional_sense_code, 985 parameter.additional_sense_code_qualifier, 986 label ? label : "(unknown)"); 987 } 988 989 if ((parameter.additional_sense_code == 0 990 && parameter.additional_sense_code_qualifier == 0) 991 || label == NULL) { 992 scsi_get_sense_key_info(parameter.sense_key, &label, &action, &status); 993 } 994 995 if (status == B_DEV_MEDIA_CHANGED) { 996 lun->media_changed = true; 997 lun->media_present = true; 998 } else if (parameter.sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION 999 && status != B_DEV_NO_MEDIA) { 1000 lun->media_present = true; 1001 } else if (status == B_DEV_NOT_READY) { 1002 lun->media_present = false; 1003 usb_disk_reset_capacity(lun); 1004 } 1005 1006 if (_action != NULL) 1007 *_action = action; 1008 1009 return status; 1010 } 1011 1012 1013 status_t 1014 usb_disk_mode_sense(device_lun *lun) 1015 { 1016 size_t dataLength = sizeof(scsi_mode_sense_6_parameter); 1017 1018 uint8 commandBlock[12]; 1019 memset(commandBlock, 0, sizeof(commandBlock)); 1020 1021 commandBlock[0] = SCSI_MODE_SENSE_6; 1022 commandBlock[1] = SCSI_MODE_PAGE_DEVICE_CONFIGURATION; 1023 commandBlock[2] = 0; // Current values 1024 commandBlock[3] = dataLength >> 8; 1025 commandBlock[4] = dataLength; 1026 1027 scsi_mode_sense_6_parameter parameter; 1028 status_t result = usb_disk_operation(lun, commandBlock, 6, 1029 ¶meter, &dataLength, true); 1030 if (result != B_OK) { 1031 TRACE_ALWAYS("getting mode sense data failed: %s\n", strerror(result)); 1032 return result; 1033 } 1034 1035 lun->write_protected 1036 = (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT) 1037 != 0; 1038 TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no"); 1039 return B_OK; 1040 } 1041 1042 1043 status_t 1044 usb_disk_test_unit_ready(device_lun *lun, err_act *_action) 1045 { 1046 // if unsupported we assume the unit is fixed and therefore always ok 1047 if (lun->device->is_ufi || !lun->device->tur_supported) 1048 return B_OK; 1049 1050 status_t result = B_OK; 1051 uint8 commandBlock[12]; 1052 memset(commandBlock, 0, sizeof(commandBlock)); 1053 1054 if (lun->device->is_atapi) { 1055 commandBlock[0] = SCSI_START_STOP_UNIT_6; 1056 commandBlock[1] = lun->logical_unit_number << 5; 1057 commandBlock[2] = 0; 1058 commandBlock[3] = 0; 1059 commandBlock[4] = 1; 1060 1061 result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, false, 1062 _action); 1063 } else { 1064 commandBlock[0] = SCSI_TEST_UNIT_READY_6; 1065 commandBlock[1] = lun->logical_unit_number << 5; 1066 commandBlock[2] = 0; 1067 commandBlock[3] = 0; 1068 commandBlock[4] = 0; 1069 result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, true, 1070 _action); 1071 } 1072 1073 if (result == B_DEV_INVALID_IOCTL) { 1074 lun->device->tur_supported = false; 1075 return B_OK; 1076 } 1077 1078 return result; 1079 } 1080 1081 1082 status_t 1083 usb_disk_inquiry(device_lun *lun) 1084 { 1085 size_t dataLength = sizeof(scsi_inquiry_6_parameter); 1086 1087 uint8 commandBlock[12]; 1088 memset(commandBlock, 0, sizeof(commandBlock)); 1089 1090 commandBlock[0] = SCSI_INQUIRY_6; 1091 commandBlock[1] = lun->logical_unit_number << 5; 1092 commandBlock[2] = 0; // page code 1093 commandBlock[4] = dataLength; 1094 1095 scsi_inquiry_6_parameter parameter; 1096 status_t result = B_ERROR; 1097 err_act action = err_act_ok; 1098 for (uint32 tries = 0; tries < 3; tries++) { 1099 result = usb_disk_operation(lun, commandBlock, 6, ¶meter, 1100 &dataLength, true, &action); 1101 if (result == B_OK || (action != err_act_retry 1102 && action != err_act_many_retries)) { 1103 break; 1104 } 1105 } 1106 if (result != B_OK) { 1107 TRACE_ALWAYS("getting inquiry data failed: %s\n", strerror(result)); 1108 lun->device_type = B_DISK; 1109 lun->removable = true; 1110 return result; 1111 } 1112 1113 TRACE("peripherial_device_type 0x%02x\n", 1114 parameter.peripherial_device_type); 1115 TRACE("peripherial_qualifier 0x%02x\n", 1116 parameter.peripherial_qualifier); 1117 TRACE("removable_medium %s\n", 1118 parameter.removable_medium ? "yes" : "no"); 1119 TRACE("version 0x%02x\n", parameter.version); 1120 TRACE("response_data_format 0x%02x\n", parameter.response_data_format); 1121 TRACE_ALWAYS("vendor_identification \"%.8s\"\n", 1122 parameter.vendor_identification); 1123 TRACE_ALWAYS("product_identification \"%.16s\"\n", 1124 parameter.product_identification); 1125 TRACE_ALWAYS("product_revision_level \"%.4s\"\n", 1126 parameter.product_revision_level); 1127 1128 memcpy(lun->vendor_name, parameter.vendor_identification, 1129 MIN(sizeof(lun->vendor_name), sizeof(parameter.vendor_identification))); 1130 memcpy(lun->product_name, parameter.product_identification, 1131 MIN(sizeof(lun->product_name), 1132 sizeof(parameter.product_identification))); 1133 memcpy(lun->product_revision, parameter.product_revision_level, 1134 MIN(sizeof(lun->product_revision), 1135 sizeof(parameter.product_revision_level))); 1136 1137 lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ 1138 lun->removable = (parameter.removable_medium == 1); 1139 return B_OK; 1140 } 1141 1142 1143 status_t 1144 usb_disk_reset_capacity(device_lun *lun) 1145 { 1146 lun->block_size = 512; 1147 lun->block_count = 0; 1148 return B_OK; 1149 } 1150 1151 1152 status_t 1153 usb_disk_update_capacity(device_lun *lun) 1154 { 1155 size_t dataLength = sizeof(scsi_read_capacity_10_parameter); 1156 scsi_read_capacity_10_parameter parameter; 1157 status_t result = B_ERROR; 1158 err_act action = err_act_ok; 1159 1160 uint8 commandBlock[12]; 1161 memset(commandBlock, 0, sizeof(commandBlock)); 1162 1163 commandBlock[0] = SCSI_READ_CAPACITY_10; 1164 commandBlock[1] = lun->logical_unit_number << 5; 1165 1166 // Retry reading the capacity up to three times. The first try might only 1167 // yield a unit attention telling us that the device or media status 1168 // changed, which is more or less expected if it is the first operation 1169 // on the device or the device only clears the unit atention for capacity 1170 // reads. 1171 for (int32 i = 0; i < 5; i++) { 1172 result = usb_disk_operation(lun, commandBlock, 10, ¶meter, 1173 &dataLength, true, &action); 1174 1175 if (result == B_OK || (action != err_act_retry 1176 && action != err_act_many_retries)) { 1177 break; 1178 } 1179 1180 // In some cases, it's best to wait a little for the device to settle 1181 // before retrying. 1182 if (lun->device->is_ufi && (result == B_DEV_NO_MEDIA 1183 || result == B_TIMED_OUT || result == B_DEV_STALLED)) 1184 snooze(10000); 1185 } 1186 1187 if (result != B_OK) { 1188 TRACE_ALWAYS("failed to update capacity: %s\n", strerror(result)); 1189 lun->media_present = false; 1190 lun->media_changed = false; 1191 usb_disk_reset_capacity(lun); 1192 return result; 1193 } 1194 1195 lun->media_present = true; 1196 lun->media_changed = false; 1197 lun->block_size = ntohl(parameter.logical_block_length); 1198 lun->block_count = ntohl(parameter.last_logical_block_address) + 1; 1199 return B_OK; 1200 } 1201 1202 1203 status_t 1204 usb_disk_synchronize(device_lun *lun, bool force) 1205 { 1206 if (lun->device->is_ufi) { 1207 // UFI use interrupt because it runs all commands immediately, and 1208 // tells us when its done. There is no cache involved in that case, 1209 // so nothing to synchronize. 1210 return B_UNSUPPORTED; 1211 } 1212 1213 if (lun->device->sync_support == 0) { 1214 // this device reported an illegal request when syncing or repeatedly 1215 // returned an other error, it apparently does not support syncing... 1216 return B_UNSUPPORTED; 1217 } 1218 1219 if (!lun->should_sync && !force) 1220 return B_OK; 1221 1222 uint8 commandBlock[12]; 1223 memset(commandBlock, 0, sizeof(commandBlock)); 1224 1225 commandBlock[0] = SCSI_SYNCHRONIZE_CACHE_10; 1226 commandBlock[1] = lun->logical_unit_number << 5; 1227 1228 status_t result = usb_disk_operation(lun, commandBlock, 10, 1229 NULL, NULL, false); 1230 1231 if (result == B_OK) { 1232 lun->device->sync_support = SYNC_SUPPORT_RELOAD; 1233 lun->should_sync = false; 1234 return B_OK; 1235 } 1236 1237 if (result == B_DEV_INVALID_IOCTL) 1238 lun->device->sync_support = 0; 1239 else 1240 lun->device->sync_support--; 1241 1242 return result; 1243 } 1244 1245 1246 // 1247 //#pragma mark - Device Attach/Detach Notifications and Callback 1248 // 1249 1250 1251 static void 1252 usb_disk_callback(void *cookie, status_t status, void *data, 1253 size_t actualLength) 1254 { 1255 //TRACE("callback()\n"); 1256 disk_device *device = (disk_device *)cookie; 1257 device->status = status; 1258 device->actual_length = actualLength; 1259 release_sem(device->notify); 1260 } 1261 1262 1263 static status_t 1264 usb_disk_device_added(usb_device newDevice, void **cookie) 1265 { 1266 TRACE("device_added(0x%08" B_PRIx32 ")\n", newDevice); 1267 disk_device *device = (disk_device *)malloc(sizeof(disk_device)); 1268 device->device = newDevice; 1269 device->removed = false; 1270 device->open_count = 0; 1271 device->interface = 0xff; 1272 device->current_tag = 0; 1273 device->sync_support = SYNC_SUPPORT_RELOAD; 1274 device->tur_supported = true; 1275 device->is_atapi = false; 1276 device->is_ufi = false; 1277 device->luns = NULL; 1278 1279 // scan through the interfaces to find our bulk-only data interface 1280 const usb_configuration_info *configuration 1281 = gUSBModule->get_configuration(newDevice); 1282 if (configuration == NULL) { 1283 free(device); 1284 return B_ERROR; 1285 } 1286 1287 for (size_t i = 0; i < configuration->interface_count; i++) { 1288 usb_interface_info *interface = configuration->interface[i].active; 1289 if (interface == NULL) 1290 continue; 1291 1292 if (interface->descr->interface_class == USB_MASS_STORAGE_DEVICE_CLASS 1293 && (((interface->descr->interface_subclass == 0x06 /* SCSI */ 1294 || interface->descr->interface_subclass == 0x02 /* ATAPI */ 1295 || interface->descr->interface_subclass == 0x05 /* ATAPI */) 1296 && interface->descr->interface_protocol == 0x50 /* bulk-only */) 1297 || (interface->descr->interface_subclass == 0x04 /* UFI */ 1298 && interface->descr->interface_protocol == 0x00))) { 1299 1300 bool hasIn = false; 1301 bool hasOut = false; 1302 bool hasInt = false; 1303 for (size_t j = 0; j < interface->endpoint_count; j++) { 1304 usb_endpoint_info *endpoint = &interface->endpoint[j]; 1305 if (endpoint == NULL) 1306 continue; 1307 1308 if (!hasIn && (endpoint->descr->endpoint_address 1309 & USB_ENDPOINT_ADDR_DIR_IN) != 0 1310 && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 1311 device->bulk_in = endpoint->handle; 1312 hasIn = true; 1313 } else if (!hasOut && (endpoint->descr->endpoint_address 1314 & USB_ENDPOINT_ADDR_DIR_IN) == 0 1315 && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 1316 device->bulk_out = endpoint->handle; 1317 hasOut = true; 1318 } else if (!hasInt && (endpoint->descr->endpoint_address 1319 & USB_ENDPOINT_ADDR_DIR_IN) 1320 && endpoint->descr->attributes 1321 == USB_ENDPOINT_ATTR_INTERRUPT) { 1322 device->interrupt = endpoint->handle; 1323 hasInt = true; 1324 } 1325 1326 if (hasIn && hasOut && hasInt) 1327 break; 1328 } 1329 1330 if (!(hasIn && hasOut)) { 1331 // Missing one of the required endpoints, try next interface 1332 continue; 1333 } 1334 1335 device->interface = interface->descr->interface_number; 1336 device->is_atapi = interface->descr->interface_subclass != 0x06 1337 && interface->descr->interface_subclass != 0x04; 1338 device->is_ufi = interface->descr->interface_subclass == 0x04; 1339 1340 if (device->is_ufi && !hasInt) { 1341 // UFI without interrupt endpoint is not possible. 1342 continue; 1343 } 1344 break; 1345 } 1346 } 1347 1348 if (device->interface == 0xff) { 1349 TRACE_ALWAYS("no valid bulk-only or CBI interface found\n"); 1350 free(device); 1351 return B_ERROR; 1352 } 1353 1354 mutex_init(&device->lock, "usb_disk device lock"); 1355 1356 device->notify = create_sem(0, "usb_disk callback notify"); 1357 if (device->notify < B_OK) { 1358 mutex_destroy(&device->lock); 1359 status_t result = device->notify; 1360 free(device); 1361 return result; 1362 } 1363 1364 if (device->is_ufi) { 1365 device->interruptLock = create_sem(0, "usb_disk interrupt lock"); 1366 if (device->interruptLock < B_OK) { 1367 mutex_destroy(&device->lock); 1368 delete_sem(device->notify); 1369 status_t result = device->interruptLock; 1370 free(device); 1371 return result; 1372 } 1373 } 1374 1375 device->lun_count = usb_disk_get_max_lun(device) + 1; 1376 device->luns = (device_lun **)malloc(device->lun_count 1377 * sizeof(device_lun *)); 1378 for (uint8 i = 0; i < device->lun_count; i++) 1379 device->luns[i] = NULL; 1380 1381 status_t result = B_OK; 1382 1383 TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count); 1384 for (uint8 i = 0; i < device->lun_count; i++) { 1385 // create the individual luns present on this device 1386 device_lun *lun = (device_lun *)malloc(sizeof(device_lun)); 1387 if (lun == NULL) { 1388 result = B_NO_MEMORY; 1389 break; 1390 } 1391 1392 device->luns[i] = lun; 1393 lun->device = device; 1394 lun->logical_unit_number = i; 1395 lun->should_sync = false; 1396 lun->media_present = true; 1397 lun->media_changed = true; 1398 1399 memset(lun->vendor_name, 0, sizeof(lun->vendor_name)); 1400 memset(lun->product_name, 0, sizeof(lun->product_name)); 1401 memset(lun->product_revision, 0, sizeof(lun->product_revision)); 1402 1403 usb_disk_reset_capacity(lun); 1404 1405 // initialize this lun 1406 result = usb_disk_inquiry(lun); 1407 1408 if (device->is_ufi) { 1409 // Reset the device 1410 // If we don't do it all the other commands except inquiry and send 1411 // diagnostics will be stalled. 1412 result = usb_disk_send_diagnostic(lun); 1413 } 1414 1415 err_act action = err_act_ok; 1416 for (uint32 tries = 0; tries < 8; tries++) { 1417 TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " begin\n", 1418 i, tries); 1419 status_t ready = usb_disk_test_unit_ready(lun, &action); 1420 if (ready == B_OK || ready == B_DEV_NO_MEDIA 1421 || ready == B_DEV_MEDIA_CHANGED) { 1422 if (lun->device_type == B_CD) 1423 lun->write_protected = true; 1424 // TODO: check for write protection; disabled since some 1425 // devices lock up when getting the mode sense 1426 else if (/*usb_disk_mode_sense(lun) != B_OK*/true) 1427 lun->write_protected = false; 1428 1429 TRACE("usb lun %" B_PRIu8 " ready. write protected = %c%s\n", i, 1430 lun->write_protected ? 'y' : 'n', 1431 ready == B_DEV_NO_MEDIA ? " (no media inserted)" : ""); 1432 1433 break; 1434 } 1435 TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " failed\n", 1436 i, tries); 1437 if (action != err_act_retry && action != err_act_many_retries) 1438 break; 1439 bigtime_t snoozeTime = 1000000 * tries; 1440 TRACE("snoozing %" B_PRIu64 " microseconds for usb lun\n", 1441 snoozeTime); 1442 snooze(snoozeTime); 1443 } 1444 1445 if (result != B_OK) 1446 break; 1447 } 1448 1449 if (result != B_OK) { 1450 TRACE_ALWAYS("failed to initialize logical units: %s\n", 1451 strerror(result)); 1452 usb_disk_free_device_and_luns(device); 1453 return result; 1454 } 1455 1456 mutex_lock(&gDeviceListLock); 1457 device->device_number = 0; 1458 disk_device *other = gDeviceList; 1459 while (other != NULL) { 1460 if (other->device_number >= device->device_number) 1461 device->device_number = other->device_number + 1; 1462 1463 other = (disk_device *)other->link; 1464 } 1465 1466 device->link = (void *)gDeviceList; 1467 gDeviceList = device; 1468 gLunCount += device->lun_count; 1469 for (uint8 i = 0; i < device->lun_count; i++) 1470 sprintf(device->luns[i]->name, DEVICE_NAME, device->device_number, i); 1471 mutex_unlock(&gDeviceListLock); 1472 1473 TRACE("new device: 0x%p\n", device); 1474 *cookie = (void *)device; 1475 return B_OK; 1476 } 1477 1478 1479 static status_t 1480 usb_disk_device_removed(void *cookie) 1481 { 1482 TRACE("device_removed(0x%p)\n", cookie); 1483 disk_device *device = (disk_device *)cookie; 1484 1485 mutex_lock(&gDeviceListLock); 1486 if (gDeviceList == device) { 1487 gDeviceList = (disk_device *)device->link; 1488 } else { 1489 disk_device *element = gDeviceList; 1490 while (element) { 1491 if (element->link == device) { 1492 element->link = device->link; 1493 break; 1494 } 1495 1496 element = (disk_device *)element->link; 1497 } 1498 } 1499 gLunCount -= device->lun_count; 1500 gDeviceCount--; 1501 1502 device->removed = true; 1503 gUSBModule->cancel_queued_transfers(device->bulk_in); 1504 gUSBModule->cancel_queued_transfers(device->bulk_out); 1505 if (device->open_count == 0) 1506 usb_disk_free_device_and_luns(device); 1507 1508 mutex_unlock(&gDeviceListLock); 1509 return B_OK; 1510 } 1511 1512 1513 // 1514 //#pragma mark - Partial Buffer Functions 1515 // 1516 1517 1518 static bool 1519 usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length, 1520 uint32 &blockPosition, uint16 &blockCount) 1521 { 1522 blockPosition = (uint32)(position / lun->block_size); 1523 if ((off_t)blockPosition * lun->block_size != position) 1524 return true; 1525 1526 blockCount = (uint16)(length / lun->block_size); 1527 if ((size_t)blockCount * lun->block_size != length) 1528 return true; 1529 1530 return false; 1531 } 1532 1533 1534 static status_t 1535 usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, 1536 void *buffer, size_t *length) 1537 { 1538 uint8 commandBlock[12]; 1539 memset(commandBlock, 0, sizeof(commandBlock)); 1540 if (lun->device->is_ufi) { 1541 commandBlock[0] = SCSI_READ_12; 1542 commandBlock[1] = lun->logical_unit_number << 5; 1543 commandBlock[2] = blockPosition >> 24; 1544 commandBlock[3] = blockPosition >> 16; 1545 commandBlock[4] = blockPosition >> 8; 1546 commandBlock[5] = blockPosition; 1547 commandBlock[6] = 0; // blockCount >> 24; 1548 commandBlock[7] = 0; // blockCount >> 16; 1549 commandBlock[8] = blockCount >> 8; 1550 commandBlock[9] = blockCount; 1551 1552 status_t result = B_OK; 1553 for (int tries = 0; tries < 5; tries++) { 1554 result = usb_disk_operation(lun, commandBlock, 12, buffer, length, 1555 true); 1556 if (result == B_OK) 1557 break; 1558 else 1559 snooze(10000); 1560 } 1561 return result; 1562 } else { 1563 commandBlock[0] = SCSI_READ_10; 1564 commandBlock[1] = 0; 1565 commandBlock[2] = blockPosition >> 24; 1566 commandBlock[3] = blockPosition >> 16; 1567 commandBlock[4] = blockPosition >> 8; 1568 commandBlock[5] = blockPosition; 1569 commandBlock[7] = blockCount >> 8; 1570 commandBlock[8] = blockCount; 1571 status_t result = usb_disk_operation(lun, commandBlock, 10, 1572 buffer, length, true); 1573 return result; 1574 } 1575 } 1576 1577 1578 static status_t 1579 usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, 1580 void *buffer, size_t *length) 1581 { 1582 uint8 commandBlock[12]; 1583 memset(commandBlock, 0, sizeof(commandBlock)); 1584 1585 if (lun->device->is_ufi) { 1586 commandBlock[0] = SCSI_WRITE_12; 1587 commandBlock[1] = lun->logical_unit_number << 5; 1588 commandBlock[2] = blockPosition >> 24; 1589 commandBlock[3] = blockPosition >> 16; 1590 commandBlock[4] = blockPosition >> 8; 1591 commandBlock[5] = blockPosition; 1592 commandBlock[6] = blockCount >> 24; 1593 commandBlock[7] = blockCount >> 16; 1594 commandBlock[8] = blockCount >> 8; 1595 commandBlock[9] = blockCount; 1596 1597 status_t result; 1598 result = usb_disk_operation(lun, commandBlock, 12, buffer, length, 1599 false); 1600 1601 int retry = 10; 1602 err_act action = err_act_ok; 1603 while (result == B_DEV_NO_MEDIA && retry > 0) { 1604 snooze(10000); 1605 result = usb_disk_request_sense(lun, &action); 1606 retry--; 1607 } 1608 1609 if (result == B_OK) 1610 lun->should_sync = true; 1611 return result; 1612 } else { 1613 commandBlock[0] = SCSI_WRITE_10; 1614 commandBlock[2] = blockPosition >> 24; 1615 commandBlock[3] = blockPosition >> 16; 1616 commandBlock[4] = blockPosition >> 8; 1617 commandBlock[5] = blockPosition; 1618 commandBlock[7] = blockCount >> 8; 1619 commandBlock[8] = blockCount; 1620 status_t result = usb_disk_operation(lun, commandBlock, 10, 1621 buffer, length, false); 1622 if (result == B_OK) 1623 lun->should_sync = true; 1624 return result; 1625 } 1626 } 1627 1628 1629 static status_t 1630 usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length, 1631 void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition, 1632 uint16 &blockCount) 1633 { 1634 blockPosition = (uint32)(position / lun->block_size); 1635 blockCount = (uint16)((uint32)((position + length + lun->block_size - 1) 1636 / lun->block_size) - blockPosition); 1637 size_t blockLength = blockCount * lun->block_size; 1638 blockBuffer = malloc(blockLength); 1639 if (blockBuffer == NULL) { 1640 TRACE_ALWAYS("no memory to allocate partial buffer\n"); 1641 return B_NO_MEMORY; 1642 } 1643 1644 status_t result = usb_disk_block_read(lun, blockPosition, blockCount, 1645 blockBuffer, &blockLength); 1646 if (result != B_OK) { 1647 TRACE_ALWAYS("block read failed when filling partial buffer: %s\n", 1648 strerror(result)); 1649 free(blockBuffer); 1650 return result; 1651 } 1652 1653 off_t offset = position - (off_t)blockPosition * lun->block_size; 1654 partialBuffer = (uint8 *)blockBuffer + offset; 1655 return B_OK; 1656 } 1657 1658 1659 // 1660 //#pragma mark - Driver Hooks 1661 // 1662 1663 1664 static status_t 1665 usb_disk_open(const char *name, uint32 flags, void **cookie) 1666 { 1667 TRACE("open(%s)\n", name); 1668 if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0) 1669 return B_NAME_NOT_FOUND; 1670 1671 int32 lastPart = 0; 1672 size_t nameLength = strlen(name); 1673 for (int32 i = nameLength - 1; i >= 0; i--) { 1674 if (name[i] == '/') { 1675 lastPart = i; 1676 break; 1677 } 1678 } 1679 1680 char rawName[nameLength + 4]; 1681 strncpy(rawName, name, lastPart + 1); 1682 rawName[lastPart + 1] = 0; 1683 strcat(rawName, "raw"); 1684 TRACE("opening raw device %s for %s\n", rawName, name); 1685 1686 mutex_lock(&gDeviceListLock); 1687 disk_device *device = gDeviceList; 1688 while (device) { 1689 for (uint8 i = 0; i < device->lun_count; i++) { 1690 device_lun *lun = device->luns[i]; 1691 if (strncmp(rawName, lun->name, 32) == 0) { 1692 // found the matching device/lun 1693 if (device->removed) { 1694 mutex_unlock(&gDeviceListLock); 1695 return B_ERROR; 1696 } 1697 1698 device->open_count++; 1699 *cookie = lun; 1700 mutex_unlock(&gDeviceListLock); 1701 return B_OK; 1702 } 1703 } 1704 1705 device = (disk_device *)device->link; 1706 } 1707 1708 mutex_unlock(&gDeviceListLock); 1709 return B_NAME_NOT_FOUND; 1710 } 1711 1712 1713 static status_t 1714 usb_disk_close(void *cookie) 1715 { 1716 TRACE("close()\n"); 1717 device_lun *lun = (device_lun *)cookie; 1718 disk_device *device = lun->device; 1719 1720 mutex_lock(&device->lock); 1721 if (!device->removed) 1722 usb_disk_synchronize(lun, false); 1723 mutex_unlock(&device->lock); 1724 1725 return B_OK; 1726 } 1727 1728 1729 static status_t 1730 usb_disk_free(void *cookie) 1731 { 1732 TRACE("free()\n"); 1733 mutex_lock(&gDeviceListLock); 1734 1735 device_lun *lun = (device_lun *)cookie; 1736 disk_device *device = lun->device; 1737 device->open_count--; 1738 if (device->open_count == 0 && device->removed) { 1739 // we can simply free the device here as it has been removed from 1740 // the device list in the device removed notification hook 1741 usb_disk_free_device_and_luns(device); 1742 } 1743 1744 mutex_unlock(&gDeviceListLock); 1745 return B_OK; 1746 } 1747 1748 1749 static inline void 1750 normalize_name(char *name, size_t nameLength) 1751 { 1752 bool wasSpace = false; 1753 size_t insertIndex = 0; 1754 for (size_t i = 0; i < nameLength; i++) { 1755 bool isSpace = name[i] == ' '; 1756 if (isSpace && wasSpace) 1757 continue; 1758 1759 name[insertIndex++] = name[i]; 1760 wasSpace = isSpace; 1761 } 1762 1763 if (insertIndex > 0 && name[insertIndex - 1] == ' ') 1764 insertIndex--; 1765 1766 name[insertIndex] = 0; 1767 } 1768 1769 1770 static status_t 1771 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) 1772 { 1773 device_lun *lun = (device_lun *)cookie; 1774 disk_device *device = lun->device; 1775 mutex_lock(&device->lock); 1776 if (device->removed) { 1777 mutex_unlock(&device->lock); 1778 return B_DEV_NOT_READY; 1779 } 1780 1781 status_t result = B_DEV_INVALID_IOCTL; 1782 switch (op) { 1783 case B_GET_DEVICE_SIZE: { 1784 if (lun->media_changed) { 1785 result = usb_disk_update_capacity(lun); 1786 if (result != B_OK) 1787 break; 1788 } 1789 1790 size_t size = lun->block_size * lun->block_count; 1791 result = user_memcpy(buffer, &size, sizeof(size)); 1792 1793 break; 1794 } 1795 1796 case B_GET_MEDIA_STATUS: 1797 { 1798 err_act action = err_act_ok; 1799 for (uint32 tries = 0; tries < 3; tries++) { 1800 status_t ready = usb_disk_test_unit_ready(lun, &action); 1801 if (ready == B_OK || ready == B_DEV_NO_MEDIA 1802 || (action != err_act_retry 1803 && action != err_act_many_retries)) { 1804 *(status_t *)buffer = ready; 1805 break; 1806 } 1807 snooze(500000); 1808 } 1809 TRACE("B_GET_MEDIA_STATUS: 0x%08" B_PRIx32 "\n", 1810 *(status_t *)buffer); 1811 result = B_OK; 1812 break; 1813 } 1814 1815 case B_GET_GEOMETRY: 1816 { 1817 if (lun->media_changed) { 1818 result = usb_disk_update_capacity(lun); 1819 if (result != B_OK) 1820 break; 1821 } 1822 1823 device_geometry geometry; 1824 devfs_compute_geometry_size(&geometry, lun->block_count, 1825 lun->block_size); 1826 1827 geometry.device_type = lun->device_type; 1828 geometry.removable = lun->removable; 1829 geometry.read_only = lun->write_protected; 1830 geometry.write_once = lun->device_type == B_WORM; 1831 TRACE("B_GET_GEOMETRY: %" B_PRId32 " sectors at %" B_PRId32 1832 " bytes per sector\n", geometry.cylinder_count, 1833 geometry.bytes_per_sector); 1834 result = user_memcpy(buffer, &geometry, sizeof(device_geometry)); 1835 break; 1836 } 1837 1838 case B_FLUSH_DRIVE_CACHE: 1839 TRACE("B_FLUSH_DRIVE_CACHE\n"); 1840 result = usb_disk_synchronize(lun, true); 1841 break; 1842 1843 case B_EJECT_DEVICE: 1844 { 1845 uint8 commandBlock[12]; 1846 memset(commandBlock, 0, sizeof(commandBlock)); 1847 1848 commandBlock[0] = SCSI_START_STOP_UNIT_6; 1849 commandBlock[1] = lun->logical_unit_number << 5; 1850 commandBlock[4] = 2; 1851 1852 result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, 1853 false); 1854 break; 1855 } 1856 1857 case B_LOAD_MEDIA: 1858 { 1859 uint8 commandBlock[12]; 1860 memset(commandBlock, 0, sizeof(commandBlock)); 1861 1862 commandBlock[0] = SCSI_START_STOP_UNIT_6; 1863 commandBlock[1] = lun->logical_unit_number << 5; 1864 commandBlock[4] = 3; 1865 1866 result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, 1867 false); 1868 break; 1869 } 1870 1871 case B_GET_ICON: 1872 // We don't support this legacy ioctl anymore, but the two other 1873 // icon ioctls below instead. 1874 break; 1875 1876 case B_GET_ICON_NAME: 1877 { 1878 const char *iconName = "devices/drive-removable-media-usb"; 1879 char vendor[sizeof(lun->vendor_name)+1]; 1880 char product[sizeof(lun->product_name)+1]; 1881 1882 if (device->is_ufi) { 1883 iconName = "devices/drive-floppy-usb"; 1884 } 1885 1886 switch (lun->device_type) { 1887 case B_CD: 1888 case B_OPTICAL: 1889 iconName = "devices/drive-optical"; 1890 break; 1891 case B_TAPE: // TODO 1892 default: 1893 snprintf(vendor, sizeof(vendor), "%.8s", 1894 lun->vendor_name); 1895 snprintf(product, sizeof(product), "%.16s", 1896 lun->product_name); 1897 for (int i = 0; kIconMatches[i].icon; i++) { 1898 if (kIconMatches[i].vendor != NULL 1899 && strstr(vendor, kIconMatches[i].vendor) == NULL) 1900 continue; 1901 if (kIconMatches[i].product != NULL 1902 && strstr(product, kIconMatches[i].product) == NULL) 1903 continue; 1904 iconName = kIconMatches[i].name; 1905 } 1906 break; 1907 } 1908 result = user_strlcpy((char *)buffer, iconName, 1909 B_FILE_NAME_LENGTH); 1910 break; 1911 } 1912 1913 case B_GET_VECTOR_ICON: 1914 { 1915 device_icon *icon = &kKeyIconData; 1916 char vendor[sizeof(lun->vendor_name)+1]; 1917 char product[sizeof(lun->product_name)+1]; 1918 1919 if (length != sizeof(device_icon)) { 1920 result = B_BAD_VALUE; 1921 break; 1922 } 1923 1924 if (device->is_ufi) { 1925 // UFI is specific for floppy drives 1926 icon = &kFloppyIconData; 1927 } else { 1928 switch (lun->device_type) { 1929 case B_CD: 1930 case B_OPTICAL: 1931 icon = &kCDIconData; 1932 break; 1933 case B_TAPE: // TODO 1934 default: 1935 snprintf(vendor, sizeof(vendor), "%.8s", 1936 lun->vendor_name); 1937 snprintf(product, sizeof(product), "%.16s", 1938 lun->product_name); 1939 for (int i = 0; kIconMatches[i].icon; i++) { 1940 if (kIconMatches[i].vendor != NULL 1941 && strstr(vendor, 1942 kIconMatches[i].vendor) == NULL) 1943 continue; 1944 if (kIconMatches[i].product != NULL 1945 && strstr(product, 1946 kIconMatches[i].product) == NULL) 1947 continue; 1948 icon = kIconMatches[i].icon; 1949 } 1950 break; 1951 } 1952 } 1953 1954 device_icon iconData; 1955 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) { 1956 result = B_BAD_ADDRESS; 1957 break; 1958 } 1959 1960 if (iconData.icon_size >= icon->icon_size) { 1961 if (user_memcpy(iconData.icon_data, icon->icon_data, 1962 (size_t)icon->icon_size) != B_OK) { 1963 result = B_BAD_ADDRESS; 1964 break; 1965 } 1966 } 1967 1968 iconData.icon_size = icon->icon_size; 1969 result = user_memcpy(buffer, &iconData, sizeof(device_icon)); 1970 break; 1971 } 1972 1973 case B_GET_DEVICE_NAME: 1974 { 1975 size_t nameLength = sizeof(lun->vendor_name) 1976 + sizeof(lun->product_name) + sizeof(lun->product_revision) + 3; 1977 1978 char name[nameLength]; 1979 snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name, 1980 lun->product_name, lun->product_revision); 1981 1982 normalize_name(name, nameLength); 1983 1984 result = user_strlcpy((char *)buffer, name, length); 1985 if (result > 0) 1986 result = B_OK; 1987 1988 TRACE_ALWAYS("got device name \"%s\": %s\n", name, 1989 strerror(result)); 1990 break; 1991 } 1992 1993 default: 1994 TRACE_ALWAYS("unhandled ioctl %" B_PRId32 "\n", op); 1995 break; 1996 } 1997 1998 mutex_unlock(&device->lock); 1999 return result; 2000 } 2001 2002 2003 static status_t 2004 usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) 2005 { 2006 if (buffer == NULL || length == NULL) 2007 return B_BAD_VALUE; 2008 2009 TRACE("read(%" B_PRIdOFF ", %ld)\n", position, *length); 2010 device_lun *lun = (device_lun *)cookie; 2011 disk_device *device = lun->device; 2012 mutex_lock(&device->lock); 2013 if (device->removed) { 2014 *length = 0; 2015 mutex_unlock(&device->lock); 2016 return B_DEV_NOT_READY; 2017 } 2018 2019 status_t result = B_ERROR; 2020 uint32 blockPosition = 0; 2021 uint16 blockCount = 0; 2022 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length, 2023 blockPosition, blockCount); 2024 if (needsPartial) { 2025 void *partialBuffer = NULL; 2026 void *blockBuffer = NULL; 2027 result = usb_disk_prepare_partial_buffer(lun, position, *length, 2028 partialBuffer, blockBuffer, blockPosition, blockCount); 2029 if (result == B_OK) { 2030 memcpy(buffer, partialBuffer, *length); 2031 free(blockBuffer); 2032 } 2033 } else { 2034 result = usb_disk_block_read(lun, blockPosition, blockCount, buffer, 2035 length); 2036 } 2037 2038 mutex_unlock(&device->lock); 2039 if (result == B_OK) { 2040 TRACE("read successful with %ld bytes\n", *length); 2041 return B_OK; 2042 } 2043 2044 *length = 0; 2045 TRACE_ALWAYS("read failed: %s\n", strerror(result)); 2046 return result; 2047 } 2048 2049 2050 static status_t 2051 usb_disk_write(void *cookie, off_t position, const void *buffer, 2052 size_t *length) 2053 { 2054 if (buffer == NULL || length == NULL) 2055 return B_BAD_VALUE; 2056 2057 TRACE("write(%" B_PRIdOFF", %ld)\n", position, *length); 2058 device_lun *lun = (device_lun *)cookie; 2059 disk_device *device = lun->device; 2060 mutex_lock(&device->lock); 2061 if (device->removed) { 2062 *length = 0; 2063 mutex_unlock(&device->lock); 2064 return B_DEV_NOT_READY; 2065 } 2066 2067 status_t result = B_ERROR; 2068 uint32 blockPosition = 0; 2069 uint16 blockCount = 0; 2070 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, 2071 *length, blockPosition, blockCount); 2072 if (needsPartial) { 2073 void *partialBuffer = NULL; 2074 void *blockBuffer = NULL; 2075 result = usb_disk_prepare_partial_buffer(lun, position, *length, 2076 partialBuffer, blockBuffer, blockPosition, blockCount); 2077 if (result == B_OK) { 2078 memcpy(partialBuffer, buffer, *length); 2079 size_t blockLength = blockCount * lun->block_size; 2080 result = usb_disk_block_write(lun, blockPosition, blockCount, 2081 blockBuffer, &blockLength); 2082 free(blockBuffer); 2083 } 2084 } else { 2085 result = usb_disk_block_write(lun, blockPosition, blockCount, 2086 (void *)buffer, length); 2087 } 2088 2089 mutex_unlock(&device->lock); 2090 if (result == B_OK) { 2091 TRACE("write successful with %ld bytes\n", *length); 2092 return B_OK; 2093 } 2094 2095 *length = 0; 2096 TRACE_ALWAYS("write failed: %s\n", strerror(result)); 2097 return result; 2098 } 2099 2100 2101 // 2102 //#pragma mark - Driver Entry Points 2103 // 2104 2105 2106 status_t 2107 init_hardware() 2108 { 2109 TRACE("init_hardware()\n"); 2110 return B_OK; 2111 } 2112 2113 2114 status_t 2115 init_driver() 2116 { 2117 TRACE("init_driver()\n"); 2118 static usb_notify_hooks notifyHooks = { 2119 &usb_disk_device_added, 2120 &usb_disk_device_removed 2121 }; 2122 2123 static usb_support_descriptor supportedDevices[] = { 2124 { 0x08 /* mass storage */, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 }, 2125 { 0x08 /* mass storage */, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 }, 2126 { 0x08 /* mass storage */, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 }, 2127 { 0x08 /* mass storage */, 0x04 /* UFI */, 0x00, 0, 0 } 2128 }; 2129 2130 gDeviceList = NULL; 2131 gDeviceCount = 0; 2132 gLunCount = 0; 2133 mutex_init(&gDeviceListLock, "usb_disk device list lock"); 2134 2135 TRACE("trying module %s\n", B_USB_MODULE_NAME); 2136 status_t result = get_module(B_USB_MODULE_NAME, 2137 (module_info **)&gUSBModule); 2138 if (result < B_OK) { 2139 TRACE_ALWAYS("getting module failed: %s\n", strerror(result)); 2140 mutex_destroy(&gDeviceListLock); 2141 return result; 2142 } 2143 2144 gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 4, NULL); 2145 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 2146 return B_OK; 2147 } 2148 2149 2150 void 2151 uninit_driver() 2152 { 2153 TRACE("uninit_driver()\n"); 2154 gUSBModule->uninstall_notify(DRIVER_NAME); 2155 mutex_lock(&gDeviceListLock); 2156 2157 if (gDeviceNames) { 2158 for (int32 i = 0; gDeviceNames[i]; i++) 2159 free(gDeviceNames[i]); 2160 free(gDeviceNames); 2161 gDeviceNames = NULL; 2162 } 2163 2164 mutex_destroy(&gDeviceListLock); 2165 put_module(B_USB_MODULE_NAME); 2166 } 2167 2168 2169 const char ** 2170 publish_devices() 2171 { 2172 TRACE("publish_devices()\n"); 2173 if (gDeviceNames) { 2174 for (int32 i = 0; gDeviceNames[i]; i++) 2175 free(gDeviceNames[i]); 2176 free(gDeviceNames); 2177 gDeviceNames = NULL; 2178 } 2179 2180 gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1)); 2181 if (gDeviceNames == NULL) 2182 return NULL; 2183 2184 int32 index = 0; 2185 mutex_lock(&gDeviceListLock); 2186 disk_device *device = gDeviceList; 2187 while (device) { 2188 for (uint8 i = 0; i < device->lun_count; i++) 2189 gDeviceNames[index++] = strdup(device->luns[i]->name); 2190 2191 device = (disk_device *)device->link; 2192 } 2193 2194 gDeviceNames[index++] = NULL; 2195 mutex_unlock(&gDeviceListLock); 2196 return (const char **)gDeviceNames; 2197 } 2198 2199 2200 device_hooks * 2201 find_device(const char *name) 2202 { 2203 TRACE("find_device()\n"); 2204 static device_hooks hooks = { 2205 &usb_disk_open, 2206 &usb_disk_close, 2207 &usb_disk_free, 2208 &usb_disk_ioctl, 2209 &usb_disk_read, 2210 &usb_disk_write, 2211 NULL, 2212 NULL, 2213 NULL, 2214 NULL 2215 }; 2216 2217 return &hooks; 2218 } 2219