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