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