xref: /haiku/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
1 /*
2  * Copyright 2008-2010, 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 #include <ByteOrder.h>
10 #include <KernelExport.h>
11 #include <Drivers.h>
12 #include <malloc.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include "usb_disk.h"
16 #include "usb_disk_scsi.h"
17 
18 
19 #define DRIVER_NAME			"usb_disk"
20 #define DEVICE_NAME_BASE	"disk/usb/"
21 #define DEVICE_NAME			DEVICE_NAME_BASE"%ld/%d/raw"
22 
23 
24 //#define TRACE_USB_DISK
25 #ifdef TRACE_USB_DISK
26 #define TRACE(x...)			dprintf(DRIVER_NAME": "x)
27 #define TRACE_ALWAYS(x...)	dprintf(DRIVER_NAME": "x)
28 #else
29 #define TRACE(x...)			/* nothing */
30 #define TRACE_ALWAYS(x...)	dprintf(DRIVER_NAME": "x)
31 #endif
32 
33 
34 int32 api_version = B_CUR_DRIVER_API_VERSION;
35 static usb_module_info *gUSBModule = NULL;
36 static disk_device *gDeviceList = NULL;
37 static uint32 gDeviceCount = 0;
38 static uint32 gLunCount = 0;
39 static mutex gDeviceListLock;
40 static char **gDeviceNames = NULL;
41 
42 static uint8 kDeviceIcon[] = {
43 	0x6e, 0x63, 0x69, 0x66, 0x0a, 0x04, 0x01, 0x73, 0x05, 0x01, 0x02, 0x01,
44 	0x06, 0x02, 0xb1, 0xf8, 0x5d, 0x3a, 0x2f, 0xbf, 0xbe, 0xdb, 0x67, 0xb6,
45 	0x98, 0x06, 0x4b, 0x22, 0x15, 0x47, 0x13, 0x02, 0x00, 0xed, 0xed, 0xed,
46 	0xff, 0xab, 0xbc, 0xc6, 0x02, 0x01, 0x06, 0x02, 0xb9, 0x82, 0x56, 0x32,
47 	0x7d, 0xfb, 0xb8, 0x06, 0x39, 0xbe, 0xd9, 0xb5, 0x4b, 0x7d, 0x31, 0x4a,
48 	0xa4, 0xe7, 0x00, 0xd1, 0xde, 0xe4, 0xff, 0x7a, 0x9c, 0xae, 0x02, 0x00,
49 	0x16, 0x02, 0x38, 0xe9, 0xaa, 0x3b, 0x7b, 0x1d, 0xbf, 0xb0, 0xa6, 0x3d,
50 	0x16, 0x76, 0x4b, 0x84, 0x81, 0x48, 0x37, 0x36, 0x00, 0x99, 0xff, 0x53,
51 	0x02, 0x00, 0x16, 0x02, 0xba, 0x38, 0x9a, 0xb8, 0xef, 0x79, 0x3e, 0x34,
52 	0x8b, 0xbf, 0x56, 0x52, 0x48, 0x2c, 0x61, 0x4c, 0x4e, 0xec, 0x00, 0x40,
53 	0xff, 0x01, 0x05, 0xff, 0x05, 0x46, 0x02, 0x01, 0x16, 0x02, 0x35, 0xc2,
54 	0x71, 0x3a, 0xf6, 0x84, 0xb9, 0xf3, 0x5b, 0x34, 0x81, 0xa0, 0x49, 0xc0,
55 	0x57, 0x49, 0x6e, 0x51, 0xff, 0xf3, 0x00, 0x52, 0x02, 0x01, 0x06, 0x02,
56 	0x38, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x80, 0x00,
57 	0x49, 0xa0, 0x00, 0x49, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x06,
58 	0xe3, 0x06, 0x0c, 0x06, 0x09, 0xab, 0xaa, 0x03, 0x3e, 0x5e, 0x3c, 0x5f,
59 	0x3e, 0x5e, 0x60, 0x4d, 0x5a, 0x4a, 0x60, 0x47, 0x56, 0x42, 0x50, 0x45,
60 	0x4c, 0x43, 0x2a, 0x54, 0x36, 0x5d, 0x36, 0x5d, 0x3a, 0x60, 0x06, 0x08,
61 	0xfb, 0xea, 0x27, 0x49, 0x26, 0x48, 0x27, 0x49, 0x32, 0x56, 0x37, 0x59,
62 	0x37, 0x59, 0x38, 0x5a, 0x3b, 0x59, 0x3a, 0x5a, 0x3b, 0x59, 0x58, 0x3c,
63 	0x52, 0x36, 0x43, 0x29, 0x27, 0x45, 0x27, 0x45, 0x26, 0x46, 0x06, 0x05,
64 	0xab, 0x03, 0x27, 0x49, 0x26, 0x48, 0x27, 0x49, 0x32, 0x56, 0x52, 0x36,
65 	0x43, 0x29, 0x27, 0x45, 0x27, 0x45, 0x26, 0x46, 0x0a, 0x05, 0xc2, 0x1c,
66 	0xb8, 0xf9, 0x4f, 0x25, 0xc9, 0x4c, 0xb7, 0xc4, 0x5a, 0x30, 0x51, 0x39,
67 	0x0a, 0x04, 0xc5, 0x50, 0xbb, 0xc0, 0xc2, 0x1c, 0xb8, 0xf9, 0x4f, 0x25,
68 	0xc9, 0x4c, 0xb7, 0xc4, 0x0a, 0x04, 0x51, 0x39, 0xc5, 0x50, 0xbb, 0xc0,
69 	0xc9, 0x4c, 0xb7, 0xc4, 0x5a, 0x30, 0x0a, 0x04, 0x4f, 0x2f, 0x51, 0x31,
70 	0x53, 0x2f, 0x51, 0x2d, 0x06, 0x04, 0xee, 0x4f, 0x35, 0x53, 0x30, 0x51,
71 	0x32, 0x55, 0x2e, 0x58, 0x2c, 0x54, 0x31, 0x56, 0x2f, 0x52, 0x33, 0x06,
72 	0x04, 0xee, 0x31, 0x58, 0x40, 0x47, 0x39, 0x4e, 0x47, 0x40, 0x50, 0x38,
73 	0x41, 0x48, 0x48, 0x41, 0x3a, 0x4f, 0x08, 0x02, 0x3a, 0x40, 0x3e, 0x3c,
74 	0x02, 0x04, 0x3e, 0x3a, 0xbe, 0x48, 0x3a, 0xbf, 0x9f, 0x3a, 0x41, 0x3d,
75 	0x41, 0xbd, 0xe2, 0x41, 0xbf, 0x39, 0x3e, 0x40, 0xbf, 0x9f, 0x40, 0xbe,
76 	0x48, 0x40, 0x3b, 0x3d, 0x3b, 0xbf, 0x39, 0x3b, 0xbd, 0xe2, 0x06, 0x05,
77 	0xbe, 0x02, 0x32, 0x56, 0x36, 0x5a, 0x36, 0x5a, 0x37, 0x5b, 0x3a, 0x5a,
78 	0x39, 0x5b, 0x3a, 0x5a, 0x58, 0x3c, 0x52, 0x36, 0x11, 0x0a, 0x00, 0x01,
79 	0x00, 0x00, 0x0a, 0x01, 0x01, 0x03, 0x12, 0x3f, 0xe9, 0x8e, 0xbb, 0x54,
80 	0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0x4d, 0xd9, 0x45, 0xc0,
81 	0xc5, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x02, 0x01, 0x04, 0x02, 0x3f,
82 	0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6,
83 	0x4d, 0xd9, 0x45, 0xc0, 0xc5, 0x0a, 0x03, 0x01, 0x05, 0x02, 0x3f, 0xe9,
84 	0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0x4d,
85 	0xd9, 0x45, 0xc0, 0xc5, 0x0a, 0x01, 0x01, 0x01, 0x12, 0x3f, 0xe9, 0x8e,
86 	0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0xb0, 0x64,
87 	0x46, 0x78, 0x3b, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x04, 0x01, 0x02,
88 	0x02, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9,
89 	0x8e, 0xc6, 0xb0, 0x64, 0x46, 0x78, 0x3b, 0x0a, 0x05, 0x01, 0x0b, 0x02,
90 	0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e,
91 	0xc6, 0xb0, 0x64, 0x46, 0x78, 0x3b, 0x0a, 0x01, 0x01, 0x06, 0x02, 0x3f,
92 	0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6,
93 	0x5b, 0x2d, 0x45, 0x43, 0x93, 0x0a, 0x01, 0x01, 0x06, 0x02, 0x3f, 0xe9,
94 	0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc7, 0x7d,
95 	0x8b, 0x44, 0x36, 0x9a, 0x0a, 0x06, 0x02, 0x07, 0x08, 0x02, 0x3f, 0xe9,
96 	0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0x4d,
97 	0xd9, 0x45, 0xc0, 0xc5, 0x0a, 0x01, 0x01, 0x09, 0x12, 0x3f, 0x6c, 0x5c,
98 	0xba, 0xea, 0x46, 0x3a, 0xea, 0x46, 0x3f, 0x6c, 0x5c, 0xc5, 0x19, 0x6c,
99 	0x46, 0x6b, 0x36, 0x01, 0x17, 0x8c, 0x22, 0x04, 0x0a, 0x07, 0x01, 0x09,
100 	0x12, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9,
101 	0x8e, 0xc6, 0x4d, 0xd9, 0x45, 0xc0, 0xc5, 0x01, 0x17, 0x88, 0x22, 0x04,
102 	0x0a, 0x08, 0x01, 0x09, 0x12, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b,
103 	0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0x01, 0xed, 0x46, 0x11, 0xa8, 0x01,
104 	0x17, 0x85, 0x22, 0x04, 0x0a, 0x01, 0x01, 0x0a, 0x12, 0x3f, 0xe9, 0x8e,
105 	0xbb, 0x54, 0xe2, 0x3a, 0xaa, 0x52, 0x3f, 0x21, 0x43, 0xc6, 0x59, 0xd0,
106 	0x46, 0xdb, 0x8c, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x06, 0x01, 0x0a,
107 	0x02, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9,
108 	0x8e, 0xc6, 0x99, 0xc6, 0x45, 0x5e, 0x3a, 0x0a, 0x01, 0x01, 0x0a, 0x12,
109 	0x3f, 0x21, 0x43, 0xba, 0xaa, 0x52, 0x3a, 0xaa, 0x52, 0x3f, 0x21, 0x43,
110 	0xc7, 0xd2, 0xa7, 0x49, 0x5f, 0xed, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a,
111 	0x09, 0x01, 0x0a, 0x02, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54,
112 	0xe2, 0x3f, 0xe9, 0x8e, 0xc8, 0xa5, 0xc8, 0x48, 0xeb, 0x05
113 };
114 
115 
116 //
117 //#pragma mark - Forward Declarations
118 //
119 
120 
121 static void	usb_disk_callback(void *cookie, status_t status, void *data,
122 				size_t actualLength);
123 
124 status_t	usb_disk_mass_storage_reset(disk_device *device);
125 uint8		usb_disk_get_max_lun(disk_device *device);
126 void		usb_disk_reset_recovery(disk_device *device);
127 status_t	usb_disk_transfer_data(disk_device *device, bool directionIn,
128 				void *data, size_t dataLength);
129 status_t	usb_disk_receive_csw(disk_device *device,
130 				command_status_wrapper *status);
131 status_t	usb_disk_operation(device_lun *lun, uint8 operation,
132 				uint8 opLength, uint32 logicalBlockAddress,
133 				uint16 transferLength, void *data, uint32 *dataLength,
134 				bool directionIn);
135 
136 status_t	usb_disk_request_sense(device_lun *lun);
137 status_t	usb_disk_mode_sense(device_lun *lun);
138 status_t	usb_disk_test_unit_ready(device_lun *lun);
139 status_t	usb_disk_inquiry(device_lun *lun);
140 status_t	usb_disk_reset_capacity(device_lun *lun);
141 status_t	usb_disk_update_capacity(device_lun *lun);
142 status_t	usb_disk_synchronize(device_lun *lun, bool force);
143 
144 
145 //
146 //#pragma mark - Device Allocation Helper Functions
147 //
148 
149 
150 void
151 usb_disk_free_device_and_luns(disk_device *device)
152 {
153 	mutex_lock(&device->lock);
154 	mutex_destroy(&device->lock);
155 	delete_sem(device->notify);
156 	for (uint8 i = 0; i < device->lun_count; i++)
157 		free(device->luns[i]);
158 	free(device->luns);
159 	free(device);
160 }
161 
162 
163 //
164 //#pragma mark - Bulk-only Mass Storage Functions
165 //
166 
167 
168 status_t
169 usb_disk_mass_storage_reset(disk_device *device)
170 {
171 	return gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_OUT
172 		| USB_REQTYPE_CLASS, REQUEST_MASS_STORAGE_RESET, 0x0000,
173 		device->interface, 0, NULL, NULL);
174 }
175 
176 
177 uint8
178 usb_disk_get_max_lun(disk_device *device)
179 {
180 	uint8 result = 0;
181 	size_t actualLength = 0;
182 
183 	// devices that do not support multiple LUNs may stall this request
184 	if (gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_IN
185 		| USB_REQTYPE_CLASS, REQUEST_GET_MAX_LUN, 0x0000, device->interface,
186 		1, &result, &actualLength) != B_OK || actualLength != 1)
187 		return 0;
188 
189 	if (result > MAX_LOGICAL_UNIT_NUMBER) {
190 		// invalid max lun
191 		return 0;
192 	}
193 
194 	return result;
195 }
196 
197 
198 void
199 usb_disk_reset_recovery(disk_device *device)
200 {
201 	usb_disk_mass_storage_reset(device);
202 	gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT);
203 	gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT);
204 }
205 
206 
207 status_t
208 usb_disk_transfer_data(disk_device *device, bool directionIn, void *data,
209 	size_t dataLength)
210 {
211 	status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in
212 		: device->bulk_out, data, dataLength, usb_disk_callback, device);
213 	if (result != B_OK) {
214 		TRACE_ALWAYS("failed to queue data transfer\n");
215 		return result;
216 	}
217 
218 	do {
219 		result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT,
220 			10 * 1000 * 1000);
221 		if (result == B_TIMED_OUT) {
222 			// Cancel the transfer and collect the sem that should now be
223 			// released through the callback on cancel. Handling of device
224 			// reset is done in usb_disk_operation() when it detects that
225 			// the transfer failed.
226 			gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in
227 				: device->bulk_out);
228 			acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0);
229 		}
230 	} while (result == B_INTERRUPTED);
231 
232 	if (result != B_OK) {
233 		TRACE_ALWAYS("acquire_sem failed while waiting for data transfer\n");
234 		return result;
235 	}
236 
237 	return B_OK;
238 }
239 
240 
241 status_t
242 usb_disk_receive_csw(disk_device *device, command_status_wrapper *status)
243 {
244 	status_t result = usb_disk_transfer_data(device, true, status,
245 		sizeof(command_status_wrapper));
246 	if (result != B_OK)
247 		return result;
248 
249 	if (device->status != B_OK
250 		|| device->actual_length != sizeof(command_status_wrapper)) {
251 		// receiving the command status wrapper failed
252 		return B_ERROR;
253 	}
254 
255 	return B_OK;
256 }
257 
258 
259 status_t
260 usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength,
261 	uint32 logicalBlockAddress, uint16 transferLength, void *data,
262 	uint32 *dataLength, bool directionIn)
263 {
264 	TRACE("operation: lun: %u; op: %u; oplen: %u; lba: %lu; tlen: %u; data: "
265 		"%p; dlen: %p (%lu); in: %c\n",
266 		lun->logical_unit_number, operation, opLength, logicalBlockAddress,
267 		transferLength, data, dataLength, dataLength ? *dataLength : 0,
268 		directionIn ? 'y' : 'n');
269 
270 	disk_device *device = lun->device;
271 	command_block_wrapper command;
272 	command.signature = CBW_SIGNATURE;
273 	command.tag = device->current_tag++;
274 	command.data_transfer_length = (dataLength != NULL ? *dataLength : 0);
275 	command.flags = (directionIn ? CBW_DATA_INPUT : CBW_DATA_OUTPUT);
276 	command.lun = lun->logical_unit_number;
277 	command.command_block_length
278 		= device->is_atapi ? ATAPI_COMMAND_LENGTH : opLength;
279 	memset(command.command_block, 0, sizeof(command.command_block));
280 
281 	switch (opLength) {
282 		case 6:
283 		{
284 			scsi_command_6 *commandBlock
285 				= (scsi_command_6 *)command.command_block;
286 			commandBlock->operation = operation;
287 			commandBlock->lun = lun->logical_unit_number << 5;
288 			commandBlock->allocation_length = (uint8)transferLength;
289 			if (operation == SCSI_MODE_SENSE_6) {
290 				// we hijack the lba argument to transport the desired page
291 				commandBlock->reserved[1] = (uint8)logicalBlockAddress;
292 			}
293 			break;
294 		}
295 
296 		case 10:
297 		{
298 			scsi_command_10 *commandBlock
299 				= (scsi_command_10 *)command.command_block;
300 			commandBlock->operation = operation;
301 			commandBlock->lun_flags = lun->logical_unit_number << 5;
302 			commandBlock->logical_block_address = htonl(logicalBlockAddress);
303 			commandBlock->transfer_length = htons(transferLength);
304 			break;
305 		}
306 
307 		default:
308 			TRACE_ALWAYS("unsupported operation length %d\n", opLength);
309 			return B_BAD_VALUE;
310 	}
311 
312 	status_t result = usb_disk_transfer_data(device, false, &command,
313 		sizeof(command_block_wrapper));
314 	if (result != B_OK)
315 		return result;
316 
317 	if (device->status != B_OK ||
318 		device->actual_length != sizeof(command_block_wrapper)) {
319 		// sending the command block wrapper failed
320 		TRACE_ALWAYS("sending the command block wrapper failed\n");
321 		usb_disk_reset_recovery(device);
322 		return B_ERROR;
323 	}
324 
325 	size_t transferedData = 0;
326 	if (data != NULL && dataLength != NULL && *dataLength > 0) {
327 		// we have data to transfer in a data stage
328 		result = usb_disk_transfer_data(device, directionIn, data,
329 			*dataLength);
330 		if (result != B_OK)
331 			return result;
332 
333 		transferedData = device->actual_length;
334 		if (device->status != B_OK || transferedData != *dataLength) {
335 			// sending or receiving of the data failed
336 			if (device->status == B_DEV_STALLED) {
337 				TRACE("stall while transfering data\n");
338 				gUSBModule->clear_feature(directionIn ? device->bulk_in
339 					: device->bulk_out, USB_FEATURE_ENDPOINT_HALT);
340 			} else {
341 				TRACE_ALWAYS("sending or receiving of the data failed\n");
342 				usb_disk_reset_recovery(device);
343 				return B_ERROR;
344 			}
345 		}
346 	}
347 
348 	command_status_wrapper status;
349 	result =  usb_disk_receive_csw(device, &status);
350 	if (result != B_OK) {
351 		// in case of a stall or error clear the stall and try again
352 		gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT);
353 		result = usb_disk_receive_csw(device, &status);
354 	}
355 
356 	if (result != B_OK) {
357 		TRACE_ALWAYS("receiving the command status wrapper failed\n");
358 		usb_disk_reset_recovery(device);
359 		return result;
360 	}
361 
362 	if (status.signature != CSW_SIGNATURE || status.tag != command.tag) {
363 		// the command status wrapper is not valid
364 		TRACE_ALWAYS("command status wrapper is not valid\n");
365 		usb_disk_reset_recovery(device);
366 		return B_ERROR;
367 	}
368 
369 	switch (status.status) {
370 		case CSW_STATUS_COMMAND_PASSED:
371 		case CSW_STATUS_COMMAND_FAILED:
372 		{
373 			// The residue from "status.data_residue" is not maintained
374 			// correctly by some devices, so calculate it instead.
375 			uint32 residue = command.data_transfer_length - transferedData;
376 
377 			if (dataLength != NULL) {
378 				*dataLength -= residue;
379 				if (transferedData < *dataLength) {
380 					TRACE_ALWAYS("less data transfered than indicated\n");
381 					*dataLength = transferedData;
382 				}
383 			}
384 
385 			if (status.status == CSW_STATUS_COMMAND_PASSED) {
386 				// the operation is complete and has succeeded
387 				return B_OK;
388 			} else {
389 				if (operation == SCSI_REQUEST_SENSE_6)
390 					return B_ERROR;
391 
392 				// the operation is complete but has failed at the SCSI level
393 				if (operation != SCSI_TEST_UNIT_READY_6) {
394 					TRACE_ALWAYS("operation 0x%02x failed at the SCSI level\n",
395 						operation);
396 				}
397 
398 				result = usb_disk_request_sense(lun);
399 				return result == B_OK ? B_ERROR : result;
400 			}
401 		}
402 
403 		case CSW_STATUS_PHASE_ERROR:
404 		{
405 			// a protocol or device error occured
406 			TRACE_ALWAYS("phase error in operation 0x%02x\n", operation);
407 			usb_disk_reset_recovery(device);
408 			return B_ERROR;
409 		}
410 
411 		default:
412 		{
413 			// command status wrapper is not meaningful
414 			TRACE_ALWAYS("command status wrapper has invalid status\n");
415 			usb_disk_reset_recovery(device);
416 			return B_ERROR;
417 		}
418 	}
419 }
420 
421 
422 //
423 //#pragma mark - Helper/Convenience Functions
424 //
425 
426 
427 status_t
428 usb_disk_request_sense(device_lun *lun)
429 {
430 	uint32 dataLength = sizeof(scsi_request_sense_6_parameter);
431 	scsi_request_sense_6_parameter parameter;
432 	status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0,
433 		dataLength, &parameter, &dataLength, true);
434 	if (result != B_OK) {
435 		TRACE_ALWAYS("getting request sense data failed\n");
436 		return result;
437 	}
438 
439 	if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY
440 		&& parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) {
441 		TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: "
442 			"0x%02x;\n", parameter.sense_key, parameter.additional_sense_code,
443 			parameter.additional_sense_code_qualifier);
444 	}
445 
446 	switch (parameter.sense_key) {
447 		case SCSI_SENSE_KEY_NO_SENSE:
448 		case SCSI_SENSE_KEY_RECOVERED_ERROR:
449 			return B_OK;
450 
451 		case SCSI_SENSE_KEY_HARDWARE_ERROR:
452 		case SCSI_SENSE_KEY_MEDIUM_ERROR:
453 			TRACE_ALWAYS("request_sense: media or hardware error\n");
454 			return B_DEV_UNREADABLE;
455 
456 		case SCSI_SENSE_KEY_ILLEGAL_REQUEST:
457 			TRACE_ALWAYS("request_sense: illegal request\n");
458 			return B_DEV_INVALID_IOCTL;
459 
460 		case SCSI_SENSE_KEY_UNIT_ATTENTION:
461 			if (parameter.additional_sense_code
462 					!= SCSI_ASC_MEDIUM_NOT_PRESENT) {
463 				TRACE_ALWAYS("request_sense: media changed\n");
464 				lun->media_changed = true;
465 				lun->media_present = true;
466 				return B_DEV_MEDIA_CHANGED;
467 			}
468 			// fall through
469 
470 		case SCSI_SENSE_KEY_NOT_READY:
471 			TRACE("request_sense: device not ready (asc 0x%02x ascq 0x%02x)\n",
472 				parameter.additional_sense_code,
473 				parameter.additional_sense_code_qualifier);
474 			lun->media_present = false;
475 			usb_disk_reset_capacity(lun);
476 			return B_DEV_NO_MEDIA;
477 
478 		case SCSI_SENSE_KEY_DATA_PROTECT:
479 			TRACE_ALWAYS("request_sense: write protected\n");
480 			return B_READ_ONLY_DEVICE;
481 
482 		case SCSI_SENSE_KEY_ABORTED_COMMAND:
483 			TRACE_ALWAYS("request_sense: command aborted\n");
484 			return B_CANCELED;
485 	}
486 
487 	return B_ERROR;
488 }
489 
490 
491 status_t
492 usb_disk_mode_sense(device_lun *lun)
493 {
494 	uint32 dataLength = sizeof(scsi_mode_sense_6_parameter);
495 	scsi_mode_sense_6_parameter parameter;
496 	status_t result = usb_disk_operation(lun, SCSI_MODE_SENSE_6, 6,
497 		SCSI_MODE_PAGE_DEVICE_CONFIGURATION, dataLength, &parameter,
498 		&dataLength, true);
499 	if (result != B_OK) {
500 		TRACE_ALWAYS("getting mode sense data failed\n");
501 		return result;
502 	}
503 
504 	lun->write_protected
505 		= (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT)
506 			!= 0;
507 	TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no");
508 	return B_OK;
509 }
510 
511 
512 status_t
513 usb_disk_test_unit_ready(device_lun *lun)
514 {
515 	// if unsupported we assume the unit is fixed and therefore always ok
516 	if (!lun->device->tur_supported)
517 		return B_OK;
518 
519 	status_t result;
520 	if (lun->device->is_atapi) {
521 		result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 1,
522 			NULL, NULL, false);
523 	} else {
524 		result = usb_disk_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0,
525 			NULL, NULL, true);
526 	}
527 
528 	if (result == B_DEV_INVALID_IOCTL) {
529 		lun->device->tur_supported = false;
530 		return B_OK;
531 	}
532 
533 	return result;
534 }
535 
536 
537 status_t
538 usb_disk_inquiry(device_lun *lun)
539 {
540 	uint32 dataLength = sizeof(scsi_inquiry_6_parameter);
541 	scsi_inquiry_6_parameter parameter;
542 	status_t result = B_ERROR;
543 	for (uint32 tries = 0; tries < 3; tries++) {
544 		result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength,
545 			&parameter, &dataLength, true);
546 		if (result == B_OK)
547 			break;
548 	}
549 	if (result != B_OK) {
550 		TRACE_ALWAYS("getting inquiry data failed\n");
551 		lun->device_type = B_DISK;
552 		lun->removable = true;
553 		return result;
554 	}
555 
556 	TRACE("peripherial_device_type  0x%02x\n",
557 		parameter.peripherial_device_type);
558 	TRACE("peripherial_qualifier    0x%02x\n",
559 		parameter.peripherial_qualifier);
560 	TRACE("removable_medium         %s\n",
561 		parameter.removable_medium ? "yes" : "no");
562 	TRACE("version                  0x%02x\n", parameter.version);
563 	TRACE("response_data_format     0x%02x\n", parameter.response_data_format);
564 	TRACE_ALWAYS("vendor_identification    \"%.8s\"\n",
565 		parameter.vendor_identification);
566 	TRACE_ALWAYS("product_identification   \"%.16s\"\n",
567 		parameter.product_identification);
568 	TRACE_ALWAYS("product_revision_level   \"%.4s\"\n",
569 		parameter.product_revision_level);
570 	lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */
571 	lun->removable = (parameter.removable_medium == 1);
572 	return B_OK;
573 }
574 
575 
576 status_t
577 usb_disk_reset_capacity(device_lun *lun)
578 {
579 	lun->block_size = 512;
580 	lun->block_count = 0;
581 	return B_OK;
582 }
583 
584 
585 status_t
586 usb_disk_update_capacity(device_lun *lun)
587 {
588 	uint32 dataLength = sizeof(scsi_read_capacity_10_parameter);
589 	scsi_read_capacity_10_parameter parameter;
590 	status_t result = B_ERROR;
591 
592 	// Retry reading the capacity up to three times. The first try might only
593 	// yield a unit attention telling us that the device or media status
594 	// changed, which is more or less expected if it is the first operation
595 	// on the device or the device only clears the unit atention for capacity
596 	// reads.
597 	for (int32 i = 0; i < 3; i++) {
598 		result = usb_disk_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0,
599 			&parameter, &dataLength, true);
600 		if (result == B_OK)
601 			break;
602 	}
603 
604 	if (result != B_OK) {
605 		TRACE_ALWAYS("failed to update capacity\n");
606 		lun->media_present = false;
607 		lun->media_changed = false;
608 		usb_disk_reset_capacity(lun);
609 		return result;
610 	}
611 
612 	lun->media_present = true;
613 	lun->media_changed = false;
614 	lun->block_size = ntohl(parameter.logical_block_length);
615 	lun->block_count = ntohl(parameter.last_logical_block_address) + 1;
616 	return B_OK;
617 }
618 
619 
620 status_t
621 usb_disk_synchronize(device_lun *lun, bool force)
622 {
623 	if (lun->device->sync_support == 0) {
624 		// this device reported an illegal request when syncing or repeatedly
625 		// returned an other error, it apparently does not support syncing...
626 		return B_UNSUPPORTED;
627 	}
628 
629 	if (!lun->should_sync && !force)
630 		return B_OK;
631 
632 	status_t result = usb_disk_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 10,
633 		0, 0, NULL, NULL, false);
634 
635 	if (result == B_OK) {
636 		lun->device->sync_support = SYNC_SUPPORT_RELOAD;
637 		lun->should_sync = false;
638 		return B_OK;
639 	}
640 
641 	if (result == B_DEV_INVALID_IOCTL)
642 		lun->device->sync_support = 0;
643 	else
644 		lun->device->sync_support--;
645 
646 	return result;
647 }
648 
649 
650 //
651 //#pragma mark - Device Attach/Detach Notifications and Callback
652 //
653 
654 
655 static void
656 usb_disk_callback(void *cookie, status_t status, void *data,
657 	size_t actualLength)
658 {
659 	//TRACE("callback()\n");
660 	disk_device *device = (disk_device *)cookie;
661 	device->status = status;
662 	device->actual_length = actualLength;
663 	release_sem(device->notify);
664 }
665 
666 
667 static status_t
668 usb_disk_device_added(usb_device newDevice, void **cookie)
669 {
670 	TRACE("device_added(0x%08lx)\n", newDevice);
671 	disk_device *device = (disk_device *)malloc(sizeof(disk_device));
672 	device->device = newDevice;
673 	device->removed = false;
674 	device->open_count = 0;
675 	device->interface = 0xff;
676 	device->current_tag = 0;
677 	device->sync_support = SYNC_SUPPORT_RELOAD;
678 	device->tur_supported = true;
679 	device->is_atapi = false;
680 	device->luns = NULL;
681 
682 	// scan through the interfaces to find our bulk-only data interface
683 	const usb_configuration_info *configuration
684 		= gUSBModule->get_configuration(newDevice);
685 	if (configuration == NULL) {
686 		free(device);
687 		return B_ERROR;
688 	}
689 
690 	for (size_t i = 0; i < configuration->interface_count; i++) {
691 		usb_interface_info *interface = configuration->interface[i].active;
692 		if (interface == NULL)
693 			continue;
694 
695 		if (interface->descr->interface_class == 0x08 /* mass storage */
696 			&& (interface->descr->interface_subclass == 0x06 /* SCSI */
697 				|| interface->descr->interface_subclass == 0x02 /* ATAPI */
698 				|| interface->descr->interface_subclass == 0x05 /* ATAPI */)
699 			&& interface->descr->interface_protocol == 0x50 /* bulk-only */) {
700 
701 			bool hasIn = false;
702 			bool hasOut = false;
703 			for (size_t j = 0; j < interface->endpoint_count; j++) {
704 				usb_endpoint_info *endpoint = &interface->endpoint[j];
705 				if (endpoint == NULL
706 					|| endpoint->descr->attributes != USB_ENDPOINT_ATTR_BULK)
707 					continue;
708 
709 				if (!hasIn && (endpoint->descr->endpoint_address
710 					& USB_ENDPOINT_ADDR_DIR_IN) != 0) {
711 					device->bulk_in = endpoint->handle;
712 					hasIn = true;
713 				} else if (!hasOut && (endpoint->descr->endpoint_address
714 					& USB_ENDPOINT_ADDR_DIR_IN) == 0) {
715 					device->bulk_out = endpoint->handle;
716 					hasOut = true;
717 				}
718 
719 				if (hasIn && hasOut)
720 					break;
721 			}
722 
723 			if (!(hasIn && hasOut))
724 				continue;
725 
726 			device->interface = interface->descr->interface_number;
727 			device->is_atapi = interface->descr->interface_subclass != 0x06;
728 			break;
729 		}
730 	}
731 
732 	if (device->interface == 0xff) {
733 		TRACE_ALWAYS("no valid bulk-only interface found\n");
734 		free(device);
735 		return B_ERROR;
736 	}
737 
738 	mutex_init(&device->lock, "usb_disk device lock");
739 
740 	device->notify = create_sem(0, "usb_disk callback notify");
741 	if (device->notify < B_OK) {
742 		mutex_destroy(&device->lock);
743 		status_t result = device->notify;
744 		free(device);
745 		return result;
746 	}
747 
748 	device->lun_count = usb_disk_get_max_lun(device) + 1;
749 	device->luns = (device_lun **)malloc(device->lun_count
750 		* sizeof(device_lun *));
751 	for (uint8 i = 0; i < device->lun_count; i++)
752 		device->luns[i] = NULL;
753 
754 	status_t result = B_OK;
755 
756 	TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count);
757 	for (uint8 i = 0; i < device->lun_count; i++) {
758 		// create the individual luns present on this device
759 		device_lun *lun = (device_lun *)malloc(sizeof(device_lun));
760 		if (lun == NULL) {
761 			result = B_NO_MEMORY;
762 			break;
763 		}
764 
765 		device->luns[i] = lun;
766 		lun->device = device;
767 		lun->logical_unit_number = i;
768 		lun->should_sync = false;
769 		lun->media_present = true;
770 		lun->media_changed = true;
771 		usb_disk_reset_capacity(lun);
772 
773 		// initialize this lun
774 		result = usb_disk_inquiry(lun);
775 		for (uint32 tries = 0; tries < 8; tries++) {
776 			TRACE("usb lun %"B_PRIu8" inquiry attempt %"B_PRIu32" begin\n",
777 				i, tries);
778 			status_t ready = usb_disk_test_unit_ready(lun);
779 			if (ready == B_OK || ready == B_DEV_NO_MEDIA) {
780 				if (ready == B_OK) {
781 					if (lun->device_type == B_CD)
782 						lun->write_protected = true;
783 					// TODO: check for write protection; disabled since
784 					// some devices lock up when getting the mode sense
785 					else if (/*usb_disk_mode_sense(lun) != B_OK*/true)
786 						lun->write_protected = false;
787 
788 					TRACE("usb lun %"B_PRIu8" ready. write protected = %c\n", i,
789 						lun->write_protected ? 'y' : 'n');
790 
791 					break;
792 				}
793 				TRACE("usb lun %"B_PRIu8" is ready... "
794 					"but doesn't have any media inserted\n", i);
795 				break;
796 			}
797 			TRACE("usb lun %"B_PRIu8" inquiry attempt %"B_PRIu32" failed\n",
798 				i, tries);
799 
800 			bigtime_t snoozeTime = 1000000 * tries;
801 			TRACE("snoozing %"B_PRIu64" microseconds for usb lun\n",
802 				snoozeTime);
803 			snooze(snoozeTime);
804 		}
805 
806 		if (result != B_OK)
807 			break;
808 	}
809 
810 	if (result != B_OK) {
811 		TRACE_ALWAYS("failed to initialize logical units\n");
812 		usb_disk_free_device_and_luns(device);
813 		return result;
814 	}
815 
816 	mutex_lock(&gDeviceListLock);
817 	device->device_number = 0;
818 	disk_device *other = gDeviceList;
819 	while (other != NULL) {
820 		if (other->device_number >= device->device_number)
821 			device->device_number = other->device_number + 1;
822 
823 		other = (disk_device *)other->link;
824 	}
825 
826 	device->link = (void *)gDeviceList;
827 	gDeviceList = device;
828 	gLunCount += device->lun_count;
829 	for (uint8 i = 0; i < device->lun_count; i++)
830 		sprintf(device->luns[i]->name, DEVICE_NAME, device->device_number, i);
831 	mutex_unlock(&gDeviceListLock);
832 
833 	TRACE("new device: 0x%08lx\n", (uint32)device);
834 	*cookie = (void *)device;
835 	return B_OK;
836 }
837 
838 
839 static status_t
840 usb_disk_device_removed(void *cookie)
841 {
842 	TRACE("device_removed(0x%08lx)\n", (uint32)cookie);
843 	disk_device *device = (disk_device *)cookie;
844 
845 	mutex_lock(&gDeviceListLock);
846 	if (gDeviceList == device) {
847 		gDeviceList = (disk_device *)device->link;
848 	} else {
849 		disk_device *element = gDeviceList;
850 		while (element) {
851 			if (element->link == device) {
852 				element->link = device->link;
853 				break;
854 			}
855 
856 			element = (disk_device *)element->link;
857 		}
858 	}
859 	gLunCount -= device->lun_count;
860 	gDeviceCount--;
861 
862 	device->removed = true;
863 	gUSBModule->cancel_queued_transfers(device->bulk_in);
864 	gUSBModule->cancel_queued_transfers(device->bulk_out);
865 	if (device->open_count == 0)
866 		usb_disk_free_device_and_luns(device);
867 
868 	mutex_unlock(&gDeviceListLock);
869 	return B_OK;
870 }
871 
872 
873 //
874 //#pragma mark - Partial Buffer Functions
875 //
876 
877 
878 static bool
879 usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length,
880 	uint32 &blockPosition, uint16 &blockCount)
881 {
882 	blockPosition = (uint32)(position / lun->block_size);
883 	if ((off_t)blockPosition * lun->block_size != position)
884 		return true;
885 
886 	blockCount = (uint16)(length / lun->block_size);
887 	if ((size_t)blockCount * lun->block_size != length)
888 		return true;
889 
890 	return false;
891 }
892 
893 
894 static status_t
895 usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount,
896 	void *buffer, size_t *length)
897 {
898 	status_t result = usb_disk_operation(lun, SCSI_READ_10, 10, blockPosition,
899 		blockCount, buffer, length, true);
900 	return result;
901 }
902 
903 
904 static status_t
905 usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount,
906 	void *buffer, size_t *length)
907 {
908 	status_t result = usb_disk_operation(lun, SCSI_WRITE_10, 10, blockPosition,
909 		blockCount, buffer, length, false);
910 	if (result == B_OK)
911 		lun->should_sync = true;
912 	return result;
913 }
914 
915 
916 static status_t
917 usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length,
918 	void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition,
919 	uint16 &blockCount)
920 {
921 	blockPosition = (uint32)(position / lun->block_size);
922 	blockCount = (uint16)((uint32)((position + length + lun->block_size - 1)
923 		/ lun->block_size) - blockPosition);
924 	size_t blockLength = blockCount * lun->block_size;
925 	blockBuffer = malloc(blockLength);
926 	if (blockBuffer == NULL) {
927 		TRACE_ALWAYS("no memory to allocate partial buffer\n");
928 		return B_NO_MEMORY;
929 	}
930 
931 	status_t result = usb_disk_block_read(lun, blockPosition, blockCount,
932 		blockBuffer, &blockLength);
933 	if (result != B_OK) {
934 		TRACE_ALWAYS("block read failed when filling partial buffer\n");
935 		free(blockBuffer);
936 		return result;
937 	}
938 
939 	off_t offset = position - (blockPosition * lun->block_size);
940 	partialBuffer = (uint8 *)blockBuffer + offset;
941 	return B_OK;
942 }
943 
944 
945 //
946 //#pragma mark - Driver Hooks
947 //
948 
949 
950 static status_t
951 usb_disk_open(const char *name, uint32 flags, void **cookie)
952 {
953 	TRACE("open(%s)\n", name);
954 	if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0)
955 		return B_NAME_NOT_FOUND;
956 
957 	int32 lastPart = 0;
958 	size_t nameLength = strlen(name);
959 	for (int32 i = nameLength - 1; i >= 0; i--) {
960 		if (name[i] == '/') {
961 			lastPart = i;
962 			break;
963 		}
964 	}
965 
966 	char rawName[nameLength + 4];
967 	strncpy(rawName, name, lastPart + 1);
968 	rawName[lastPart + 1] = 0;
969 	strcat(rawName, "raw");
970 	TRACE("opening raw device %s for %s\n", rawName, name);
971 
972 	mutex_lock(&gDeviceListLock);
973 	disk_device *device = gDeviceList;
974 	while (device) {
975 		for (uint8 i = 0; i < device->lun_count; i++) {
976 			device_lun *lun = device->luns[i];
977 			if (strncmp(rawName, lun->name, 32) == 0) {
978 				// found the matching device/lun
979 				if (device->removed) {
980 					mutex_unlock(&gDeviceListLock);
981 					return B_ERROR;
982 				}
983 
984 				device->open_count++;
985 				*cookie = lun;
986 				mutex_unlock(&gDeviceListLock);
987 				return B_OK;
988 			}
989 		}
990 
991 		device = (disk_device *)device->link;
992 	}
993 
994 	mutex_unlock(&gDeviceListLock);
995 	return B_NAME_NOT_FOUND;
996 }
997 
998 
999 static status_t
1000 usb_disk_close(void *cookie)
1001 {
1002 	TRACE("close()\n");
1003 	device_lun *lun = (device_lun *)cookie;
1004 	disk_device *device = lun->device;
1005 
1006 	mutex_lock(&device->lock);
1007 	if (!device->removed)
1008 		usb_disk_synchronize(lun, false);
1009 	mutex_unlock(&device->lock);
1010 
1011 	return B_OK;
1012 }
1013 
1014 
1015 static status_t
1016 usb_disk_free(void *cookie)
1017 {
1018 	TRACE("free()\n");
1019 	mutex_lock(&gDeviceListLock);
1020 
1021 	device_lun *lun = (device_lun *)cookie;
1022 	disk_device *device = lun->device;
1023 	device->open_count--;
1024 	if (device->open_count == 0 && device->removed) {
1025 		// we can simply free the device here as it has been removed from
1026 		// the device list in the device removed notification hook
1027 		usb_disk_free_device_and_luns(device);
1028 	}
1029 
1030 	mutex_unlock(&gDeviceListLock);
1031 	return B_OK;
1032 }
1033 
1034 
1035 static status_t
1036 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
1037 {
1038 	device_lun *lun = (device_lun *)cookie;
1039 	disk_device *device = lun->device;
1040 	mutex_lock(&device->lock);
1041 	if (device->removed) {
1042 		mutex_unlock(&device->lock);
1043 		return B_DEV_NOT_READY;
1044 	}
1045 
1046 	status_t result = B_DEV_INVALID_IOCTL;
1047 	switch (op) {
1048 		case B_GET_MEDIA_STATUS:
1049 		{
1050 			*(status_t *)buffer = usb_disk_test_unit_ready(lun);
1051 			TRACE("B_GET_MEDIA_STATUS: 0x%08lx\n", *(status_t *)buffer);
1052 			result = B_OK;
1053 			break;
1054 		}
1055 
1056 		case B_GET_GEOMETRY:
1057 		{
1058 			if (lun->media_changed) {
1059 				result = usb_disk_update_capacity(lun);
1060 				if (result != B_OK)
1061 					break;
1062 			}
1063 
1064 			device_geometry *geometry = (device_geometry *)buffer;
1065 			geometry->bytes_per_sector = lun->block_size;
1066 			geometry->cylinder_count = lun->block_count;
1067 			geometry->sectors_per_track = geometry->head_count = 1;
1068 			geometry->device_type = lun->device_type;
1069 			geometry->removable = lun->removable;
1070 			geometry->read_only = lun->write_protected;
1071 			geometry->write_once = (lun->device_type == B_WORM);
1072 			TRACE("B_GET_GEOMETRY: %ld sectors at %ld bytes per sector\n",
1073 				geometry->cylinder_count, geometry->bytes_per_sector);
1074 			result = B_OK;
1075 			break;
1076 		}
1077 
1078 		case B_FLUSH_DRIVE_CACHE:
1079 			TRACE("B_FLUSH_DRIVE_CACHE\n");
1080 			result = usb_disk_synchronize(lun, true);
1081 			break;
1082 
1083 		case B_EJECT_DEVICE:
1084 			result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 2,
1085 				NULL, NULL, false);
1086 			break;
1087 
1088 		case B_LOAD_MEDIA:
1089 			result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 3,
1090 				NULL, NULL, false);
1091 			break;
1092 
1093 #if HAIKU_TARGET_PLATFORM_HAIKU
1094 		case B_GET_ICON:
1095 			// We don't support this legacy ioctl anymore, but the two other
1096 			// icon ioctls below instead.
1097 			break;
1098 
1099 		case B_GET_ICON_NAME:
1100 			result = user_strlcpy((char *)buffer,
1101 				"devices/drive-removable-media-usb", B_FILE_NAME_LENGTH);
1102 			break;
1103 
1104 		case B_GET_VECTOR_ICON:
1105 		{
1106 			if (length != sizeof(device_icon)) {
1107 				result = B_BAD_VALUE;
1108 				break;
1109 			}
1110 
1111 			device_icon iconData;
1112 			if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) {
1113 				result = B_BAD_ADDRESS;
1114 				break;
1115 			}
1116 
1117 			if (iconData.icon_size >= (int32)sizeof(kDeviceIcon)) {
1118 				if (user_memcpy(iconData.icon_data, kDeviceIcon,
1119 						sizeof(kDeviceIcon)) != B_OK) {
1120 					result = B_BAD_ADDRESS;
1121 					break;
1122 				}
1123 			}
1124 
1125 			iconData.icon_size = sizeof(kDeviceIcon);
1126 			result = user_memcpy(buffer, &iconData, sizeof(device_icon));
1127 			break;
1128 		}
1129 #endif
1130 
1131 		default:
1132 			TRACE_ALWAYS("unhandled ioctl %ld\n", op);
1133 			break;
1134 	}
1135 
1136 	mutex_unlock(&device->lock);
1137 	return result;
1138 }
1139 
1140 
1141 static status_t
1142 usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length)
1143 {
1144 	if (buffer == NULL || length == NULL)
1145 		return B_BAD_VALUE;
1146 
1147 	TRACE("read(%lld, %ld)\n", position, *length);
1148 	device_lun *lun = (device_lun *)cookie;
1149 	disk_device *device = lun->device;
1150 	mutex_lock(&device->lock);
1151 	if (device->removed) {
1152 		*length = 0;
1153 		mutex_unlock(&device->lock);
1154 		return B_DEV_NOT_READY;
1155 	}
1156 
1157 	status_t result = B_ERROR;
1158 	uint32 blockPosition = 0;
1159 	uint16 blockCount = 0;
1160 	bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length,
1161 		blockPosition, blockCount);
1162 	if (needsPartial) {
1163 		void *partialBuffer = NULL;
1164 		void *blockBuffer = NULL;
1165 		result = usb_disk_prepare_partial_buffer(lun, position, *length,
1166 			partialBuffer, blockBuffer, blockPosition, blockCount);
1167 		if (result == B_OK) {
1168 			memcpy(buffer, partialBuffer, *length);
1169 			free(blockBuffer);
1170 		}
1171 	} else {
1172 		result = usb_disk_block_read(lun, blockPosition, blockCount, buffer,
1173 			length);
1174 	}
1175 
1176 	mutex_unlock(&device->lock);
1177 	if (result == B_OK) {
1178 		TRACE("read successful with %ld bytes\n", *length);
1179 		return B_OK;
1180 	}
1181 
1182 	*length = 0;
1183 	TRACE_ALWAYS("read fails with 0x%08lx\n", result);
1184 	return result;
1185 }
1186 
1187 
1188 static status_t
1189 usb_disk_write(void *cookie, off_t position, const void *buffer,
1190 	size_t *length)
1191 {
1192 	if (buffer == NULL || length == NULL)
1193 		return B_BAD_VALUE;
1194 
1195 	TRACE("write(%lld, %ld)\n", position, *length);
1196 	device_lun *lun = (device_lun *)cookie;
1197 	disk_device *device = lun->device;
1198 	mutex_lock(&device->lock);
1199 	if (device->removed) {
1200 		*length = 0;
1201 		mutex_unlock(&device->lock);
1202 		return B_DEV_NOT_READY;
1203 	}
1204 
1205 	status_t result = B_ERROR;
1206 	uint32 blockPosition = 0;
1207 	uint16 blockCount = 0;
1208 	bool needsPartial = usb_disk_needs_partial_buffer(lun, position,
1209 		*length, blockPosition, blockCount);
1210 	if (needsPartial) {
1211 		void *partialBuffer = NULL;
1212 		void *blockBuffer = NULL;
1213 		result = usb_disk_prepare_partial_buffer(lun, position, *length,
1214 			partialBuffer, blockBuffer, blockPosition, blockCount);
1215 		if (result == B_OK) {
1216 			memcpy(partialBuffer, buffer, *length);
1217 			size_t blockLength = blockCount * lun->block_size;
1218 			result = usb_disk_block_write(lun, blockPosition, blockCount,
1219 				blockBuffer, &blockLength);
1220 			free(blockBuffer);
1221 		}
1222 	} else {
1223 		result = usb_disk_block_write(lun, blockPosition, blockCount,
1224 			(void *)buffer, length);
1225 	}
1226 
1227 	mutex_unlock(&device->lock);
1228 	if (result == B_OK) {
1229 		TRACE("write successful with %ld bytes\n", *length);
1230 		return B_OK;
1231 	}
1232 
1233 	*length = 0;
1234 	TRACE_ALWAYS("write fails with 0x%08lx\n", result);
1235 	return result;
1236 }
1237 
1238 
1239 //
1240 //#pragma mark - Driver Entry Points
1241 //
1242 
1243 
1244 status_t
1245 init_hardware()
1246 {
1247 	TRACE("init_hardware()\n");
1248 	return B_OK;
1249 }
1250 
1251 
1252 status_t
1253 init_driver()
1254 {
1255 	TRACE("init_driver()\n");
1256 	static usb_notify_hooks notifyHooks = {
1257 		&usb_disk_device_added,
1258 		&usb_disk_device_removed
1259 	};
1260 
1261 	static usb_support_descriptor supportedDevices[] = {
1262 		{ 0x08 /* mass storage */, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 },
1263 		{ 0x08 /* mass storage */, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 },
1264 		{ 0x08 /* mass storage */, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 }
1265 	};
1266 
1267 	gDeviceList = NULL;
1268 	gDeviceCount = 0;
1269 	gLunCount = 0;
1270 	mutex_init(&gDeviceListLock, "usb_disk device list lock");
1271 
1272 	TRACE("trying module %s\n", B_USB_MODULE_NAME);
1273 	status_t result = get_module(B_USB_MODULE_NAME,
1274 		(module_info **)&gUSBModule);
1275 	if (result < B_OK) {
1276 		TRACE_ALWAYS("getting module failed 0x%08lx\n", result);
1277 		mutex_destroy(&gDeviceListLock);
1278 		return result;
1279 	}
1280 
1281 	gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 3, NULL);
1282 	gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
1283 	return B_OK;
1284 }
1285 
1286 
1287 void
1288 uninit_driver()
1289 {
1290 	TRACE("uninit_driver()\n");
1291 	gUSBModule->uninstall_notify(DRIVER_NAME);
1292 	mutex_lock(&gDeviceListLock);
1293 
1294 	if (gDeviceNames) {
1295 		for (int32 i = 0; gDeviceNames[i]; i++)
1296 			free(gDeviceNames[i]);
1297 		free(gDeviceNames);
1298 		gDeviceNames = NULL;
1299 	}
1300 
1301 	mutex_destroy(&gDeviceListLock);
1302 	put_module(B_USB_MODULE_NAME);
1303 }
1304 
1305 
1306 const char **
1307 publish_devices()
1308 {
1309 	TRACE("publish_devices()\n");
1310 	if (gDeviceNames) {
1311 		for (int32 i = 0; gDeviceNames[i]; i++)
1312 			free(gDeviceNames[i]);
1313 		free(gDeviceNames);
1314 		gDeviceNames = NULL;
1315 	}
1316 
1317 	gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1));
1318 	if (gDeviceNames == NULL)
1319 		return NULL;
1320 
1321 	int32 index = 0;
1322 	mutex_lock(&gDeviceListLock);
1323 	disk_device *device = gDeviceList;
1324 	while (device) {
1325 		for (uint8 i = 0; i < device->lun_count; i++)
1326 			gDeviceNames[index++] = strdup(device->luns[i]->name);
1327 
1328 		device = (disk_device *)device->link;
1329 	}
1330 
1331 	gDeviceNames[index++] = NULL;
1332 	mutex_unlock(&gDeviceListLock);
1333 	return (const char **)gDeviceNames;
1334 }
1335 
1336 
1337 device_hooks *
1338 find_device(const char *name)
1339 {
1340 	TRACE("find_device()\n");
1341 	static device_hooks hooks = {
1342 		&usb_disk_open,
1343 		&usb_disk_close,
1344 		&usb_disk_free,
1345 		&usb_disk_ioctl,
1346 		&usb_disk_read,
1347 		&usb_disk_write,
1348 		NULL,
1349 		NULL,
1350 		NULL,
1351 		NULL
1352 	};
1353 
1354 	return &hooks;
1355 }
1356