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