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