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