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
13Device::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 %" B_PRId32 "\n", i);
85			return;
86		}
87
88		TRACE("configuration %" B_PRId32 "\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 %" B_PRId32 " got %" B_PRIuSIZE " expected %"
110				B_PRIu16 "\n", i, 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
278Device::~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
324status_t
325Device::InitCheck()
326{
327	if (fInitOK)
328		return B_OK;
329
330	return B_ERROR;
331}
332
333
334status_t
335Device::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
350status_t
351Device::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
369const usb_configuration_info *
370Device::Configuration() const
371{
372	return fCurrentConfiguration;
373}
374
375
376const usb_configuration_info *
377Device::ConfigurationAt(uint8 index) const
378{
379	if (index >= fDeviceDescriptor.num_configurations)
380		return NULL;
381
382	return &fConfigurations[index];
383}
384
385
386status_t
387Device::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
402status_t
403Device::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
442void
443Device::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
493status_t
494Device::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
526void
527Device::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
549status_t
550Device::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
581const usb_device_descriptor *
582Device::DeviceDescriptor() const
583{
584	return &fDeviceDescriptor;
585}
586
587
588status_t
589Device::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
676status_t
677Device::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
688status_t
689Device::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
707status_t
708Device::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
726status_t
727Device::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