xref: /haiku/src/add-ons/kernel/bus_managers/usb/Device.cpp (revision 1705656eac83cd8b65c2ee895888cd529c62c04c)
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 				case USB_DESCRIPTOR_ENDPOINT_COMPANION: {
258 					usb_endpoint_descriptor* desc = currentInterface
259 						->endpoint[currentInterface->endpoint_count - 1].descr;
260 					if ((uint8*)desc != (&configData[descriptorStart
261 							- desc->length])) {
262 						TRACE_ERROR("found endpoint companion descriptor not immediately "
263 							"following endpoint descriptor, ignoring!\n");
264 						break;
265 					}
266 					// TODO: It'd be nicer if we could store the endpoint companion
267 					// descriptor along with the endpoint descriptor, but as the
268 					// interface struct is public API, that would be an ABI break.
269 
270 					// fall through
271 				}
272 
273 				default:
274 					TRACE("got generic descriptor\n");
275 					usb_generic_descriptor* genericDescriptor
276 						= (usb_generic_descriptor*)&configData[descriptorStart];
277 					TRACE("\tlength:.............%d\n",
278 						genericDescriptor->length);
279 					TRACE("\tdescriptor_type:....0x%02x\n",
280 						genericDescriptor->descriptor_type);
281 
282 					if (currentInterface == NULL)
283 						break;
284 
285 					// Allocate this descriptor
286 					currentInterface->generic_count++;
287 					usb_descriptor** newGenerics = (usb_descriptor**)realloc(
288 						currentInterface->generic,
289 						currentInterface->generic_count
290 							* sizeof(usb_descriptor*));
291 					if (newGenerics == NULL) {
292 						TRACE_ERROR("out of memory allocating"
293 							" generic descriptor\n");
294 						currentInterface->generic_count--;
295 						return;
296 					}
297 
298 					currentInterface->generic = newGenerics;
299 
300 					// Add this descriptor
301 					currentInterface->generic[
302 						currentInterface->generic_count - 1]
303 							= (usb_descriptor*)genericDescriptor;
304 					break;
305 			}
306 
307 			descriptorStart += configData[descriptorStart];
308 		}
309 	}
310 
311 	// Set default configuration
312 	TRACE("setting default configuration\n");
313 	if (SetConfigurationAt(0) != B_OK) {
314 		TRACE_ERROR("failed to set default configuration\n");
315 		return;
316 	}
317 
318 	fInitOK = true;
319 }
320 
321 
322 Device::~Device()
323 {
324 	// Unset fInitOK to indicate we are tearing down.
325 	fInitOK = false;
326 
327 	delete fDefaultPipe;
328 
329 	if (fConfigurations == NULL) {
330 		// we didn't get far in device setup, so everything below is unneeded
331 		return;
332 	}
333 
334 	// Destroy open endpoints. Do not send a device request to unconfigure
335 	// though, since we may be deleted because the device was unplugged
336 	// already.
337 	Unconfigure(false);
338 
339 	// Free all allocated resources
340 	for (int32 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
341 		usb_configuration_info* configuration = &fConfigurations[i];
342 		if (configuration == NULL)
343 			continue;
344 
345 		free(configuration->descr);
346 		if (configuration->interface == NULL)
347 			continue;
348 
349 		for (size_t j = 0; j < configuration->interface_count; j++) {
350 			usb_interface_list* interfaceList = &configuration->interface[j];
351 			if (interfaceList->alt == NULL)
352 				continue;
353 
354 			for (size_t k = 0; k < interfaceList->alt_count; k++) {
355 				usb_interface_info* interface = &interfaceList->alt[k];
356 				delete (Interface*)GetStack()->GetObject(interface->handle);
357 				free(interface->endpoint);
358 				free(interface->generic);
359 			}
360 
361 			free(interfaceList->alt);
362 		}
363 
364 		free(configuration->interface);
365 	}
366 
367 	free(fConfigurations);
368 }
369 
370 
371 status_t
372 Device::InitCheck()
373 {
374 	if (fInitOK)
375 		return B_OK;
376 
377 	return B_ERROR;
378 }
379 
380 
381 status_t
382 Device::Changed(change_item** changeList, bool added)
383 {
384 	fAvailable = added;
385 	change_item* changeItem = new(std::nothrow) change_item;
386 	if (changeItem == NULL)
387 		return B_NO_MEMORY;
388 
389 	changeItem->added = added;
390 	changeItem->device = this;
391 	changeItem->link = *changeList;
392 	*changeList = changeItem;
393 	return B_OK;
394 }
395 
396 
397 status_t
398 Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
399 	void* data, size_t dataLength, size_t* actualLength)
400 {
401 	if (!fAvailable)
402 		return B_ERROR;
403 
404 	return fDefaultPipe->SendRequest(
405 		USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD,
406 		USB_REQUEST_GET_DESCRIPTOR, (descriptorType << 8) | index,
407 		languageID, dataLength, data, dataLength, actualLength);
408 }
409 
410 
411 const usb_configuration_info*
412 Device::Configuration() const
413 {
414 	return fCurrentConfiguration;
415 }
416 
417 
418 const usb_configuration_info*
419 Device::ConfigurationAt(uint8 index) const
420 {
421 	if (index >= fDeviceDescriptor.num_configurations)
422 		return NULL;
423 
424 	return &fConfigurations[index];
425 }
426 
427 
428 status_t
429 Device::SetConfiguration(const usb_configuration_info* configuration)
430 {
431 	if (!configuration)
432 		return Unconfigure(true);
433 
434 	for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
435 		if (configuration->descr->configuration_value
436 				== fConfigurations[i].descr->configuration_value)
437 			return SetConfigurationAt(i);
438 	}
439 
440 	return B_BAD_VALUE;
441 }
442 
443 
444 status_t
445 Device::SetConfigurationAt(uint8 index)
446 {
447 	if (!fAvailable)
448 		return B_ERROR;
449 	if (index >= fDeviceDescriptor.num_configurations)
450 		return B_BAD_VALUE;
451 	if (&fConfigurations[index] == fCurrentConfiguration)
452 		return B_OK;
453 
454 	// Destroy our open endpoints
455 	Unconfigure(false);
456 
457 	// Tell the device to set the configuration
458 	status_t result = fDefaultPipe->SendRequest(
459 		USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD,
460 		USB_REQUEST_SET_CONFIGURATION,
461 		fConfigurations[index].descr->configuration_value, 0, 0, NULL, 0, NULL);
462 	if (result < B_OK)
463 		return result;
464 
465 	// Set current configuration
466 	fCurrentConfiguration = &fConfigurations[index];
467 
468 	// Initialize all the endpoints that are now active
469 	InitEndpoints(-1);
470 
471 	// Wait some for the configuration being finished
472 	if (!fIsRootHub)
473 		snooze(USB_DELAY_SET_CONFIGURATION);
474 	return B_OK;
475 }
476 
477 
478 void
479 Device::InitEndpoints(int32 interfaceIndex)
480 {
481 	for (size_t j = 0; j < fCurrentConfiguration->interface_count; j++) {
482 		if (interfaceIndex >= 0 && j != (size_t)interfaceIndex)
483 			continue;
484 
485 		usb_interface_info* interfaceInfo
486 			= fCurrentConfiguration->interface[j].active;
487 		if (interfaceInfo == NULL)
488 			continue;
489 
490 		for (size_t i = 0; i < interfaceInfo->endpoint_count; i++) {
491 			usb_endpoint_info* endpoint = &interfaceInfo->endpoint[i];
492 			Pipe* pipe = NULL;
493 
494 			usb_endpoint_companion_descriptor* comp_descr = NULL;
495 			if (fSpeed == USB_SPEED_SUPER) {
496 				// We should have a companion descriptor for this device.
497 				// Let's find it: it'll be the "i"th one.
498 				size_t k = 0;
499 				for (size_t j = 0; j < interfaceInfo->generic_count; j++) {
500 					usb_descriptor* desc = interfaceInfo->generic[j];
501 					if (desc->endpoint.descriptor_type
502 							!= USB_DESCRIPTOR_ENDPOINT_COMPANION) {
503 						continue;
504 					}
505 					if (k == i) {
506 						comp_descr = (usb_endpoint_companion_descriptor*)desc;
507 						break;
508 					}
509 					k++;
510 				}
511 				if (comp_descr == NULL) {
512 					TRACE_ERROR("SuperSpeed device without an endpoint companion "
513 						"descriptor!");
514 				}
515 			}
516 
517 			Pipe::pipeDirection direction = Pipe::Out;
518 			if ((endpoint->descr->endpoint_address & 0x80) != 0)
519 				direction = Pipe::In;
520 
521 			switch (endpoint->descr->attributes & 0x03) {
522 				case USB_ENDPOINT_ATTR_CONTROL:		// Control Endpoint
523 					pipe = new(std::nothrow) ControlPipe(this);
524 					direction = Pipe::Default;
525 					break;
526 
527 				case USB_ENDPOINT_ATTR_ISOCHRONOUS:	// Isochronous Endpoint
528 					pipe = new(std::nothrow) IsochronousPipe(this);
529 					break;
530 
531 				case USB_ENDPOINT_ATTR_BULK:		// Bulk Endpoint
532 					pipe = new(std::nothrow) BulkPipe(this);
533 					break;
534 
535 				case USB_ENDPOINT_ATTR_INTERRUPT:	// Interrupt Endpoint
536 					pipe = new(std::nothrow) InterruptPipe(this);
537 					break;
538 			}
539 
540 			if (pipe == NULL) {
541 				TRACE_ERROR("failed to allocate pipe\n");
542 				endpoint->handle = 0;
543 				continue;
544 			}
545 
546 			pipe->InitCommon(fDeviceAddress,
547 				endpoint->descr->endpoint_address & 0x0f,
548 				fSpeed, direction, endpoint->descr->max_packet_size,
549 				endpoint->descr->interval, fHubAddress, fHubPort);
550 			if (comp_descr != NULL) {
551 				pipe->InitSuperSpeed(comp_descr->max_burst,
552 					comp_descr->bytes_per_interval);
553 			}
554 			endpoint->handle = pipe->USBID();
555 		}
556 	}
557 }
558 
559 
560 status_t
561 Device::Unconfigure(bool atDeviceLevel)
562 {
563 	// If we only want to destroy our open pipes before setting
564 	// another configuration unconfigure will be called with
565 	// atDevice = false. otherwise we explicitly want to unconfigure
566 	// the device and have to send it the corresponding request.
567 	if (atDeviceLevel && fAvailable) {
568 		status_t result = fDefaultPipe->SendRequest(
569 			USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD,
570 			USB_REQUEST_SET_CONFIGURATION, 0, 0, 0, NULL, 0, NULL);
571 		if (result < B_OK)
572 			return result;
573 
574 		snooze(USB_DELAY_SET_CONFIGURATION);
575 	}
576 
577 	if (!fCurrentConfiguration)
578 		return B_OK;
579 
580 	ClearEndpoints(-1);
581 	fCurrentConfiguration = NULL;
582 	return B_OK;
583 }
584 
585 
586 void
587 Device::ClearEndpoints(int32 interfaceIndex)
588 {
589 	if (fCurrentConfiguration == NULL
590 		|| fCurrentConfiguration->interface == NULL)
591 		return;
592 
593 	for (size_t j = 0; j < fCurrentConfiguration->interface_count; j++) {
594 		if (interfaceIndex >= 0 && j != (size_t)interfaceIndex)
595 			continue;
596 
597 		usb_interface_info* interfaceInfo
598 			= fCurrentConfiguration->interface[j].active;
599 		if (interfaceInfo == NULL || interfaceInfo->endpoint == NULL)
600 			continue;
601 
602 		for (size_t i = 0; i < interfaceInfo->endpoint_count; i++) {
603 			usb_endpoint_info* endpoint = &interfaceInfo->endpoint[i];
604 			delete (Pipe*)GetStack()->GetObject(endpoint->handle);
605 			endpoint->handle = 0;
606 		}
607 	}
608 }
609 
610 
611 status_t
612 Device::SetAltInterface(const usb_interface_info* interface)
613 {
614 	uint8 interfaceNumber = interface->descr->interface_number;
615 	// Tell the device to set the alternate settings
616 	status_t result = fDefaultPipe->SendRequest(
617 		USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_STANDARD,
618 		USB_REQUEST_SET_INTERFACE,
619 		interface->descr->alternate_setting, interfaceNumber, 0, NULL, 0, NULL);
620 	if (result < B_OK)
621 		return result;
622 
623 	// Clear the no longer active endpoints
624 	ClearEndpoints(interfaceNumber);
625 
626 	// Update the active pointer of the interface list
627 	usb_interface_list* interfaceList
628 		= &fCurrentConfiguration->interface[interfaceNumber];
629 	interfaceList->active
630 		= &interfaceList->alt[interface->descr->alternate_setting];
631 
632 	// Initialize the new endpoints
633 	InitEndpoints(interfaceNumber);
634 	return result;
635 }
636 
637 
638 const usb_device_descriptor*
639 Device::DeviceDescriptor() const
640 {
641 	return &fDeviceDescriptor;
642 }
643 
644 
645 status_t
646 Device::ReportDevice(usb_support_descriptor* supportDescriptors,
647 	uint32 supportDescriptorCount, const usb_notify_hooks* hooks,
648 	usb_driver_cookie** cookies, bool added, bool recursive)
649 {
650 	TRACE("reporting device\n");
651 	bool supported = false;
652 	if (supportDescriptorCount == 0 || supportDescriptors == NULL)
653 		supported = true;
654 
655 	for (uint32 i = 0; !supported && i < supportDescriptorCount; i++) {
656 		if ((supportDescriptors[i].vendor != 0
657 				&& fDeviceDescriptor.vendor_id != supportDescriptors[i].vendor)
658 			|| (supportDescriptors[i].product != 0
659 				&& fDeviceDescriptor.product_id
660 					!= supportDescriptors[i].product))
661 			continue;
662 
663 		if ((supportDescriptors[i].dev_class == 0
664 				|| fDeviceDescriptor.device_class
665 					== supportDescriptors[i].dev_class)
666 			&& (supportDescriptors[i].dev_subclass == 0
667 				|| fDeviceDescriptor.device_subclass
668 					== supportDescriptors[i].dev_subclass)
669 			&& (supportDescriptors[i].dev_protocol == 0
670 				|| fDeviceDescriptor.device_protocol
671 					== supportDescriptors[i].dev_protocol)) {
672 			supported = true;
673 		}
674 
675 		// we have to check all interfaces for matching class/subclass/protocol
676 		for (uint32 j = 0;
677 				!supported && j < fDeviceDescriptor.num_configurations; j++) {
678 			for (uint32 k = 0;
679 					!supported && k < fConfigurations[j].interface_count; k++) {
680 				for (uint32 l = 0; !supported
681 					&& l < fConfigurations[j].interface[k].alt_count; l++) {
682 					usb_interface_descriptor* descriptor
683 						= fConfigurations[j].interface[k].alt[l].descr;
684 					if ((supportDescriptors[i].dev_class == 0
685 							|| descriptor->interface_class
686 								== supportDescriptors[i].dev_class)
687 						&& (supportDescriptors[i].dev_subclass == 0
688 							|| descriptor->interface_subclass
689 								== supportDescriptors[i].dev_subclass)
690 						&& (supportDescriptors[i].dev_protocol == 0
691 							|| descriptor->interface_protocol
692 								== supportDescriptors[i].dev_protocol)) {
693 						supported = true;
694 					}
695 				}
696 			}
697 		}
698 	}
699 
700 	if (!supported)
701 		return B_UNSUPPORTED;
702 
703 	if ((added && hooks->device_added == NULL)
704 		|| (!added && hooks->device_removed == NULL)) {
705 		// hooks are not installed, but report success to indicate that
706 		// the driver supports the device
707 		return B_OK;
708 	}
709 
710 	usb_id id = USBID();
711 	if (added) {
712 		usb_driver_cookie* cookie = new(std::nothrow) usb_driver_cookie;
713 		if (hooks->device_added(id, &cookie->cookie) >= B_OK) {
714 			cookie->device = id;
715 			cookie->link = *cookies;
716 			*cookies = cookie;
717 		} else
718 			delete cookie;
719 	} else {
720 		usb_driver_cookie** pointer = cookies;
721 		usb_driver_cookie* cookie = *cookies;
722 		while (cookie != NULL) {
723 			if (cookie->device == id)
724 				break;
725 			pointer = &cookie->link;
726 			cookie = cookie->link;
727 		}
728 
729 		if (cookie == NULL) {
730 			// the device is supported, but there is no cookie. this most
731 			// probably means that the device_added hook above failed.
732 			return B_OK;
733 		}
734 
735 		hooks->device_removed(cookie->cookie);
736 		*pointer = cookie->link;
737 		delete cookie;
738 	}
739 
740 	return B_OK;
741 }
742 
743 
744 status_t
745 Device::BuildDeviceName(char* string, uint32* index, size_t bufferSize,
746 	Device* device)
747 {
748 	if (!Parent() || (Parent()->Type() & USB_OBJECT_HUB) == 0)
749 		return B_ERROR;
750 
751 	((Hub*)Parent())->BuildDeviceName(string, index, bufferSize, this);
752 	return B_OK;
753 }
754 
755 
756 status_t
757 Device::SetFeature(uint16 selector)
758 {
759 	if (!fAvailable)
760 		return B_ERROR;
761 
762 	TRACE("set feature %u\n", selector);
763 	return fDefaultPipe->SendRequest(
764 		USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
765 		USB_REQUEST_SET_FEATURE, selector, 0, 0, NULL, 0, NULL);
766 }
767 
768 
769 status_t
770 Device::ClearFeature(uint16 selector)
771 {
772 	if (!fAvailable)
773 		return B_ERROR;
774 
775 	TRACE("clear feature %u\n", selector);
776 	return fDefaultPipe->SendRequest(
777 		USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
778 		USB_REQUEST_CLEAR_FEATURE, selector, 0, 0, NULL, 0, NULL);
779 }
780 
781 
782 status_t
783 Device::GetStatus(uint16* status)
784 {
785 	if (!fAvailable)
786 		return B_ERROR;
787 
788 	TRACE("get status\n");
789 	return fDefaultPipe->SendRequest(
790 		USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_IN,
791 		USB_REQUEST_GET_STATUS, 0, 0, 2, (void*)status, 2, NULL);
792 }
793