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