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 status_t 1156 usb_disk_update_capacity(device_lun *lun) 1157 { 1158 size_t dataLength = sizeof(scsi_read_capacity_10_parameter); 1159 scsi_read_capacity_10_parameter parameter; 1160 status_t result = B_ERROR; 1161 err_act action = err_act_ok; 1162 1163 uint8 commandBlock[12]; 1164 memset(commandBlock, 0, sizeof(commandBlock)); 1165 1166 commandBlock[0] = SCSI_READ_CAPACITY_10; 1167 commandBlock[1] = lun->logical_unit_number << 5; 1168 1169 // Retry reading the capacity up to three times. The first try might only 1170 // yield a unit attention telling us that the device or media status 1171 // changed, which is more or less expected if it is the first operation 1172 // on the device or the device only clears the unit atention for capacity 1173 // reads. 1174 for (int32 i = 0; i < 5; i++) { 1175 result = usb_disk_operation(lun, commandBlock, 10, ¶meter, 1176 &dataLength, true, &action); 1177 1178 if (result == B_OK || (action != err_act_retry 1179 && action != err_act_many_retries)) { 1180 break; 1181 } 1182 1183 // In some cases, it's best to wait a little for the device to settle 1184 // before retrying. 1185 if (lun->device->is_ufi && (result == B_DEV_NO_MEDIA 1186 || result == B_TIMED_OUT || result == B_DEV_STALLED)) 1187 snooze(10000); 1188 } 1189 1190 if (result != B_OK) { 1191 TRACE_ALWAYS("failed to update capacity: %s\n", strerror(result)); 1192 lun->media_present = false; 1193 lun->media_changed = false; 1194 usb_disk_reset_capacity(lun); 1195 return result; 1196 } 1197 1198 lun->media_present = true; 1199 lun->media_changed = false; 1200 lun->block_size = B_BENDIAN_TO_HOST_INT32(parameter.logical_block_length); 1201 lun->block_count = 1202 B_BENDIAN_TO_HOST_INT32(parameter.last_logical_block_address) + 1; 1203 return B_OK; 1204 } 1205 1206 1207 status_t 1208 usb_disk_synchronize(device_lun *lun, bool force) 1209 { 1210 if (lun->device->is_ufi) { 1211 // UFI use interrupt because it runs all commands immediately, and 1212 // tells us when its done. There is no cache involved in that case, 1213 // so nothing to synchronize. 1214 return B_UNSUPPORTED; 1215 } 1216 1217 if (lun->device->sync_support == 0) { 1218 // this device reported an illegal request when syncing or repeatedly 1219 // returned an other error, it apparently does not support syncing... 1220 return B_UNSUPPORTED; 1221 } 1222 1223 if (!lun->should_sync && !force) 1224 return B_OK; 1225 1226 uint8 commandBlock[12]; 1227 memset(commandBlock, 0, sizeof(commandBlock)); 1228 1229 commandBlock[0] = SCSI_SYNCHRONIZE_CACHE_10; 1230 commandBlock[1] = lun->logical_unit_number << 5; 1231 1232 status_t result = usb_disk_operation(lun, commandBlock, 10, 1233 NULL, NULL, false); 1234 1235 if (result == B_OK) { 1236 lun->device->sync_support = SYNC_SUPPORT_RELOAD; 1237 lun->should_sync = false; 1238 return B_OK; 1239 } 1240 1241 if (result == B_DEV_INVALID_IOCTL) 1242 lun->device->sync_support = 0; 1243 else 1244 lun->device->sync_support--; 1245 1246 return result; 1247 } 1248 1249 1250 // 1251 //#pragma mark - Device Attach/Detach Notifications and Callback 1252 // 1253 1254 1255 static void 1256 usb_disk_callback(void *cookie, status_t status, void *data, 1257 size_t actualLength) 1258 { 1259 //TRACE("callback()\n"); 1260 disk_device *device = (disk_device *)cookie; 1261 device->status = status; 1262 device->actual_length = actualLength; 1263 release_sem(device->notify); 1264 } 1265 1266 1267 static status_t 1268 usb_disk_device_added(usb_device newDevice, void **cookie) 1269 { 1270 TRACE("device_added(0x%08" B_PRIx32 ")\n", newDevice); 1271 disk_device *device = (disk_device *)malloc(sizeof(disk_device)); 1272 device->device = newDevice; 1273 device->removed = false; 1274 device->open_count = 0; 1275 device->interface = 0xff; 1276 device->current_tag = 0; 1277 device->sync_support = SYNC_SUPPORT_RELOAD; 1278 device->tur_supported = true; 1279 device->is_atapi = false; 1280 device->is_ufi = false; 1281 device->luns = NULL; 1282 1283 // scan through the interfaces to find our bulk-only data interface 1284 const usb_configuration_info *configuration 1285 = gUSBModule->get_configuration(newDevice); 1286 if (configuration == NULL) { 1287 free(device); 1288 return B_ERROR; 1289 } 1290 1291 for (size_t i = 0; i < configuration->interface_count; i++) { 1292 usb_interface_info *interface = configuration->interface[i].active; 1293 if (interface == NULL) 1294 continue; 1295 1296 if (interface->descr->interface_class == USB_MASS_STORAGE_DEVICE_CLASS 1297 && (((interface->descr->interface_subclass == 0x06 /* SCSI */ 1298 || interface->descr->interface_subclass == 0x02 /* ATAPI */ 1299 || interface->descr->interface_subclass == 0x05 /* ATAPI */) 1300 && interface->descr->interface_protocol == 0x50 /* bulk-only */) 1301 || (interface->descr->interface_subclass == 0x04 /* UFI */ 1302 && interface->descr->interface_protocol == 0x00))) { 1303 1304 bool hasIn = false; 1305 bool hasOut = false; 1306 bool hasInt = false; 1307 for (size_t j = 0; j < interface->endpoint_count; j++) { 1308 usb_endpoint_info *endpoint = &interface->endpoint[j]; 1309 if (endpoint == NULL) 1310 continue; 1311 1312 if (!hasIn && (endpoint->descr->endpoint_address 1313 & USB_ENDPOINT_ADDR_DIR_IN) != 0 1314 && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 1315 device->bulk_in = endpoint->handle; 1316 hasIn = true; 1317 } else if (!hasOut && (endpoint->descr->endpoint_address 1318 & USB_ENDPOINT_ADDR_DIR_IN) == 0 1319 && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 1320 device->bulk_out = endpoint->handle; 1321 hasOut = true; 1322 } else if (!hasInt && (endpoint->descr->endpoint_address 1323 & USB_ENDPOINT_ADDR_DIR_IN) 1324 && endpoint->descr->attributes 1325 == USB_ENDPOINT_ATTR_INTERRUPT) { 1326 device->interrupt = endpoint->handle; 1327 hasInt = true; 1328 } 1329 1330 if (hasIn && hasOut && hasInt) 1331 break; 1332 } 1333 1334 if (!(hasIn && hasOut)) { 1335 // Missing one of the required endpoints, try next interface 1336 continue; 1337 } 1338 1339 device->interface = interface->descr->interface_number; 1340 device->is_atapi = interface->descr->interface_subclass != 0x06 1341 && interface->descr->interface_subclass != 0x04; 1342 device->is_ufi = interface->descr->interface_subclass == 0x04; 1343 1344 if (device->is_ufi && !hasInt) { 1345 // UFI without interrupt endpoint is not possible. 1346 continue; 1347 } 1348 break; 1349 } 1350 } 1351 1352 if (device->interface == 0xff) { 1353 TRACE_ALWAYS("no valid bulk-only or CBI interface found\n"); 1354 free(device); 1355 return B_ERROR; 1356 } 1357 1358 mutex_init(&device->lock, "usb_disk device lock"); 1359 1360 device->notify = create_sem(0, "usb_disk callback notify"); 1361 if (device->notify < B_OK) { 1362 mutex_destroy(&device->lock); 1363 status_t result = device->notify; 1364 free(device); 1365 return result; 1366 } 1367 1368 if (device->is_ufi) { 1369 device->interruptLock = create_sem(0, "usb_disk interrupt lock"); 1370 if (device->interruptLock < B_OK) { 1371 mutex_destroy(&device->lock); 1372 delete_sem(device->notify); 1373 status_t result = device->interruptLock; 1374 free(device); 1375 return result; 1376 } 1377 } 1378 1379 device->lun_count = usb_disk_get_max_lun(device) + 1; 1380 device->luns = (device_lun **)malloc(device->lun_count 1381 * sizeof(device_lun *)); 1382 for (uint8 i = 0; i < device->lun_count; i++) 1383 device->luns[i] = NULL; 1384 1385 status_t result = B_OK; 1386 1387 TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count); 1388 for (uint8 i = 0; i < device->lun_count; i++) { 1389 // create the individual luns present on this device 1390 device_lun *lun = (device_lun *)malloc(sizeof(device_lun)); 1391 if (lun == NULL) { 1392 result = B_NO_MEMORY; 1393 break; 1394 } 1395 1396 device->luns[i] = lun; 1397 lun->device = device; 1398 lun->logical_unit_number = i; 1399 lun->should_sync = false; 1400 lun->media_present = true; 1401 lun->media_changed = true; 1402 1403 memset(lun->vendor_name, 0, sizeof(lun->vendor_name)); 1404 memset(lun->product_name, 0, sizeof(lun->product_name)); 1405 memset(lun->product_revision, 0, sizeof(lun->product_revision)); 1406 1407 usb_disk_reset_capacity(lun); 1408 1409 // initialize this lun 1410 result = usb_disk_inquiry(lun); 1411 1412 if (device->is_ufi) { 1413 // Reset the device 1414 // If we don't do it all the other commands except inquiry and send 1415 // diagnostics will be stalled. 1416 result = usb_disk_send_diagnostic(lun); 1417 } 1418 1419 err_act action = err_act_ok; 1420 for (uint32 tries = 0; tries < 8; tries++) { 1421 TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " begin\n", 1422 i, tries); 1423 status_t ready = usb_disk_test_unit_ready(lun, &action); 1424 if (ready == B_OK || ready == B_DEV_NO_MEDIA 1425 || ready == B_DEV_MEDIA_CHANGED) { 1426 if (lun->device_type == B_CD) 1427 lun->write_protected = true; 1428 // TODO: check for write protection; disabled since some 1429 // devices lock up when getting the mode sense 1430 else if (/*usb_disk_mode_sense(lun) != B_OK*/true) 1431 lun->write_protected = false; 1432 1433 TRACE("usb lun %" B_PRIu8 " ready. write protected = %c%s\n", i, 1434 lun->write_protected ? 'y' : 'n', 1435 ready == B_DEV_NO_MEDIA ? " (no media inserted)" : ""); 1436 1437 break; 1438 } 1439 TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " failed\n", 1440 i, tries); 1441 if (action != err_act_retry && action != err_act_many_retries) 1442 break; 1443 bigtime_t snoozeTime = 1000000 * tries; 1444 TRACE("snoozing %" B_PRIu64 " microseconds for usb lun\n", 1445 snoozeTime); 1446 snooze(snoozeTime); 1447 } 1448 1449 if (result != B_OK) 1450 break; 1451 } 1452 1453 if (result != B_OK) { 1454 TRACE_ALWAYS("failed to initialize logical units: %s\n", 1455 strerror(result)); 1456 usb_disk_free_device_and_luns(device); 1457 return result; 1458 } 1459 1460 mutex_lock(&gDeviceListLock); 1461 device->device_number = 0; 1462 disk_device *other = gDeviceList; 1463 while (other != NULL) { 1464 if (other->device_number >= device->device_number) 1465 device->device_number = other->device_number + 1; 1466 1467 other = (disk_device *)other->link; 1468 } 1469 1470 device->link = (void *)gDeviceList; 1471 gDeviceList = device; 1472 gLunCount += device->lun_count; 1473 for (uint8 i = 0; i < device->lun_count; i++) 1474 sprintf(device->luns[i]->name, DEVICE_NAME, device->device_number, i); 1475 mutex_unlock(&gDeviceListLock); 1476 1477 TRACE("new device: 0x%p\n", device); 1478 *cookie = (void *)device; 1479 return B_OK; 1480 } 1481 1482 1483 static status_t 1484 usb_disk_device_removed(void *cookie) 1485 { 1486 TRACE("device_removed(0x%p)\n", cookie); 1487 disk_device *device = (disk_device *)cookie; 1488 1489 mutex_lock(&gDeviceListLock); 1490 if (gDeviceList == device) { 1491 gDeviceList = (disk_device *)device->link; 1492 } else { 1493 disk_device *element = gDeviceList; 1494 while (element) { 1495 if (element->link == device) { 1496 element->link = device->link; 1497 break; 1498 } 1499 1500 element = (disk_device *)element->link; 1501 } 1502 } 1503 gLunCount -= device->lun_count; 1504 gDeviceCount--; 1505 1506 device->removed = true; 1507 gUSBModule->cancel_queued_transfers(device->bulk_in); 1508 gUSBModule->cancel_queued_transfers(device->bulk_out); 1509 if (device->open_count == 0) 1510 usb_disk_free_device_and_luns(device); 1511 1512 mutex_unlock(&gDeviceListLock); 1513 return B_OK; 1514 } 1515 1516 1517 // 1518 //#pragma mark - Partial Buffer Functions 1519 // 1520 1521 1522 static bool 1523 usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length, 1524 uint32 &blockPosition, uint16 &blockCount) 1525 { 1526 blockPosition = (uint32)(position / lun->block_size); 1527 if ((off_t)blockPosition * lun->block_size != position) 1528 return true; 1529 1530 blockCount = (uint16)(length / lun->block_size); 1531 if ((size_t)blockCount * lun->block_size != length) 1532 return true; 1533 1534 return false; 1535 } 1536 1537 1538 static status_t 1539 usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, 1540 void *buffer, size_t *length) 1541 { 1542 uint8 commandBlock[12]; 1543 memset(commandBlock, 0, sizeof(commandBlock)); 1544 if (lun->device->is_ufi) { 1545 commandBlock[0] = SCSI_READ_12; 1546 commandBlock[1] = lun->logical_unit_number << 5; 1547 commandBlock[2] = blockPosition >> 24; 1548 commandBlock[3] = blockPosition >> 16; 1549 commandBlock[4] = blockPosition >> 8; 1550 commandBlock[5] = blockPosition; 1551 commandBlock[6] = 0; // blockCount >> 24; 1552 commandBlock[7] = 0; // blockCount >> 16; 1553 commandBlock[8] = blockCount >> 8; 1554 commandBlock[9] = blockCount; 1555 1556 status_t result = B_OK; 1557 for (int tries = 0; tries < 5; tries++) { 1558 result = usb_disk_operation(lun, commandBlock, 12, buffer, length, 1559 true); 1560 if (result == B_OK) 1561 break; 1562 else 1563 snooze(10000); 1564 } 1565 return result; 1566 } else { 1567 commandBlock[0] = SCSI_READ_10; 1568 commandBlock[1] = 0; 1569 commandBlock[2] = blockPosition >> 24; 1570 commandBlock[3] = blockPosition >> 16; 1571 commandBlock[4] = blockPosition >> 8; 1572 commandBlock[5] = blockPosition; 1573 commandBlock[7] = blockCount >> 8; 1574 commandBlock[8] = blockCount; 1575 status_t result = usb_disk_operation(lun, commandBlock, 10, 1576 buffer, length, true); 1577 return result; 1578 } 1579 } 1580 1581 1582 static status_t 1583 usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, 1584 void *buffer, size_t *length) 1585 { 1586 uint8 commandBlock[12]; 1587 memset(commandBlock, 0, sizeof(commandBlock)); 1588 1589 if (lun->device->is_ufi) { 1590 commandBlock[0] = SCSI_WRITE_12; 1591 commandBlock[1] = lun->logical_unit_number << 5; 1592 commandBlock[2] = blockPosition >> 24; 1593 commandBlock[3] = blockPosition >> 16; 1594 commandBlock[4] = blockPosition >> 8; 1595 commandBlock[5] = blockPosition; 1596 commandBlock[6] = blockCount >> 24; 1597 commandBlock[7] = blockCount >> 16; 1598 commandBlock[8] = blockCount >> 8; 1599 commandBlock[9] = blockCount; 1600 1601 status_t result; 1602 result = usb_disk_operation(lun, commandBlock, 12, buffer, length, 1603 false); 1604 1605 int retry = 10; 1606 err_act action = err_act_ok; 1607 while (result == B_DEV_NO_MEDIA && retry > 0) { 1608 snooze(10000); 1609 result = usb_disk_request_sense(lun, &action); 1610 retry--; 1611 } 1612 1613 if (result == B_OK) 1614 lun->should_sync = true; 1615 return result; 1616 } else { 1617 commandBlock[0] = SCSI_WRITE_10; 1618 commandBlock[2] = blockPosition >> 24; 1619 commandBlock[3] = blockPosition >> 16; 1620 commandBlock[4] = blockPosition >> 8; 1621 commandBlock[5] = blockPosition; 1622 commandBlock[7] = blockCount >> 8; 1623 commandBlock[8] = blockCount; 1624 status_t result = usb_disk_operation(lun, commandBlock, 10, 1625 buffer, length, false); 1626 if (result == B_OK) 1627 lun->should_sync = true; 1628 return result; 1629 } 1630 } 1631 1632 1633 static status_t 1634 usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length, 1635 void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition, 1636 uint16 &blockCount) 1637 { 1638 blockPosition = (uint32)(position / lun->block_size); 1639 blockCount = (uint16)((uint32)((position + length + lun->block_size - 1) 1640 / lun->block_size) - blockPosition); 1641 size_t blockLength = blockCount * lun->block_size; 1642 blockBuffer = malloc(blockLength); 1643 if (blockBuffer == NULL) { 1644 TRACE_ALWAYS("no memory to allocate partial buffer\n"); 1645 return B_NO_MEMORY; 1646 } 1647 1648 status_t result = usb_disk_block_read(lun, blockPosition, blockCount, 1649 blockBuffer, &blockLength); 1650 if (result != B_OK) { 1651 TRACE_ALWAYS("block read failed when filling partial buffer: %s\n", 1652 strerror(result)); 1653 free(blockBuffer); 1654 return result; 1655 } 1656 1657 off_t offset = position - (off_t)blockPosition * lun->block_size; 1658 partialBuffer = (uint8 *)blockBuffer + offset; 1659 return B_OK; 1660 } 1661 1662 1663 // 1664 //#pragma mark - Driver Hooks 1665 // 1666 1667 1668 static status_t 1669 usb_disk_open(const char *name, uint32 flags, void **cookie) 1670 { 1671 TRACE("open(%s)\n", name); 1672 if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0) 1673 return B_NAME_NOT_FOUND; 1674 1675 int32 lastPart = 0; 1676 size_t nameLength = strlen(name); 1677 for (int32 i = nameLength - 1; i >= 0; i--) { 1678 if (name[i] == '/') { 1679 lastPart = i; 1680 break; 1681 } 1682 } 1683 1684 char rawName[nameLength + 4]; 1685 strncpy(rawName, name, lastPart + 1); 1686 rawName[lastPart + 1] = 0; 1687 strcat(rawName, "raw"); 1688 TRACE("opening raw device %s for %s\n", rawName, name); 1689 1690 mutex_lock(&gDeviceListLock); 1691 disk_device *device = gDeviceList; 1692 while (device) { 1693 for (uint8 i = 0; i < device->lun_count; i++) { 1694 device_lun *lun = device->luns[i]; 1695 if (strncmp(rawName, lun->name, 32) == 0) { 1696 // found the matching device/lun 1697 if (device->removed) { 1698 mutex_unlock(&gDeviceListLock); 1699 return B_ERROR; 1700 } 1701 1702 device->open_count++; 1703 *cookie = lun; 1704 mutex_unlock(&gDeviceListLock); 1705 return B_OK; 1706 } 1707 } 1708 1709 device = (disk_device *)device->link; 1710 } 1711 1712 mutex_unlock(&gDeviceListLock); 1713 return B_NAME_NOT_FOUND; 1714 } 1715 1716 1717 static status_t 1718 usb_disk_close(void *cookie) 1719 { 1720 TRACE("close()\n"); 1721 device_lun *lun = (device_lun *)cookie; 1722 disk_device *device = lun->device; 1723 1724 mutex_lock(&device->lock); 1725 if (!device->removed) 1726 usb_disk_synchronize(lun, false); 1727 mutex_unlock(&device->lock); 1728 1729 return B_OK; 1730 } 1731 1732 1733 static status_t 1734 usb_disk_free(void *cookie) 1735 { 1736 TRACE("free()\n"); 1737 mutex_lock(&gDeviceListLock); 1738 1739 device_lun *lun = (device_lun *)cookie; 1740 disk_device *device = lun->device; 1741 device->open_count--; 1742 if (device->open_count == 0 && device->removed) { 1743 // we can simply free the device here as it has been removed from 1744 // the device list in the device removed notification hook 1745 usb_disk_free_device_and_luns(device); 1746 } 1747 1748 mutex_unlock(&gDeviceListLock); 1749 return B_OK; 1750 } 1751 1752 1753 static inline void 1754 normalize_name(char *name, size_t nameLength) 1755 { 1756 bool wasSpace = false; 1757 size_t insertIndex = 0; 1758 for (size_t i = 0; i < nameLength; i++) { 1759 bool isSpace = name[i] == ' '; 1760 if (isSpace && wasSpace) 1761 continue; 1762 1763 name[insertIndex++] = name[i]; 1764 wasSpace = isSpace; 1765 } 1766 1767 if (insertIndex > 0 && name[insertIndex - 1] == ' ') 1768 insertIndex--; 1769 1770 name[insertIndex] = 0; 1771 } 1772 1773 1774 static status_t 1775 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) 1776 { 1777 device_lun *lun = (device_lun *)cookie; 1778 disk_device *device = lun->device; 1779 MutexLocker locker(&device->lock); 1780 if (device->removed) 1781 return B_DEV_NOT_READY; 1782 1783 switch (op) { 1784 case B_GET_DEVICE_SIZE: { 1785 if (lun->media_changed) { 1786 status_t result = usb_disk_update_capacity(lun); 1787 if (result != B_OK) 1788 return result; 1789 } 1790 1791 size_t size = lun->block_size * lun->block_count; 1792 return user_memcpy(buffer, &size, sizeof(size)); 1793 } 1794 1795 case B_GET_MEDIA_STATUS: 1796 { 1797 err_act action = err_act_ok; 1798 status_t ready; 1799 for (uint32 tries = 0; tries < 3; tries++) { 1800 ready = usb_disk_test_unit_ready(lun, &action); 1801 if (ready == B_OK || ready == B_DEV_NO_MEDIA 1802 || (action != err_act_retry 1803 && action != err_act_many_retries)) { 1804 if (IS_USER_ADDRESS(buffer)) { 1805 if (user_memcpy(buffer, &ready, sizeof(status_t)) != B_OK) 1806 return B_BAD_ADDRESS; 1807 } else if (is_called_via_syscall()) { 1808 return B_BAD_ADDRESS; 1809 } else 1810 *(status_t *)buffer = ready; 1811 break; 1812 } 1813 snooze(500000); 1814 } 1815 TRACE("B_GET_MEDIA_STATUS: 0x%08" B_PRIx32 "\n", ready); 1816 return B_OK; 1817 } 1818 1819 case B_GET_GEOMETRY: 1820 { 1821 if (lun->media_changed) { 1822 status_t result = usb_disk_update_capacity(lun); 1823 if (result != B_OK) 1824 return result; 1825 } 1826 1827 device_geometry geometry; 1828 devfs_compute_geometry_size(&geometry, lun->block_count, 1829 lun->block_size); 1830 1831 geometry.device_type = lun->device_type; 1832 geometry.removable = lun->removable; 1833 geometry.read_only = lun->write_protected; 1834 geometry.write_once = lun->device_type == B_WORM; 1835 TRACE("B_GET_GEOMETRY: %" B_PRId32 " sectors at %" B_PRId32 1836 " bytes per sector\n", geometry.cylinder_count, 1837 geometry.bytes_per_sector); 1838 return user_memcpy(buffer, &geometry, sizeof(device_geometry)); 1839 } 1840 1841 case B_FLUSH_DRIVE_CACHE: 1842 TRACE("B_FLUSH_DRIVE_CACHE\n"); 1843 return usb_disk_synchronize(lun, true); 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 return usb_disk_operation(lun, commandBlock, 6, NULL, NULL, 1855 false); 1856 } 1857 1858 case B_LOAD_MEDIA: 1859 { 1860 uint8 commandBlock[12]; 1861 memset(commandBlock, 0, sizeof(commandBlock)); 1862 1863 commandBlock[0] = SCSI_START_STOP_UNIT_6; 1864 commandBlock[1] = lun->logical_unit_number << 5; 1865 commandBlock[4] = 3; 1866 1867 return usb_disk_operation(lun, commandBlock, 6, NULL, NULL, 1868 false); 1869 } 1870 1871 case B_GET_ICON: 1872 // We don't support this legacy ioctl anymore, but the two other 1873 // icon ioctls below instead. 1874 break; 1875 1876 case B_GET_ICON_NAME: 1877 { 1878 const char *iconName = "devices/drive-removable-media-usb"; 1879 char vendor[sizeof(lun->vendor_name)+1]; 1880 char product[sizeof(lun->product_name)+1]; 1881 1882 if (device->is_ufi) { 1883 iconName = "devices/drive-floppy-usb"; 1884 } 1885 1886 switch (lun->device_type) { 1887 case B_CD: 1888 case B_OPTICAL: 1889 iconName = "devices/drive-optical"; 1890 break; 1891 case B_TAPE: // TODO 1892 default: 1893 snprintf(vendor, sizeof(vendor), "%.8s", 1894 lun->vendor_name); 1895 snprintf(product, sizeof(product), "%.16s", 1896 lun->product_name); 1897 for (int i = 0; kIconMatches[i].icon; i++) { 1898 if (kIconMatches[i].vendor != NULL 1899 && strstr(vendor, kIconMatches[i].vendor) == NULL) 1900 continue; 1901 if (kIconMatches[i].product != NULL 1902 && strstr(product, kIconMatches[i].product) == NULL) 1903 continue; 1904 iconName = kIconMatches[i].name; 1905 } 1906 break; 1907 } 1908 return user_strlcpy((char *)buffer, iconName, 1909 B_FILE_NAME_LENGTH); 1910 } 1911 1912 case B_GET_VECTOR_ICON: 1913 { 1914 device_icon *icon = &kKeyIconData; 1915 char vendor[sizeof(lun->vendor_name)+1]; 1916 char product[sizeof(lun->product_name)+1]; 1917 1918 if (length != sizeof(device_icon)) 1919 return B_BAD_VALUE; 1920 1921 if (device->is_ufi) { 1922 // UFI is specific for floppy drives 1923 icon = &kFloppyIconData; 1924 } else { 1925 switch (lun->device_type) { 1926 case B_CD: 1927 case B_OPTICAL: 1928 icon = &kCDIconData; 1929 break; 1930 case B_TAPE: // TODO 1931 default: 1932 snprintf(vendor, sizeof(vendor), "%.8s", 1933 lun->vendor_name); 1934 snprintf(product, sizeof(product), "%.16s", 1935 lun->product_name); 1936 for (int i = 0; kIconMatches[i].icon; i++) { 1937 if (kIconMatches[i].vendor != NULL 1938 && strstr(vendor, 1939 kIconMatches[i].vendor) == NULL) 1940 continue; 1941 if (kIconMatches[i].product != NULL 1942 && strstr(product, 1943 kIconMatches[i].product) == NULL) 1944 continue; 1945 icon = kIconMatches[i].icon; 1946 } 1947 break; 1948 } 1949 } 1950 1951 device_icon iconData; 1952 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) 1953 return B_BAD_ADDRESS; 1954 1955 if (iconData.icon_size >= icon->icon_size) { 1956 if (user_memcpy(iconData.icon_data, icon->icon_data, 1957 (size_t)icon->icon_size) != B_OK) 1958 return B_BAD_ADDRESS; 1959 } 1960 1961 iconData.icon_size = icon->icon_size; 1962 return user_memcpy(buffer, &iconData, sizeof(device_icon)); 1963 } 1964 1965 case B_GET_DEVICE_NAME: 1966 { 1967 size_t nameLength = sizeof(lun->vendor_name) 1968 + sizeof(lun->product_name) + sizeof(lun->product_revision) + 3; 1969 1970 char name[nameLength]; 1971 snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name, 1972 lun->product_name, lun->product_revision); 1973 1974 normalize_name(name, nameLength); 1975 1976 status_t result = user_strlcpy((char *)buffer, name, length); 1977 if (result > 0) 1978 result = B_OK; 1979 1980 TRACE_ALWAYS("got device name \"%s\": %s\n", name, 1981 strerror(result)); 1982 return result; 1983 } 1984 } 1985 1986 TRACE_ALWAYS("unhandled ioctl %" B_PRId32 "\n", op); 1987 return B_DEV_INVALID_IOCTL; 1988 } 1989 1990 1991 static status_t 1992 usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) 1993 { 1994 if (buffer == NULL || length == NULL) 1995 return B_BAD_VALUE; 1996 1997 TRACE("read(%" B_PRIdOFF ", %ld)\n", position, *length); 1998 device_lun *lun = (device_lun *)cookie; 1999 disk_device *device = lun->device; 2000 mutex_lock(&device->lock); 2001 if (device->removed) { 2002 *length = 0; 2003 mutex_unlock(&device->lock); 2004 return B_DEV_NOT_READY; 2005 } 2006 2007 status_t result = B_ERROR; 2008 uint32 blockPosition = 0; 2009 uint16 blockCount = 0; 2010 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length, 2011 blockPosition, blockCount); 2012 if (needsPartial) { 2013 void *partialBuffer = NULL; 2014 void *blockBuffer = NULL; 2015 result = usb_disk_prepare_partial_buffer(lun, position, *length, 2016 partialBuffer, blockBuffer, blockPosition, blockCount); 2017 if (result == B_OK) { 2018 if (IS_USER_ADDRESS(buffer)) 2019 result = user_memcpy(buffer, partialBuffer, *length); 2020 else 2021 memcpy(buffer, partialBuffer, *length); 2022 free(blockBuffer); 2023 } 2024 } else { 2025 result = usb_disk_block_read(lun, blockPosition, blockCount, buffer, 2026 length); 2027 } 2028 2029 mutex_unlock(&device->lock); 2030 if (result == B_OK) { 2031 TRACE("read successful with %ld bytes\n", *length); 2032 return B_OK; 2033 } 2034 2035 *length = 0; 2036 TRACE_ALWAYS("read failed: %s\n", strerror(result)); 2037 return result; 2038 } 2039 2040 2041 static status_t 2042 usb_disk_write(void *cookie, off_t position, const void *buffer, 2043 size_t *length) 2044 { 2045 if (buffer == NULL || length == NULL) 2046 return B_BAD_VALUE; 2047 2048 TRACE("write(%" B_PRIdOFF", %ld)\n", position, *length); 2049 device_lun *lun = (device_lun *)cookie; 2050 disk_device *device = lun->device; 2051 mutex_lock(&device->lock); 2052 if (device->removed) { 2053 *length = 0; 2054 mutex_unlock(&device->lock); 2055 return B_DEV_NOT_READY; 2056 } 2057 2058 status_t result = B_ERROR; 2059 uint32 blockPosition = 0; 2060 uint16 blockCount = 0; 2061 bool needsPartial = usb_disk_needs_partial_buffer(lun, position, 2062 *length, blockPosition, blockCount); 2063 if (needsPartial) { 2064 void *partialBuffer = NULL; 2065 void *blockBuffer = NULL; 2066 result = usb_disk_prepare_partial_buffer(lun, position, *length, 2067 partialBuffer, blockBuffer, blockPosition, blockCount); 2068 if (result == B_OK) { 2069 if (IS_USER_ADDRESS(buffer)) 2070 result = user_memcpy(partialBuffer, buffer, *length); 2071 else 2072 memcpy(partialBuffer, buffer, *length); 2073 } 2074 if (result == B_OK) { 2075 size_t blockLength = blockCount * lun->block_size; 2076 result = usb_disk_block_write(lun, blockPosition, blockCount, 2077 blockBuffer, &blockLength); 2078 free(blockBuffer); 2079 } 2080 } else { 2081 result = usb_disk_block_write(lun, blockPosition, blockCount, 2082 (void *)buffer, length); 2083 } 2084 2085 mutex_unlock(&device->lock); 2086 if (result == B_OK) { 2087 TRACE("write successful with %ld bytes\n", *length); 2088 return B_OK; 2089 } 2090 2091 *length = 0; 2092 TRACE_ALWAYS("write failed: %s\n", strerror(result)); 2093 return result; 2094 } 2095 2096 2097 // 2098 //#pragma mark - Driver Entry Points 2099 // 2100 2101 2102 status_t 2103 init_hardware() 2104 { 2105 TRACE("init_hardware()\n"); 2106 return B_OK; 2107 } 2108 2109 2110 status_t 2111 init_driver() 2112 { 2113 TRACE("init_driver()\n"); 2114 static usb_notify_hooks notifyHooks = { 2115 &usb_disk_device_added, 2116 &usb_disk_device_removed 2117 }; 2118 2119 static usb_support_descriptor supportedDevices[] = { 2120 { 0x08 /* mass storage */, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 }, 2121 { 0x08 /* mass storage */, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 }, 2122 { 0x08 /* mass storage */, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 }, 2123 { 0x08 /* mass storage */, 0x04 /* UFI */, 0x00, 0, 0 } 2124 }; 2125 2126 gDeviceList = NULL; 2127 gDeviceCount = 0; 2128 gLunCount = 0; 2129 mutex_init(&gDeviceListLock, "usb_disk device list lock"); 2130 2131 TRACE("trying module %s\n", B_USB_MODULE_NAME); 2132 status_t result = get_module(B_USB_MODULE_NAME, 2133 (module_info **)&gUSBModule); 2134 if (result < B_OK) { 2135 TRACE_ALWAYS("getting module failed: %s\n", strerror(result)); 2136 mutex_destroy(&gDeviceListLock); 2137 return result; 2138 } 2139 2140 gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 4, NULL); 2141 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 2142 return B_OK; 2143 } 2144 2145 2146 void 2147 uninit_driver() 2148 { 2149 TRACE("uninit_driver()\n"); 2150 gUSBModule->uninstall_notify(DRIVER_NAME); 2151 mutex_lock(&gDeviceListLock); 2152 2153 if (gDeviceNames) { 2154 for (int32 i = 0; gDeviceNames[i]; i++) 2155 free(gDeviceNames[i]); 2156 free(gDeviceNames); 2157 gDeviceNames = NULL; 2158 } 2159 2160 mutex_destroy(&gDeviceListLock); 2161 put_module(B_USB_MODULE_NAME); 2162 } 2163 2164 2165 const char ** 2166 publish_devices() 2167 { 2168 TRACE("publish_devices()\n"); 2169 if (gDeviceNames) { 2170 for (int32 i = 0; gDeviceNames[i]; i++) 2171 free(gDeviceNames[i]); 2172 free(gDeviceNames); 2173 gDeviceNames = NULL; 2174 } 2175 2176 gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1)); 2177 if (gDeviceNames == NULL) 2178 return NULL; 2179 2180 int32 index = 0; 2181 mutex_lock(&gDeviceListLock); 2182 disk_device *device = gDeviceList; 2183 while (device) { 2184 for (uint8 i = 0; i < device->lun_count; i++) 2185 gDeviceNames[index++] = strdup(device->luns[i]->name); 2186 2187 device = (disk_device *)device->link; 2188 } 2189 2190 gDeviceNames[index++] = NULL; 2191 mutex_unlock(&gDeviceListLock); 2192 return (const char **)gDeviceNames; 2193 } 2194 2195 2196 device_hooks * 2197 find_device(const char *name) 2198 { 2199 TRACE("find_device()\n"); 2200 static device_hooks hooks = { 2201 &usb_disk_open, 2202 &usb_disk_close, 2203 &usb_disk_free, 2204 &usb_disk_ioctl, 2205 &usb_disk_read, 2206 &usb_disk_write, 2207 NULL, 2208 NULL, 2209 NULL, 2210 NULL 2211 }; 2212 2213 return &hooks; 2214 } 2215