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