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