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