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