xref: /haiku/src/add-ons/kernel/bus_managers/usb/Device.cpp (revision 959ff00ddee8411dabb09211f3bfbd52d87229da)
1 /*
2  * Copyright 2003-2006, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  *		Niels S. Reedijk
8  */
9 
10 #include "usb_p.h"
11 
12 
13 Device::Device(Object *parent, int8 hubAddress, uint8 hubPort,
14 	usb_device_descriptor &desc, int8 deviceAddress, usb_speed speed,
15 	bool isRootHub)
16 	:	Object(parent),
17 		fDeviceDescriptor(desc),
18 		fInitOK(false),
19 		fAvailable(true),
20 		fIsRootHub(isRootHub),
21 		fConfigurations(NULL),
22 		fCurrentConfiguration(NULL),
23 		fSpeed(speed),
24 		fDeviceAddress(deviceAddress),
25 		fHubAddress(hubAddress),
26 		fHubPort(hubPort)
27 {
28 	TRACE(("USB Device %d: creating device\n", fDeviceAddress));
29 
30 	fDefaultPipe = new(std::nothrow) ControlPipe(this);
31 	if (!fDefaultPipe) {
32 		TRACE_ERROR(("USB Device %d: could not allocate default pipe\n", fDeviceAddress));
33 		return;
34 	}
35 
36 	fDefaultPipe->InitCommon(fDeviceAddress, 0, fSpeed, Pipe::Default,
37 		fDeviceDescriptor.max_packet_size_0, 0, fHubAddress, fHubPort);
38 
39 	// Get the device descriptor
40 	// We already have a part of it, but we want it all
41 	size_t actualLength;
42 	status_t status = GetDescriptor(USB_DESCRIPTOR_DEVICE, 0, 0,
43 		(void *)&fDeviceDescriptor, sizeof(fDeviceDescriptor), &actualLength);
44 
45 	if (status < B_OK || actualLength != sizeof(fDeviceDescriptor)) {
46 		TRACE_ERROR(("USB Device %d: error while getting the device descriptor\n", fDeviceAddress));
47 		return;
48 	}
49 
50 	TRACE(("full device descriptor for device %d:\n", fDeviceAddress));
51 	TRACE(("\tlength:..............%d\n", fDeviceDescriptor.length));
52 	TRACE(("\tdescriptor_type:.....0x%04x\n", fDeviceDescriptor.descriptor_type));
53 	TRACE(("\tusb_version:.........0x%04x\n", fDeviceDescriptor.usb_version));
54 	TRACE(("\tdevice_class:........0x%02x\n", fDeviceDescriptor.device_class));
55 	TRACE(("\tdevice_subclass:.....0x%02x\n", fDeviceDescriptor.device_subclass));
56 	TRACE(("\tdevice_protocol:.....0x%02x\n", fDeviceDescriptor.device_protocol));
57 	TRACE(("\tmax_packet_size_0:...%d\n", fDeviceDescriptor.max_packet_size_0));
58 	TRACE(("\tvendor_id:...........0x%04x\n", fDeviceDescriptor.vendor_id));
59 	TRACE(("\tproduct_id:..........0x%04x\n", fDeviceDescriptor.product_id));
60 	TRACE(("\tdevice_version:......0x%04x\n", fDeviceDescriptor.device_version));
61 	TRACE(("\tmanufacturer:........0x%02x\n", fDeviceDescriptor.manufacturer));
62 	TRACE(("\tproduct:.............0x%02x\n", fDeviceDescriptor.product));
63 	TRACE(("\tserial_number:.......0x%02x\n", fDeviceDescriptor.serial_number));
64 	TRACE(("\tnum_configurations:..%d\n", fDeviceDescriptor.num_configurations));
65 
66 	// Get the configurations
67 	fConfigurations = (usb_configuration_info *)malloc(
68 		fDeviceDescriptor.num_configurations * sizeof(usb_configuration_info));
69 	if (fConfigurations == NULL) {
70 		TRACE_ERROR(("USB Device %d: out of memory during config creations!\n",
71 			fDeviceAddress));
72 		return;
73 	}
74 
75 	memset(fConfigurations, 0, fDeviceDescriptor.num_configurations
76 		* sizeof(usb_configuration_info));
77 	for (int32 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
78 		usb_configuration_descriptor configDescriptor;
79 		status = GetDescriptor(USB_DESCRIPTOR_CONFIGURATION, i, 0,
80 			(void *)&configDescriptor, sizeof(usb_configuration_descriptor),
81 			&actualLength);
82 
83 		if (status < B_OK || actualLength != sizeof(usb_configuration_descriptor)) {
84 			TRACE_ERROR(("USB Device %d: error fetching configuration %ld\n",
85 				fDeviceAddress, i));
86 			return;
87 		}
88 
89 		TRACE(("USB Device %d: configuration %ld\n", fDeviceAddress, i));
90 		TRACE(("\tlength:..............%d\n", configDescriptor.length));
91 		TRACE(("\tdescriptor_type:.....0x%02x\n", configDescriptor.descriptor_type));
92 		TRACE(("\ttotal_length:........%d\n", configDescriptor.total_length));
93 		TRACE(("\tnumber_interfaces:...%d\n", configDescriptor.number_interfaces));
94 		TRACE(("\tconfiguration_value:.0x%02x\n", configDescriptor.configuration_value));
95 		TRACE(("\tconfiguration:.......0x%02x\n", configDescriptor.configuration));
96 		TRACE(("\tattributes:..........0x%02x\n", configDescriptor.attributes));
97 		TRACE(("\tmax_power:...........%d\n", configDescriptor.max_power));
98 
99 		uint8 *configData = (uint8 *)malloc(configDescriptor.total_length);
100 		if (configData == NULL) {
101 			TRACE_ERROR(("USB Device %d: out of memory when reading config\n",
102 				fDeviceAddress));
103 			return;
104 		}
105 
106 		status = GetDescriptor(USB_DESCRIPTOR_CONFIGURATION, i, 0,
107 			(void *)configData, configDescriptor.total_length, &actualLength);
108 
109 		if (status < B_OK || actualLength != configDescriptor.total_length) {
110 			TRACE_ERROR(("USB Device %d: error fetching full configuration"
111 				" descriptor %ld got %lu expected %u\n", fDeviceAddress, i,
112 				actualLength, configDescriptor.total_length));
113 			free(configData);
114 			return;
115 		}
116 
117 		usb_configuration_descriptor *configuration
118 			= (usb_configuration_descriptor *)configData;
119 		fConfigurations[i].descr = configuration;
120 		fConfigurations[i].interface_count = configuration->number_interfaces;
121 		fConfigurations[i].interface = (usb_interface_list *)malloc(
122 			configuration->number_interfaces * sizeof(usb_interface_list));
123 		if (fConfigurations[i].interface == NULL) {
124 			TRACE_ERROR(("USB Device %d: out of memory when creating interfaces\n",
125 				fDeviceAddress));
126 			return;
127 		}
128 
129 		memset(fConfigurations[i].interface, 0,
130 			configuration->number_interfaces * sizeof(usb_interface_list));
131 
132 		usb_interface_info *currentInterface = NULL;
133 		uint32 descriptorStart = sizeof(usb_configuration_descriptor);
134 		while (descriptorStart < actualLength) {
135 			switch (configData[descriptorStart + 1]) {
136 				case USB_DESCRIPTOR_INTERFACE: {
137 					TRACE(("USB Device %d: got interface descriptor\n", fDeviceAddress));
138 					usb_interface_descriptor *interfaceDescriptor
139 						= (usb_interface_descriptor *)&configData[descriptorStart];
140 					TRACE(("\tlength:.............%d\n", interfaceDescriptor->length));
141 					TRACE(("\tdescriptor_type:....0x%02x\n", interfaceDescriptor->descriptor_type));
142 					TRACE(("\tinterface_number:...%d\n", interfaceDescriptor->interface_number));
143 					TRACE(("\talternate_setting:..%d\n", interfaceDescriptor->alternate_setting));
144 					TRACE(("\tnum_endpoints:......%d\n", interfaceDescriptor->num_endpoints));
145 					TRACE(("\tinterface_class:....0x%02x\n", interfaceDescriptor->interface_class));
146 					TRACE(("\tinterface_subclass:.0x%02x\n", interfaceDescriptor->interface_subclass));
147 					TRACE(("\tinterface_protocol:.0x%02x\n", interfaceDescriptor->interface_protocol));
148 					TRACE(("\tinterface:..........%d\n", interfaceDescriptor->interface));
149 
150 					usb_interface_list *interfaceList
151 						= &fConfigurations[i].interface[interfaceDescriptor->interface_number];
152 
153 					/* Allocate this alternate */
154 					interfaceList->alt_count++;
155 					usb_interface_info *newAlternates
156 						= (usb_interface_info *)realloc(interfaceList->alt,
157 						interfaceList->alt_count * sizeof(usb_interface_info));
158 					if (newAlternates == NULL) {
159 						TRACE_ERROR(("USB Device %d: out of memory allocating"
160 							" alternate interface\n", fDeviceAddress));
161 						interfaceList->alt_count--;
162 						return;
163 					}
164 
165 					interfaceList->alt = newAlternates;
166 
167 					/* Set active interface always to the first one */
168 					interfaceList->active = interfaceList->alt;
169 
170 					/* Setup this alternate */
171 					usb_interface_info *interfaceInfo =
172 						&interfaceList->alt[interfaceList->alt_count - 1];
173 					interfaceInfo->descr = interfaceDescriptor;
174 					interfaceInfo->endpoint_count = 0;
175 					interfaceInfo->endpoint = NULL;
176 					interfaceInfo->generic_count = 0;
177 					interfaceInfo->generic = NULL;
178 
179 					Interface *interface = new(std::nothrow) Interface(this,
180 						interfaceDescriptor->interface_number);
181 					if (interface == NULL) {
182 						TRACE_ERROR(("USB Device %d: failed to allocate"
183 							" interface object\n", fDeviceAddress));
184 						return;
185 					}
186 
187 					interfaceInfo->handle = interface->USBID();
188 					currentInterface = interfaceInfo;
189 					break;
190 				}
191 
192 				case USB_DESCRIPTOR_ENDPOINT: {
193 					TRACE(("USB Device %d: got endpoint descriptor\n", fDeviceAddress));
194 					usb_endpoint_descriptor *endpointDescriptor
195 						= (usb_endpoint_descriptor *)&configData[descriptorStart];
196 					TRACE(("\tlength:.............%d\n", endpointDescriptor->length));
197 					TRACE(("\tdescriptor_type:....0x%02x\n", endpointDescriptor->descriptor_type));
198 					TRACE(("\tendpoint_address:...0x%02x\n", endpointDescriptor->endpoint_address));
199 					TRACE(("\tattributes:.........0x%02x\n", endpointDescriptor->attributes));
200 					TRACE(("\tmax_packet_size:....%d\n", endpointDescriptor->max_packet_size));
201 					TRACE(("\tinterval:...........%d\n", endpointDescriptor->interval));
202 
203 					if (!currentInterface)
204 						break;
205 
206 					/* allocate this endpoint */
207 					currentInterface->endpoint_count++;
208 					usb_endpoint_info *newEndpoints
209 						= (usb_endpoint_info *)realloc(
210 						currentInterface->endpoint,
211 						currentInterface->endpoint_count
212 						* sizeof(usb_endpoint_info));
213 					if (newEndpoints == NULL) {
214 						TRACE_ERROR(("USB Device %d: out of memory allocating"
215 							" new endpoint\n", fDeviceAddress));
216 						currentInterface->endpoint_count--;
217 						return;
218 					}
219 
220 					currentInterface->endpoint = newEndpoints;
221 
222 					/* setup this endpoint */
223 					usb_endpoint_info *endpointInfo =
224 						&currentInterface->endpoint[currentInterface->endpoint_count - 1];
225 					endpointInfo->descr = endpointDescriptor;
226 					endpointInfo->handle = 0;
227 					break;
228 				}
229 
230 				default:
231 					TRACE(("USB Device %d: got generic descriptor\n", fDeviceAddress));
232 					usb_generic_descriptor *genericDescriptor
233 						= (usb_generic_descriptor *)&configData[descriptorStart];
234 					TRACE(("\tlength:.............%d\n", genericDescriptor->length));
235 					TRACE(("\tdescriptor_type:....0x%02x\n", genericDescriptor->descriptor_type));
236 
237 					if (!currentInterface)
238 						break;
239 
240 					/* allocate this descriptor */
241 					currentInterface->generic_count++;
242 					usb_descriptor **newGenerics = (usb_descriptor **)realloc(
243 						currentInterface->generic,
244 						currentInterface->generic_count
245 						* sizeof(usb_descriptor *));
246 					if (newGenerics == NULL) {
247 						TRACE_ERROR(("USB Device %d: out of memory allocating"
248 							" generic descriptor\n", fDeviceAddress));
249 						currentInterface->generic_count--;
250 						return;
251 					}
252 
253 					currentInterface->generic = newGenerics;
254 
255 					/* add this descriptor */
256 					currentInterface->generic[currentInterface->generic_count - 1] =
257 						(usb_descriptor *)genericDescriptor;
258 					break;
259 			}
260 
261 			descriptorStart += configData[descriptorStart];
262 		}
263 	}
264 
265 	// Set default configuration
266 	TRACE(("USB Device %d: setting default configuration\n", fDeviceAddress));
267 	if (SetConfigurationAt(0) < B_OK) {
268 		TRACE_ERROR(("USB Device %d: failed to set default configuration\n",
269 			fDeviceAddress));
270 		return;
271 	}
272 
273 	fInitOK = true;
274 }
275 
276 
277 Device::~Device()
278 {
279 	// Destroy open endpoints. Do not send a device request to unconfigure
280 	// though, since we may be deleted because the device was unplugged
281 	// already.
282 	Unconfigure(false);
283 
284 	// Free all allocated resources
285 	for (int32 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
286 		usb_configuration_info *configuration = &fConfigurations[i];
287 		if (configuration == NULL)
288 			continue;
289 
290 		free(configuration->descr);
291 		if (configuration->interface == NULL)
292 			continue;
293 
294 		for (size_t j = 0; j < configuration->interface_count; j++) {
295 			usb_interface_list *interfaceList = &configuration->interface[j];
296 			if (interfaceList->alt == NULL)
297 				continue;
298 
299 			for (size_t k = 0; k < interfaceList->alt_count; k++) {
300 				usb_interface_info *interface = &interfaceList->alt[k];
301 				delete (Interface *)GetStack()->GetObject(interface->handle);
302 				free(interface->endpoint);
303 				free(interface->generic);
304 			}
305 
306 			free(interfaceList->alt);
307 		}
308 
309 		free(configuration->interface);
310 	}
311 
312 	free(fConfigurations);
313 	delete fDefaultPipe;
314 }
315 
316 
317 status_t
318 Device::InitCheck()
319 {
320 	if (fInitOK)
321 		return B_OK;
322 
323 	return B_ERROR;
324 }
325 
326 
327 status_t
328 Device::Changed(change_item **changeList, bool added)
329 {
330 	fAvailable = added;
331 	change_item *changeItem = new(std::nothrow) change_item;
332 	if (!changeItem)
333 		return B_NO_MEMORY;
334 
335 	changeItem->added = added;
336 	changeItem->device = this;
337 	changeItem->link = *changeList;
338 	*changeList = changeItem;
339 	return B_OK;
340 }
341 
342 
343 status_t
344 Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
345 	void *data, size_t dataLength, size_t *actualLength)
346 {
347 	if (!fAvailable)
348 		return B_ERROR;
349 
350 	return fDefaultPipe->SendRequest(
351 		USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD,		// type
352 		USB_REQUEST_GET_DESCRIPTOR,							// request
353 		(descriptorType << 8) | index,						// value
354 		languageID,											// index
355 		dataLength,											// length
356 		data,												// buffer
357 		dataLength,											// buffer length
358 		actualLength);										// actual length
359 }
360 
361 
362 const usb_configuration_info *
363 Device::Configuration() const
364 {
365 	return fCurrentConfiguration;
366 }
367 
368 
369 const usb_configuration_info *
370 Device::ConfigurationAt(uint8 index) const
371 {
372 	if (index >= fDeviceDescriptor.num_configurations)
373 		return NULL;
374 
375 	return &fConfigurations[index];
376 }
377 
378 
379 status_t
380 Device::SetConfiguration(const usb_configuration_info *configuration)
381 {
382 	if (!configuration)
383 		return Unconfigure(true);
384 
385 	for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
386 		if (configuration->descr->configuration_value
387 			== fConfigurations[i].descr->configuration_value)
388 			return SetConfigurationAt(i);
389 	}
390 
391 	return B_BAD_VALUE;
392 }
393 
394 
395 status_t
396 Device::SetConfigurationAt(uint8 index)
397 {
398 	if (!fAvailable)
399 		return B_ERROR;
400 	if (index >= fDeviceDescriptor.num_configurations)
401 		return B_BAD_VALUE;
402 	if (&fConfigurations[index] == fCurrentConfiguration)
403 		return B_OK;
404 
405 	// Destroy our open endpoints
406 	Unconfigure(false);
407 
408 	// Tell the device to set the configuration
409 	status_t result = fDefaultPipe->SendRequest(
410 		USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD,		// type
411 		USB_REQUEST_SET_CONFIGURATION,						// request
412 		fConfigurations[index].descr->configuration_value,	// value
413 		0,													// index
414 		0,													// length
415 		NULL,												// buffer
416 		0,													// buffer length
417 		NULL);												// actual length
418 
419 	if (result < B_OK)
420 		return result;
421 
422 	// Set current configuration
423 	fCurrentConfiguration = &fConfigurations[index];
424 
425 	// Initialize all the endpoints that are now active
426 	InitEndpoints(-1);
427 
428 	// Wait some for the configuration being finished
429 	if (!fIsRootHub)
430 		snooze(USB_DELAY_SET_CONFIGURATION);
431 	return B_OK;
432 }
433 
434 
435 void
436 Device::InitEndpoints(int32 interfaceIndex)
437 {
438 	for (size_t j = 0; j < fCurrentConfiguration->interface_count; j++) {
439 		if (interfaceIndex >= 0 && j != (size_t)interfaceIndex)
440 			continue;
441 
442 		usb_interface_info *interfaceInfo = fCurrentConfiguration->interface[j].active;
443 		for (size_t i = 0; i < interfaceInfo->endpoint_count; i++) {
444 			usb_endpoint_info *endpoint = &interfaceInfo->endpoint[i];
445 			Pipe *pipe = NULL;
446 
447 			Pipe::pipeDirection direction = Pipe::Out;
448 			if (endpoint->descr->endpoint_address & 0x80)
449 				direction = Pipe::In;
450 
451 			switch (endpoint->descr->attributes & 0x03) {
452 				case 0x00: /* Control Endpoint */
453 					pipe = new(std::nothrow) ControlPipe(this);
454 					direction = Pipe::Default;
455 					break;
456 
457 				case 0x01: /* Isochronous Endpoint */
458 					pipe = new(std::nothrow) IsochronousPipe(this);
459 					break;
460 
461 				case 0x02: /* Bulk Endpoint */
462 					pipe = new(std::nothrow) BulkPipe(this);
463 					break;
464 
465 				case 0x03: /* Interrupt Endpoint */
466 					pipe = new(std::nothrow) InterruptPipe(this);
467 					break;
468 			}
469 
470 			if (pipe == NULL) {
471 				TRACE_ERROR(("USB Device %d: failed to allocate pipe\n",
472 					fDeviceAddress));
473 				endpoint->handle = 0;
474 				continue;
475 			}
476 
477 			pipe->InitCommon(fDeviceAddress,
478 				endpoint->descr->endpoint_address & 0x0f,
479 				fSpeed, direction, endpoint->descr->max_packet_size,
480 				endpoint->descr->interval, fHubAddress, fHubPort);
481 			endpoint->handle = pipe->USBID();
482 		}
483 	}
484 }
485 
486 
487 status_t
488 Device::Unconfigure(bool atDeviceLevel)
489 {
490 	// if we only want to destroy our open pipes before setting
491 	// another configuration unconfigure will be called with
492 	// atDevice = false. otherwise we explicitly want to unconfigure
493 	// the device and have to send it the corresponding request.
494 	if (atDeviceLevel && fAvailable) {
495 		status_t result = fDefaultPipe->SendRequest(
496 			USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD,	// type
497 			USB_REQUEST_SET_CONFIGURATION,					// request
498 			0,												// value
499 			0,												// index
500 			0,												// length
501 			NULL,											// buffer
502 			0,												// buffer length
503 			NULL);											// actual length
504 
505 		if (result < B_OK)
506 			return result;
507 
508 		snooze(USB_DELAY_SET_CONFIGURATION);
509 	}
510 
511 	if (!fCurrentConfiguration)
512 		return B_OK;
513 
514 	ClearEndpoints(-1);
515 	fCurrentConfiguration = NULL;
516 	return B_OK;
517 }
518 
519 
520 void
521 Device::ClearEndpoints(int32 interfaceIndex)
522 {
523 	if (fCurrentConfiguration == NULL || fCurrentConfiguration->interface == NULL)
524 		return;
525 
526 	for (size_t j = 0; j < fCurrentConfiguration->interface_count; j++) {
527 		if (interfaceIndex >= 0 && j != (size_t)interfaceIndex)
528 			continue;
529 
530 		usb_interface_info *interfaceInfo = fCurrentConfiguration->interface[j].active;
531 		if (interfaceInfo == NULL || interfaceInfo->endpoint == NULL)
532 			continue;
533 
534 		for (size_t i = 0; i < interfaceInfo->endpoint_count; i++) {
535 			usb_endpoint_info *endpoint = &interfaceInfo->endpoint[i];
536 			delete (Pipe *)GetStack()->GetObject(endpoint->handle);
537 			endpoint->handle = 0;
538 		}
539 	}
540 }
541 
542 
543 status_t
544 Device::SetAltInterface(const usb_interface_info *interface)
545 {
546 	uint8 interfaceNumber = interface->descr->interface_number;
547 	// Tell the device to set the alternate settings
548 	status_t result = fDefaultPipe->SendRequest(
549 		USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_STANDARD,	// type
550 		USB_REQUEST_SET_INTERFACE,							// request
551 		interface->descr->alternate_setting,				// value
552 		interfaceNumber,									// index
553 		0,													// length
554 		NULL,												// buffer
555 		0,													// buffer length
556 		NULL);
557 
558 	if (result < B_OK)
559 		return result;
560 
561 	// Clear the no longer active endpoints
562 	ClearEndpoints(interfaceNumber);
563 
564 	// Update the active pointer of the interface list
565 	usb_interface_list *interfaceList
566 		= &fCurrentConfiguration->interface[interfaceNumber];
567 	interfaceList->active
568 		= &interfaceList->alt[interface->descr->alternate_setting];
569 
570 	// Initialize the new endpoints
571 	InitEndpoints(interfaceNumber);
572 	return result;
573 }
574 
575 const usb_device_descriptor *
576 Device::DeviceDescriptor() const
577 {
578 	return &fDeviceDescriptor;
579 }
580 
581 
582 status_t
583 Device::ReportDevice(usb_support_descriptor *supportDescriptors,
584 	uint32 supportDescriptorCount, const usb_notify_hooks *hooks,
585 	usb_driver_cookie **cookies, bool added, bool recursive)
586 {
587 	TRACE(("USB Device %d: reporting device\n", fDeviceAddress));
588 	bool supported = false;
589 	if (supportDescriptorCount == 0 || supportDescriptors == NULL)
590 		supported = true;
591 
592 	for (uint32 i = 0; !supported && i < supportDescriptorCount; i++) {
593 		if ((supportDescriptors[i].vendor != 0
594 			&& fDeviceDescriptor.vendor_id != supportDescriptors[i].vendor)
595 			|| (supportDescriptors[i].product != 0
596 			&& fDeviceDescriptor.product_id != supportDescriptors[i].product))
597 			continue;
598 
599 		if ((supportDescriptors[i].dev_class == 0
600 			|| fDeviceDescriptor.device_class == supportDescriptors[i].dev_class)
601 			&& (supportDescriptors[i].dev_subclass == 0
602 			|| fDeviceDescriptor.device_subclass == supportDescriptors[i].dev_subclass)
603 			&& (supportDescriptors[i].dev_protocol == 0
604 			|| fDeviceDescriptor.device_protocol == supportDescriptors[i].dev_protocol)) {
605 			supported = true;
606 		}
607 
608 		// we have to check all interfaces for matching class/subclass/protocol
609 		for (uint32 j = 0; !supported && j < fDeviceDescriptor.num_configurations; j++) {
610 			for (uint32 k = 0; !supported && k < fConfigurations[j].interface_count; k++) {
611 				for (uint32 l = 0; !supported && l < fConfigurations[j].interface[k].alt_count; l++) {
612 					usb_interface_descriptor *descriptor = fConfigurations[j].interface[k].alt[l].descr;
613 					if ((supportDescriptors[i].dev_class == 0
614 						|| descriptor->interface_class == supportDescriptors[i].dev_class)
615 						&& (supportDescriptors[i].dev_subclass == 0
616 						|| descriptor->interface_subclass == supportDescriptors[i].dev_subclass)
617 						&& (supportDescriptors[i].dev_protocol == 0
618 						|| descriptor->interface_protocol == supportDescriptors[i].dev_protocol)) {
619 						supported = true;
620 					}
621 				}
622 			}
623 		}
624 	}
625 
626 	if (!supported)
627 		return B_UNSUPPORTED;
628 
629 	if ((added && hooks->device_added == NULL)
630 		|| (!added && hooks->device_removed == NULL)) {
631 		// hooks are not installed, but report success to indicate that
632 		// the driver supports the device
633 		return B_OK;
634 	}
635 
636 	usb_id id = USBID();
637 	if (added) {
638 		usb_driver_cookie *cookie = new(std::nothrow) usb_driver_cookie;
639 		if (hooks->device_added(id, &cookie->cookie) >= B_OK) {
640 			cookie->device = id;
641 			cookie->link = *cookies;
642 			*cookies = cookie;
643 		} else
644 			delete cookie;
645 	} else {
646 		usb_driver_cookie **pointer = cookies;
647 		usb_driver_cookie *cookie = *cookies;
648 		while (cookie) {
649 			if (cookie->device == id)
650 				break;
651 			pointer = &cookie->link;
652 			cookie = cookie->link;
653 		}
654 
655 		if (!cookie) {
656 			// the device is supported, but there is no cookie. this most
657 			// probably means that the device_added hook above failed.
658 			return B_OK;
659 		}
660 
661 		hooks->device_removed(cookie->cookie);
662 		*pointer = cookie->link;
663 		delete cookie;
664 	}
665 
666 	return B_OK;
667 }
668 
669 
670 status_t
671 Device::BuildDeviceName(char *string, uint32 *index, size_t bufferSize,
672 	Device *device)
673 {
674 	if (!Parent() || (Parent()->Type() & USB_OBJECT_HUB) == 0)
675 		return B_ERROR;
676 
677 	((Hub *)Parent())->BuildDeviceName(string, index, bufferSize, this);
678 	return B_OK;
679 }
680 
681 
682 status_t
683 Device::SetFeature(uint16 selector)
684 {
685 	if (!fAvailable)
686 		return B_ERROR;
687 
688 	return fDefaultPipe->SendRequest(
689 		USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
690 		USB_REQUEST_SET_FEATURE,
691 		selector,
692 		0,
693 		0,
694 		NULL,
695 		0,
696 		NULL);
697 }
698 
699 
700 status_t
701 Device::ClearFeature(uint16 selector)
702 {
703 	if (!fAvailable)
704 		return B_ERROR;
705 
706 	return fDefaultPipe->SendRequest(
707 		USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
708 		USB_REQUEST_CLEAR_FEATURE,
709 		selector,
710 		0,
711 		0,
712 		NULL,
713 		0,
714 		NULL);
715 }
716 
717 
718 status_t
719 Device::GetStatus(uint16 *status)
720 {
721 	if (!fAvailable)
722 		return B_ERROR;
723 
724 	return fDefaultPipe->SendRequest(
725 		USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_IN,
726 		USB_REQUEST_GET_STATUS,
727 		0,
728 		0,
729 		2,
730 		(void *)status,
731 		2,
732 		NULL);
733 }
734