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