xref: /haiku/src/add-ons/kernel/bus_managers/usb/usb.cpp (revision f7325a93db585836da1ad886575ed30d93c8f2df)
196da8285SMichael Lotz /*
296da8285SMichael Lotz  * Copyright 2003-2006, Haiku Inc. All rights reserved.
396da8285SMichael Lotz  * Distributed under the terms of the MIT License.
496da8285SMichael Lotz  *
596da8285SMichael Lotz  * Authors:
65b0ec61fSMichael Lotz  *		Michael Lotz <mmlr@mlotz.ch>
796da8285SMichael Lotz  *		Niels S. Reedijk
896da8285SMichael Lotz  */
91501c2bfSNiels Sascha Reedijk 
1021c87a5dSJérôme Duval 
111501c2bfSNiels Sascha Reedijk #include <util/kernel_cpp.h>
12853e6be8SMichael Lotz #include "usb_private.h"
131bad4a4eSMichael Lotz #include <USB_rle.h>
141501c2bfSNiels Sascha Reedijk 
15f14fe767SMichael Lotz #define USB_MODULE_NAME "module"
1696da8285SMichael Lotz 
17b8c6a851SMichael Lotz Stack *gUSBStack = NULL;
18e6ce95c5SJérôme Duval device_manager_info *gDeviceManager;
19b8c6a851SMichael Lotz 
20b8c6a851SMichael Lotz 
21159aa93bSMichael Lotz /*!	The function is an evil hack to allow <tt> <kdebug>usb_keyboard </tt> to
22159aa93bSMichael Lotz 	execute transfers.
23159aa93bSMichael Lotz 	When invoked the first time, a new transfer is started, each time the
24159aa93bSMichael Lotz 	function is called afterwards, it is checked whether the transfer is already
25159aa93bSMichael Lotz 	completed. If called with argv[1] == "cancel" the function cancels a
26159aa93bSMichael Lotz 	possibly pending transfer.
27159aa93bSMichael Lotz */
28159aa93bSMichael Lotz static status_t
debug_run_transfer(Pipe * pipe,uint8 * data,size_t dataLength,usb_request_data * requestData,bool cancel)29159aa93bSMichael Lotz debug_run_transfer(Pipe *pipe, uint8 *data, size_t dataLength,
30159aa93bSMichael Lotz 	usb_request_data *requestData, bool cancel)
31159aa93bSMichael Lotz {
32159aa93bSMichael Lotz 	static uint8 transferBuffer[sizeof(Transfer)]
33159aa93bSMichael Lotz 		__attribute__((aligned(16)));
34159aa93bSMichael Lotz 	static Transfer *transfer = NULL;
35159aa93bSMichael Lotz 
36159aa93bSMichael Lotz 	BusManager *bus = pipe->GetBusManager();
37159aa93bSMichael Lotz 
38159aa93bSMichael Lotz 	if (cancel) {
39159aa93bSMichael Lotz 		if (transfer != NULL) {
40159aa93bSMichael Lotz 			bus->CancelDebugTransfer(transfer);
41159aa93bSMichael Lotz 			transfer = NULL;
42159aa93bSMichael Lotz 		}
43159aa93bSMichael Lotz 
44159aa93bSMichael Lotz 		return B_OK;
45159aa93bSMichael Lotz 	}
46159aa93bSMichael Lotz 
47159aa93bSMichael Lotz 	if (transfer != NULL) {
48159aa93bSMichael Lotz 		status_t error = bus->CheckDebugTransfer(transfer);
49159aa93bSMichael Lotz 		if (error != B_DEV_PENDING)
50159aa93bSMichael Lotz 			transfer = NULL;
51159aa93bSMichael Lotz 
52159aa93bSMichael Lotz 		return error;
53159aa93bSMichael Lotz 	}
54159aa93bSMichael Lotz 
55159aa93bSMichael Lotz 	transfer = new(transferBuffer) Transfer(pipe);
56159aa93bSMichael Lotz 	transfer->SetData(data, dataLength);
57159aa93bSMichael Lotz 	transfer->SetRequestData(requestData);
58159aa93bSMichael Lotz 
59159aa93bSMichael Lotz 	status_t error = bus->StartDebugTransfer(transfer);
60159aa93bSMichael Lotz 	if (error != B_OK) {
61159aa93bSMichael Lotz 		transfer = NULL;
62159aa93bSMichael Lotz 		return error;
63159aa93bSMichael Lotz 	}
64159aa93bSMichael Lotz 
65159aa93bSMichael Lotz 	return B_DEV_PENDING;
66159aa93bSMichael Lotz }
67159aa93bSMichael Lotz 
68159aa93bSMichael Lotz 
696eba0636SMichael Lotz static int
debug_get_pipe_for_id(int argc,char ** argv)706eba0636SMichael Lotz debug_get_pipe_for_id(int argc, char **argv)
716eba0636SMichael Lotz {
726eba0636SMichael Lotz 	if (gUSBStack == NULL)
736eba0636SMichael Lotz 		return 1;
746eba0636SMichael Lotz 
756eba0636SMichael Lotz 	if (!is_debug_variable_defined("_usbPipeID"))
766eba0636SMichael Lotz 		return 2;
776eba0636SMichael Lotz 
786eba0636SMichael Lotz 	uint64 id = get_debug_variable("_usbPipeID", 0);
796eba0636SMichael Lotz 	Object *object = gUSBStack->GetObjectNoLock((usb_id)id);
806eba0636SMichael Lotz 	if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
816eba0636SMichael Lotz 		return 3;
826eba0636SMichael Lotz 
836eba0636SMichael Lotz 	set_debug_variable("_usbPipe", (uint64)object);
846eba0636SMichael Lotz 	return 0;
856eba0636SMichael Lotz }
86159aa93bSMichael Lotz 
87159aa93bSMichael Lotz 
88159aa93bSMichael Lotz static int
debug_process_transfer(int argc,char ** argv)89159aa93bSMichael Lotz debug_process_transfer(int argc, char **argv)
90159aa93bSMichael Lotz {
91159aa93bSMichael Lotz 	Pipe *pipe = (Pipe *)get_debug_variable("_usbPipe", 0);
92159aa93bSMichael Lotz 	if (pipe == NULL)
93159aa93bSMichael Lotz 		return B_BAD_VALUE;
94159aa93bSMichael Lotz 
95159aa93bSMichael Lotz 	uint8 *data = (uint8 *)get_debug_variable("_usbTransferData", 0);
96159aa93bSMichael Lotz 	size_t length = (size_t)get_debug_variable("_usbTransferLength", 0);
97159aa93bSMichael Lotz 	usb_request_data *requestData
98159aa93bSMichael Lotz 		= (usb_request_data *)get_debug_variable("_usbRequestData", 0);
99159aa93bSMichael Lotz 
100159aa93bSMichael Lotz 	return debug_run_transfer(pipe, data, length, requestData,
101159aa93bSMichael Lotz 		argc > 1 && strcmp(argv[1], "cancel") == 0);
102159aa93bSMichael Lotz }
103e31cac6eSMichael Lotz 
104e31cac6eSMichael Lotz 
105e31cac6eSMichael Lotz static int
debug_clear_stall(int argc,char * argv[])106e31cac6eSMichael Lotz debug_clear_stall(int argc, char *argv[])
107e31cac6eSMichael Lotz {
108e31cac6eSMichael Lotz 	Pipe *pipe = (Pipe *)get_debug_variable("_usbPipe", 0);
109e31cac6eSMichael Lotz 	if (pipe == NULL)
110e31cac6eSMichael Lotz 		return B_BAD_VALUE;
111e31cac6eSMichael Lotz 
112e31cac6eSMichael Lotz 	static usb_request_data requestData;
113e31cac6eSMichael Lotz 
114e31cac6eSMichael Lotz 	requestData.RequestType = USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT;
115e31cac6eSMichael Lotz 	requestData.Request = USB_REQUEST_CLEAR_FEATURE;
116e31cac6eSMichael Lotz 	requestData.Value = USB_FEATURE_ENDPOINT_HALT;
117e31cac6eSMichael Lotz 	requestData.Index = pipe->EndpointAddress()
118e31cac6eSMichael Lotz 		| (pipe->Direction() == Pipe::In ? USB_ENDPOINT_ADDR_DIR_IN
119e31cac6eSMichael Lotz 			: USB_ENDPOINT_ADDR_DIR_OUT);
120e31cac6eSMichael Lotz 	requestData.Length = 0;
121e31cac6eSMichael Lotz 
122e31cac6eSMichael Lotz 	Pipe *parentPipe = ((Device *)pipe->Parent())->DefaultPipe();
123e31cac6eSMichael Lotz 	for (int tries = 0; tries < 100; tries++) {
124e31cac6eSMichael Lotz 		status_t result
125e31cac6eSMichael Lotz 			= debug_run_transfer(parentPipe, NULL, 0, &requestData, false);
126e31cac6eSMichael Lotz 
127e31cac6eSMichael Lotz 		if (result == B_DEV_PENDING)
128e31cac6eSMichael Lotz 			continue;
129e31cac6eSMichael Lotz 
130e31cac6eSMichael Lotz 		if (result == B_OK) {
131e31cac6eSMichael Lotz 			// clearing a stalled condition resets the data toggle
132e31cac6eSMichael Lotz 			pipe->SetDataToggle(false);
133e31cac6eSMichael Lotz 			return B_OK;
134e31cac6eSMichael Lotz 		}
135e31cac6eSMichael Lotz 
136e31cac6eSMichael Lotz 		return result;
137e31cac6eSMichael Lotz 	}
138e31cac6eSMichael Lotz 
139e31cac6eSMichael Lotz 	return B_TIMED_OUT;
140e31cac6eSMichael Lotz }
1416eba0636SMichael Lotz 
1426eba0636SMichael Lotz 
1431501c2bfSNiels Sascha Reedijk static int32
bus_std_ops(int32 op,...)1441501c2bfSNiels Sascha Reedijk bus_std_ops(int32 op, ...)
1451501c2bfSNiels Sascha Reedijk {
1461501c2bfSNiels Sascha Reedijk 	switch (op) {
14796da8285SMichael Lotz 		case B_MODULE_INIT: {
148f14fe767SMichael Lotz 			TRACE_MODULE("init\n");
1495b0ec61fSMichael Lotz 			if (gUSBStack)
1505b0ec61fSMichael Lotz 				return B_OK;
1515b0ec61fSMichael Lotz 
15296da8285SMichael Lotz #ifdef TRACE_USB
1531a2e81b5SNiels Sascha Reedijk 			set_dprintf_enabled(true);
15402ce23a1SMichael Lotz #endif
155b8c6a851SMichael Lotz 			Stack *stack = new(std::nothrow) Stack();
156f14fe767SMichael Lotz 			TRACE_MODULE("usb_module: stack created %p\n", stack);
157b8c6a851SMichael Lotz 			if (!stack)
158b8c6a851SMichael Lotz 				return B_NO_MEMORY;
159b8c6a851SMichael Lotz 
16096da8285SMichael Lotz 			if (stack->InitCheck() != B_OK) {
1611a2e81b5SNiels Sascha Reedijk 				delete stack;
1621501c2bfSNiels Sascha Reedijk 				return ENODEV;
1631501c2bfSNiels Sascha Reedijk 			}
16496da8285SMichael Lotz 
165eb6a1cbcSMichael Lotz 			gUSBStack = stack;
166eb01fb72SMichael Lotz 
1676eba0636SMichael Lotz 			add_debugger_command("get_usb_pipe_for_id",
1686eba0636SMichael Lotz 				&debug_get_pipe_for_id,
169159aa93bSMichael Lotz 				"Sets _usbPipe by resolving _usbPipeID");
170159aa93bSMichael Lotz 			add_debugger_command("usb_process_transfer",
171159aa93bSMichael Lotz 				&debug_process_transfer,
172159aa93bSMichael Lotz 				"Transfers _usbTransferData with _usbTransferLength"
173159aa93bSMichael Lotz 				" (and/or _usbRequestData) to pipe _usbPipe");
174e31cac6eSMichael Lotz 			add_debugger_command("usb_clear_stall",
175e31cac6eSMichael Lotz 				&debug_clear_stall,
176e31cac6eSMichael Lotz 				"Tries to issue a clear feature request for the endpoint halt"
177e31cac6eSMichael Lotz 				" feature on pipe _usbPipe");
1781501c2bfSNiels Sascha Reedijk 			break;
17996da8285SMichael Lotz 		}
18096da8285SMichael Lotz 
1811501c2bfSNiels Sascha Reedijk 		case B_MODULE_UNINIT:
182f14fe767SMichael Lotz 			TRACE_MODULE("uninit\n");
183b8c6a851SMichael Lotz 			delete gUSBStack;
184b8c6a851SMichael Lotz 			gUSBStack = NULL;
185eb01fb72SMichael Lotz 
1866eba0636SMichael Lotz 			remove_debugger_command("get_usb_pipe_for_id",
1876eba0636SMichael Lotz 				&debug_get_pipe_for_id);
1881501c2bfSNiels Sascha Reedijk 			break;
18996da8285SMichael Lotz 
1901501c2bfSNiels Sascha Reedijk 		default:
1911501c2bfSNiels Sascha Reedijk 			return EINVAL;
1921501c2bfSNiels Sascha Reedijk 	}
19396da8285SMichael Lotz 
1941501c2bfSNiels Sascha Reedijk 	return B_OK;
1951501c2bfSNiels Sascha Reedijk }
1961501c2bfSNiels Sascha Reedijk 
1971501c2bfSNiels Sascha Reedijk 
1985ee91867SAugustin Cavalier // #pragma mark - public methods
1995ee91867SAugustin Cavalier 
2005ee91867SAugustin Cavalier 
201b8c6a851SMichael Lotz status_t
register_driver(const char * driverName,const usb_support_descriptor * descriptors,size_t count,const char * optionalRepublishDriverName)202b8c6a851SMichael Lotz register_driver(const char *driverName,
203b8c6a851SMichael Lotz 	const usb_support_descriptor *descriptors,
204b8c6a851SMichael Lotz 	size_t count, const char *optionalRepublishDriverName)
205b8c6a851SMichael Lotz {
206b8c6a851SMichael Lotz 	return gUSBStack->RegisterDriver(driverName, descriptors, count,
207b8c6a851SMichael Lotz 		optionalRepublishDriverName);
208b8c6a851SMichael Lotz }
209b8c6a851SMichael Lotz 
210b8c6a851SMichael Lotz 
211b8c6a851SMichael Lotz status_t
install_notify(const char * driverName,const usb_notify_hooks * hooks)212b8c6a851SMichael Lotz install_notify(const char *driverName, const usb_notify_hooks *hooks)
213b8c6a851SMichael Lotz {
214b8c6a851SMichael Lotz 	return gUSBStack->InstallNotify(driverName, hooks);
215b8c6a851SMichael Lotz }
216b8c6a851SMichael Lotz 
217b8c6a851SMichael Lotz 
218b8c6a851SMichael Lotz status_t
uninstall_notify(const char * driverName)219b8c6a851SMichael Lotz uninstall_notify(const char *driverName)
220b8c6a851SMichael Lotz {
221b8c6a851SMichael Lotz 	return gUSBStack->UninstallNotify(driverName);
222b8c6a851SMichael Lotz }
223b8c6a851SMichael Lotz 
224b8c6a851SMichael Lotz 
225b8c6a851SMichael Lotz const usb_device_descriptor *
get_device_descriptor(usb_device dev)226dd249016SAugustin Cavalier get_device_descriptor(usb_device dev)
227b8c6a851SMichael Lotz {
228dd249016SAugustin Cavalier 	TRACE_MODULE("get_device_descriptor(%" B_PRId32 ")\n", dev);
229*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
2305ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
231b8c6a851SMichael Lotz 		return NULL;
2325ee91867SAugustin Cavalier 	Device *device = (Device *)object.Get();
233b8c6a851SMichael Lotz 
234dd249016SAugustin Cavalier 	return device->DeviceDescriptor();
235b8c6a851SMichael Lotz }
236b8c6a851SMichael Lotz 
237b8c6a851SMichael Lotz 
238b8c6a851SMichael Lotz const usb_configuration_info *
get_nth_configuration(usb_device dev,uint32 index)239dd249016SAugustin Cavalier get_nth_configuration(usb_device dev, uint32 index)
240b8c6a851SMichael Lotz {
241d8b4cfc9SRene Gollent 	TRACE_MODULE("get_nth_configuration(%" B_PRId32 ", %" B_PRIu32 ")\n",
242dd249016SAugustin Cavalier 		dev, index);
243*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
2445ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
245b8c6a851SMichael Lotz 		return NULL;
2465ee91867SAugustin Cavalier 	Device *device = (Device *)object.Get();
247b8c6a851SMichael Lotz 
248dd249016SAugustin Cavalier 	return device->ConfigurationAt((int32)index);
249b8c6a851SMichael Lotz }
250b8c6a851SMichael Lotz 
251b8c6a851SMichael Lotz 
252b8c6a851SMichael Lotz const usb_configuration_info *
get_configuration(usb_device dev)253dd249016SAugustin Cavalier get_configuration(usb_device dev)
254b8c6a851SMichael Lotz {
255dd249016SAugustin Cavalier 	TRACE_MODULE("get_configuration(%" B_PRId32 ")\n", dev);
256*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
2575ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
258b8c6a851SMichael Lotz 		return NULL;
2595ee91867SAugustin Cavalier 	Device *device = (Device *)object.Get();
260b8c6a851SMichael Lotz 
261dd249016SAugustin Cavalier 	return device->Configuration();
262b8c6a851SMichael Lotz }
263b8c6a851SMichael Lotz 
264b8c6a851SMichael Lotz 
265b8c6a851SMichael Lotz status_t
set_configuration(usb_device dev,const usb_configuration_info * configuration)266dd249016SAugustin Cavalier set_configuration(usb_device dev,
267b8c6a851SMichael Lotz 	const usb_configuration_info *configuration)
268b8c6a851SMichael Lotz {
269dd249016SAugustin Cavalier 	TRACE_MODULE("set_configuration(%" B_PRId32 ", %p)\n", dev,
270d8b4cfc9SRene Gollent 		configuration);
271*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
2725ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
27317f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
2745ee91867SAugustin Cavalier 	Device *device = (Device *)object.Get();
275b8c6a851SMichael Lotz 
276dd249016SAugustin Cavalier 	return device->SetConfiguration(configuration);
277b8c6a851SMichael Lotz }
278b8c6a851SMichael Lotz 
279b8c6a851SMichael Lotz 
280b8c6a851SMichael Lotz status_t
set_alt_interface(usb_device dev,const usb_interface_info * interface)281dd249016SAugustin Cavalier set_alt_interface(usb_device dev, const usb_interface_info *interface)
282b8c6a851SMichael Lotz {
283dd249016SAugustin Cavalier 	TRACE_MODULE("set_alt_interface(%" B_PRId32 ", %p)\n", dev, interface);
284*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
2855ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
28617f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
2875ee91867SAugustin Cavalier 	Device *device = (Device *)object.Get();
2885b0ec61fSMichael Lotz 
289dd249016SAugustin Cavalier 	return device->SetAltInterface(interface);
290b8c6a851SMichael Lotz }
291b8c6a851SMichael Lotz 
292b8c6a851SMichael Lotz 
293b8c6a851SMichael Lotz status_t
set_feature(usb_id handle,uint16 selector)2945b0ec61fSMichael Lotz set_feature(usb_id handle, uint16 selector)
295b8c6a851SMichael Lotz {
296d8b4cfc9SRene Gollent 	TRACE_MODULE("set_feature(%" B_PRId32 ", %d)\n", handle, selector);
297*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(handle), true);
2985ee91867SAugustin Cavalier 	if (!object.IsSet())
29917f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
300b8c6a851SMichael Lotz 
3018fedfdfcSMichael Lotz 	return object->SetFeature(selector);
302b8c6a851SMichael Lotz }
303b8c6a851SMichael Lotz 
304b8c6a851SMichael Lotz 
305b8c6a851SMichael Lotz status_t
clear_feature(usb_id handle,uint16 selector)3065b0ec61fSMichael Lotz clear_feature(usb_id handle, uint16 selector)
307b8c6a851SMichael Lotz {
308d8b4cfc9SRene Gollent 	TRACE_MODULE("clear_feature(%" B_PRId32 ", %d)\n", handle, selector);
309*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(handle), true);
3105ee91867SAugustin Cavalier 	if (!object.IsSet())
31117f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
312b8c6a851SMichael Lotz 
3138fedfdfcSMichael Lotz 	return object->ClearFeature(selector);
314b8c6a851SMichael Lotz }
315b8c6a851SMichael Lotz 
316b8c6a851SMichael Lotz 
317b8c6a851SMichael Lotz status_t
get_status(usb_id handle,uint16 * status)3185b0ec61fSMichael Lotz get_status(usb_id handle, uint16 *status)
319b8c6a851SMichael Lotz {
320d8b4cfc9SRene Gollent 	TRACE_MODULE("get_status(%" B_PRId32 ", %p)\n", handle, status);
3215b0ec61fSMichael Lotz 	if (!status)
3225b0ec61fSMichael Lotz 		return B_BAD_VALUE;
3235b0ec61fSMichael Lotz 
324*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(handle), true);
3255ee91867SAugustin Cavalier 	if (!object.IsSet())
32617f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
327b8c6a851SMichael Lotz 
3288fedfdfcSMichael Lotz 	return object->GetStatus(status);
329b8c6a851SMichael Lotz }
330b8c6a851SMichael Lotz 
331b8c6a851SMichael Lotz 
332b8c6a851SMichael Lotz status_t
get_descriptor(usb_device dev,uint8 type,uint8 index,uint16 languageID,void * data,size_t dataLength,size_t * actualLength)333dd249016SAugustin Cavalier get_descriptor(usb_device dev, uint8 type, uint8 index, uint16 languageID,
3345b0ec61fSMichael Lotz 	void *data, size_t dataLength, size_t *actualLength)
335b8c6a851SMichael Lotz {
336d8b4cfc9SRene Gollent 	TRACE_MODULE("get_descriptor(%" B_PRId32 ", 0x%02x, 0x%02x, 0x%04x, %p, "
337d8b4cfc9SRene Gollent 		"%" B_PRIuSIZE ", %p)\n",
338dd249016SAugustin Cavalier 		dev, type, index, languageID, data, dataLength, actualLength);
339*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
3405ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
34117f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
3425ee91867SAugustin Cavalier 	Device *device = (Device *)object.Get();
343b8c6a851SMichael Lotz 
344dd249016SAugustin Cavalier 	return device->GetDescriptor(type, index, languageID,
345b8c6a851SMichael Lotz 		data, dataLength, actualLength);
346b8c6a851SMichael Lotz }
347b8c6a851SMichael Lotz 
348b8c6a851SMichael Lotz 
349b8c6a851SMichael Lotz status_t
send_request(usb_device dev,uint8 requestType,uint8 request,uint16 value,uint16 index,uint16 length,void * data,size_t * actualLength)350dd249016SAugustin Cavalier send_request(usb_device dev, uint8 requestType, uint8 request,
3515b0ec61fSMichael Lotz 	uint16 value, uint16 index, uint16 length, void *data, size_t *actualLength)
352b8c6a851SMichael Lotz {
353d8b4cfc9SRene Gollent 	TRACE_MODULE("send_request(%" B_PRId32 ", 0x%02x, 0x%02x, 0x%04x, 0x%04x, "
354dd249016SAugustin Cavalier 		"%d, %p, %p)\n", dev, requestType, request, value, index, length,
355d8b4cfc9SRene Gollent 		data, actualLength);
356*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
3575ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
35817f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
3595ee91867SAugustin Cavalier 	Device *device = (Device *)object.Get();
360b8c6a851SMichael Lotz 
361dd249016SAugustin Cavalier 	return device->DefaultPipe()->SendRequest(requestType, request,
3628fedfdfcSMichael Lotz 		value, index, length, data, length, actualLength);
363b8c6a851SMichael Lotz }
364b8c6a851SMichael Lotz 
365b8c6a851SMichael Lotz 
366b8c6a851SMichael Lotz status_t
queue_request(usb_device dev,uint8 requestType,uint8 request,uint16 value,uint16 index,uint16 length,void * data,usb_callback_func callback,void * callbackCookie)367dd249016SAugustin Cavalier queue_request(usb_device dev, uint8 requestType, uint8 request,
3685b0ec61fSMichael Lotz 	uint16 value, uint16 index, uint16 length, void *data,
369b8c6a851SMichael Lotz 	usb_callback_func callback, void *callbackCookie)
370b8c6a851SMichael Lotz {
371d8b4cfc9SRene Gollent 	TRACE_MODULE("queue_request(%" B_PRId32 ", 0x%02x, 0x%02x, 0x%04x, 0x%04x,"
372dd249016SAugustin Cavalier 		" %u, %p, %p, %p)\n", dev, requestType, request, value, index,
373d8b4cfc9SRene Gollent 		length, data, callback,	callbackCookie);
374*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
3755ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
37617f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
3775ee91867SAugustin Cavalier 	Device *device = (Device *)object.Get();
378b8c6a851SMichael Lotz 
379dd249016SAugustin Cavalier 	return device->DefaultPipe()->QueueRequest(requestType,
3808fedfdfcSMichael Lotz 		request, value, index, length, data, length, callback, callbackCookie);
381b8c6a851SMichael Lotz }
382b8c6a851SMichael Lotz 
383b8c6a851SMichael Lotz 
384b8c6a851SMichael Lotz status_t
queue_interrupt(usb_pipe pipe,void * data,size_t dataLength,usb_callback_func callback,void * callbackCookie)3855b0ec61fSMichael Lotz queue_interrupt(usb_pipe pipe, void *data, size_t dataLength,
386b8c6a851SMichael Lotz 	usb_callback_func callback, void *callbackCookie)
387b8c6a851SMichael Lotz {
388d8b4cfc9SRene Gollent 	TRACE_MODULE("queue_interrupt(%" B_PRId32 ", %p, %ld, %p, %p)\n",
389f14fe767SMichael Lotz 		pipe, data, dataLength, callback, callbackCookie);
390*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(pipe), true);
3915ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_INTERRUPT_PIPE) == 0)
39217f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
393b8c6a851SMichael Lotz 
3945ee91867SAugustin Cavalier 	return ((InterruptPipe *)object.Get())->QueueInterrupt(data, dataLength,
3955ee91867SAugustin Cavalier 		callback, callbackCookie);
396b8c6a851SMichael Lotz }
397b8c6a851SMichael Lotz 
398b8c6a851SMichael Lotz 
399b8c6a851SMichael Lotz status_t
queue_bulk(usb_pipe pipe,void * data,size_t dataLength,usb_callback_func callback,void * callbackCookie)4005b0ec61fSMichael Lotz queue_bulk(usb_pipe pipe, void *data, size_t dataLength,
401b8c6a851SMichael Lotz 	usb_callback_func callback, void *callbackCookie)
402b8c6a851SMichael Lotz {
403d8b4cfc9SRene Gollent 	TRACE_MODULE("queue_bulk(%" B_PRId32 ", %p, %" B_PRIuSIZE ", %p, %p)\n",
404f14fe767SMichael Lotz 		pipe, data, dataLength, callback, callbackCookie);
405*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(pipe), true);
4065ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_BULK_PIPE) == 0)
40717f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
408b8c6a851SMichael Lotz 
4095ee91867SAugustin Cavalier 	return ((BulkPipe *)object.Get())->QueueBulk(data, dataLength, callback,
410b8c6a851SMichael Lotz 		callbackCookie);
411b8c6a851SMichael Lotz }
412b8c6a851SMichael Lotz 
413b8c6a851SMichael Lotz 
414b8c6a851SMichael Lotz status_t
queue_bulk_v(usb_pipe pipe,iovec * vector,size_t vectorCount,usb_callback_func callback,void * callbackCookie)4155b0ec61fSMichael Lotz queue_bulk_v(usb_pipe pipe, iovec *vector, size_t vectorCount,
4165b0ec61fSMichael Lotz 	usb_callback_func callback, void *callbackCookie)
417b8c6a851SMichael Lotz {
418d8b4cfc9SRene Gollent 	TRACE_MODULE("queue_bulk_v(%" B_PRId32 ", %p, %" B_PRIuSIZE " %p, %p)\n",
419f14fe767SMichael Lotz 		pipe, vector, vectorCount, callback, callbackCookie);
420*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(pipe), true);
4215ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_BULK_PIPE) == 0)
42217f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
423b8c6a851SMichael Lotz 
4245ee91867SAugustin Cavalier 	return ((BulkPipe *)object.Get())->QueueBulkV(vector, vectorCount,
42555a46882SAugustin Cavalier 		callback, callbackCookie);
42672457eddSMichael Lotz }
42772457eddSMichael Lotz 
42872457eddSMichael Lotz 
42972457eddSMichael Lotz status_t
queue_bulk_v_physical(usb_pipe pipe,physical_entry * vector,size_t vectorCount,usb_callback_func callback,void * callbackCookie)43055a46882SAugustin Cavalier queue_bulk_v_physical(usb_pipe pipe, physical_entry *vector, size_t vectorCount,
43172457eddSMichael Lotz 	usb_callback_func callback, void *callbackCookie)
43272457eddSMichael Lotz {
433d8b4cfc9SRene Gollent 	TRACE_MODULE("queue_bulk_v_physical(%" B_PRId32 ", %p, %" B_PRIuSIZE
434d8b4cfc9SRene Gollent 		", %p, %p)\n", pipe, vector, vectorCount, callback, callbackCookie);
435*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(pipe), true);
4365ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_BULK_PIPE) == 0)
43772457eddSMichael Lotz 		return B_DEV_INVALID_PIPE;
43872457eddSMichael Lotz 
4395ee91867SAugustin Cavalier 	return ((BulkPipe *)object.Get())->QueueBulkV(vector, vectorCount,
44055a46882SAugustin Cavalier 		callback, callbackCookie);
441b8c6a851SMichael Lotz }
442b8c6a851SMichael Lotz 
443b8c6a851SMichael Lotz 
444b8c6a851SMichael Lotz status_t
queue_isochronous(usb_pipe pipe,void * data,size_t dataLength,usb_iso_packet_descriptor * packetDesc,uint32 packetCount,uint32 * startingFrameNumber,uint32 flags,usb_callback_func callback,void * callbackCookie)4455b0ec61fSMichael Lotz queue_isochronous(usb_pipe pipe, void *data, size_t dataLength,
4461bad4a4eSMichael Lotz 	usb_iso_packet_descriptor *packetDesc, uint32 packetCount,
4471bad4a4eSMichael Lotz 	uint32 *startingFrameNumber, uint32 flags, usb_callback_func callback,
4485b0ec61fSMichael Lotz 	void *callbackCookie)
4495b0ec61fSMichael Lotz {
450d8b4cfc9SRene Gollent 	TRACE_MODULE("queue_isochronous(%" B_PRId32 ", %p, %" B_PRIuSIZE ", %p, "
451d8b4cfc9SRene Gollent 		"%" B_PRId32 ", %p, 0x%08" B_PRIx32 ", %p, %p)\n",
452f14fe767SMichael Lotz 		pipe, data, dataLength, packetDesc, packetCount, startingFrameNumber,
453f14fe767SMichael Lotz 		flags, callback, callbackCookie);
454*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(pipe), true);
4555ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_ISO_PIPE) == 0)
45617f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
4575b0ec61fSMichael Lotz 
4585ee91867SAugustin Cavalier 	return ((IsochronousPipe *)object.Get())->QueueIsochronous(data, dataLength,
4591bad4a4eSMichael Lotz 		packetDesc, packetCount, startingFrameNumber, flags, callback,
4601bad4a4eSMichael Lotz 		callbackCookie);
4615b0ec61fSMichael Lotz }
4625b0ec61fSMichael Lotz 
4635b0ec61fSMichael Lotz 
4645b0ec61fSMichael Lotz status_t
set_pipe_policy(usb_pipe pipe,uint8 maxQueuedPackets,uint16 maxBufferDurationMS,uint16 sampleSize)4655b0ec61fSMichael Lotz set_pipe_policy(usb_pipe pipe, uint8 maxQueuedPackets,
4665b0ec61fSMichael Lotz 	uint16 maxBufferDurationMS, uint16 sampleSize)
4675b0ec61fSMichael Lotz {
468d8b4cfc9SRene Gollent 	TRACE_MODULE("set_pipe_policy(%" B_PRId32 ", %d, %d, %d)\n", pipe,
469d8b4cfc9SRene Gollent 		maxQueuedPackets, maxBufferDurationMS, sampleSize);
470*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(pipe), true);
4715ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_ISO_PIPE) == 0)
47217f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
4735b0ec61fSMichael Lotz 
4745ee91867SAugustin Cavalier 	return ((IsochronousPipe *)object.IsSet())->SetPipePolicy(maxQueuedPackets,
47500f6fab9SMichael Lotz 		maxBufferDurationMS, sampleSize);
4765b0ec61fSMichael Lotz }
4775b0ec61fSMichael Lotz 
4785b0ec61fSMichael Lotz 
4795b0ec61fSMichael Lotz status_t
cancel_queued_transfers(usb_pipe pipe)4805b0ec61fSMichael Lotz cancel_queued_transfers(usb_pipe pipe)
481b8c6a851SMichael Lotz {
482d8b4cfc9SRene Gollent 	TRACE_MODULE("cancel_queued_transfers(%" B_PRId32 ")\n", pipe);
483*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(pipe), true);
4845ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_PIPE) == 0)
48517f83b21SMichael Lotz 		return B_DEV_INVALID_PIPE;
4865b0ec61fSMichael Lotz 
4875ee91867SAugustin Cavalier 	return ((Pipe *)object.Get())->CancelQueuedTransfers(false);
488b8c6a851SMichael Lotz }
489b8c6a851SMichael Lotz 
490b8c6a851SMichael Lotz 
491b8c6a851SMichael Lotz status_t
cancel_queued_requests(usb_device dev)49276ddb69aSJérôme Duval cancel_queued_requests(usb_device dev)
49376ddb69aSJérôme Duval {
49476ddb69aSJérôme Duval 	TRACE_MODULE("cancel_queued_requests(%" B_PRId32 ")\n", dev);
495*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(dev), true);
49676ddb69aSJérôme Duval 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
49776ddb69aSJérôme Duval 		return B_DEV_INVALID_PIPE;
49876ddb69aSJérôme Duval 	 Device *device = (Device *)object.Get();
49976ddb69aSJérôme Duval 
50076ddb69aSJérôme Duval 	 return device->DefaultPipe()->CancelQueuedTransfers(false);
50176ddb69aSJérôme Duval }
50276ddb69aSJérôme Duval 
50376ddb69aSJérôme Duval 
50476ddb69aSJérôme Duval status_t
usb_ioctl(uint32 opcode,void * buffer,size_t bufferSize)505b8c6a851SMichael Lotz usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize)
506b8c6a851SMichael Lotz {
507d8b4cfc9SRene Gollent 	TRACE_MODULE("usb_ioctl(%" B_PRIu32 ", %p, %" B_PRIuSIZE ")\n", opcode,
508d8b4cfc9SRene Gollent 		buffer, bufferSize);
50964f3c065SMichael Lotz 
51064f3c065SMichael Lotz 	switch (opcode) {
51164f3c065SMichael Lotz 		case 'DNAM': {
512*f7325a93SAugustin Cavalier 			BReference<Object> object(gUSBStack->GetObject(*(usb_id *)buffer), true);
5135ee91867SAugustin Cavalier 			if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
5145b0ec61fSMichael Lotz 				return B_BAD_VALUE;
5155ee91867SAugustin Cavalier 			Device *device = (Device *)object.Get();
5165b0ec61fSMichael Lotz 
51764f3c065SMichael Lotz 			uint32 index = 0;
518dd249016SAugustin Cavalier 			return device->BuildDeviceName((char *)buffer, &index,
5195b0ec61fSMichael Lotz 				bufferSize, NULL);
52064f3c065SMichael Lotz 		}
52164f3c065SMichael Lotz 	}
52264f3c065SMichael Lotz 
52364f3c065SMichael Lotz 	return B_DEV_INVALID_IOCTL;
524b8c6a851SMichael Lotz }
525b8c6a851SMichael Lotz 
526b8c6a851SMichael Lotz 
5277e1490e0SMichael Lotz status_t
get_nth_roothub(uint32 index,usb_device * rootHub)5287e1490e0SMichael Lotz get_nth_roothub(uint32 index, usb_device *rootHub)
5297e1490e0SMichael Lotz {
5307e1490e0SMichael Lotz 	if (!rootHub)
5317e1490e0SMichael Lotz 		return B_BAD_VALUE;
5327e1490e0SMichael Lotz 
5337e1490e0SMichael Lotz 	BusManager *busManager = gUSBStack->BusManagerAt(index);
5347e1490e0SMichael Lotz 	if (!busManager)
5357e1490e0SMichael Lotz 		return B_ENTRY_NOT_FOUND;
5367e1490e0SMichael Lotz 
5377e1490e0SMichael Lotz 	Hub *hub = busManager->GetRootHub();
5387e1490e0SMichael Lotz 	if (!hub)
5397e1490e0SMichael Lotz 		return B_NO_INIT;
5407e1490e0SMichael Lotz 
5417e1490e0SMichael Lotz 	*rootHub = hub->USBID();
5427e1490e0SMichael Lotz 	return B_OK;
5437e1490e0SMichael Lotz }
5447e1490e0SMichael Lotz 
5457e1490e0SMichael Lotz 
5467e1490e0SMichael Lotz status_t
get_nth_child(usb_device _hub,uint8 index,usb_device * childDevice)5477e1490e0SMichael Lotz get_nth_child(usb_device _hub, uint8 index, usb_device *childDevice)
5487e1490e0SMichael Lotz {
5497e1490e0SMichael Lotz 	if (!childDevice)
5507e1490e0SMichael Lotz 		return B_BAD_VALUE;
5517e1490e0SMichael Lotz 
552*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(_hub), true);
5535ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_HUB) == 0)
5547e1490e0SMichael Lotz 		return B_DEV_INVALID_PIPE;
5557e1490e0SMichael Lotz 
5565ee91867SAugustin Cavalier 	Hub *hub = (Hub *)object.Get();
5577e1490e0SMichael Lotz 	for (uint8 i = 0; i < 8; i++) {
5587e1490e0SMichael Lotz 		if (hub->ChildAt(i) == NULL)
5597e1490e0SMichael Lotz 			continue;
5607e1490e0SMichael Lotz 
5617e1490e0SMichael Lotz 		if (index-- > 0)
5627e1490e0SMichael Lotz 			continue;
5637e1490e0SMichael Lotz 
5647e1490e0SMichael Lotz 		*childDevice = hub->ChildAt(i)->USBID();
5657e1490e0SMichael Lotz 		return B_OK;
5667e1490e0SMichael Lotz 	}
5677e1490e0SMichael Lotz 
5687e1490e0SMichael Lotz 	return B_ENTRY_NOT_FOUND;
5697e1490e0SMichael Lotz }
5707e1490e0SMichael Lotz 
5717e1490e0SMichael Lotz 
5727e1490e0SMichael Lotz status_t
get_device_parent(usb_device _device,usb_device * parentHub,uint8 * portIndex)5737e1490e0SMichael Lotz get_device_parent(usb_device _device, usb_device *parentHub, uint8 *portIndex)
5747e1490e0SMichael Lotz {
5757e1490e0SMichael Lotz 	if (!parentHub || !portIndex)
5767e1490e0SMichael Lotz 		return B_BAD_VALUE;
5777e1490e0SMichael Lotz 
578*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(_device), true);
5795ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_DEVICE) == 0)
5807e1490e0SMichael Lotz 		return B_DEV_INVALID_PIPE;
5817e1490e0SMichael Lotz 
5827e1490e0SMichael Lotz 	Object *parent = object->Parent();
5837e1490e0SMichael Lotz 	if (!parent || (parent->Type() & USB_OBJECT_HUB) == 0)
5847e1490e0SMichael Lotz 		return B_ENTRY_NOT_FOUND;
5857e1490e0SMichael Lotz 
5867e1490e0SMichael Lotz 	Hub *hub = (Hub *)parent;
5877e1490e0SMichael Lotz 	for (uint8 i = 0; i < 8; i++) {
5885ee91867SAugustin Cavalier 		if (hub->ChildAt(i) == object.Get()) {
5897e1490e0SMichael Lotz 			*portIndex = i;
5907e1490e0SMichael Lotz 			*parentHub = hub->USBID();
5917e1490e0SMichael Lotz 			return B_OK;
5927e1490e0SMichael Lotz 		}
5937e1490e0SMichael Lotz 	}
5947e1490e0SMichael Lotz 
5957e1490e0SMichael Lotz 	return B_ERROR;
5967e1490e0SMichael Lotz }
5977e1490e0SMichael Lotz 
5987e1490e0SMichael Lotz 
5997e1490e0SMichael Lotz status_t
reset_port(usb_device _hub,uint8 portIndex)6007e1490e0SMichael Lotz reset_port(usb_device _hub, uint8 portIndex)
6017e1490e0SMichael Lotz {
602*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(_hub), true);
6035ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_HUB) == 0)
6047e1490e0SMichael Lotz 		return B_DEV_INVALID_PIPE;
6057e1490e0SMichael Lotz 
6065ee91867SAugustin Cavalier 	Hub *hub = (Hub *)object.Get();
6077e1490e0SMichael Lotz 	return hub->ResetPort(portIndex);
6087e1490e0SMichael Lotz }
6097e1490e0SMichael Lotz 
6107e1490e0SMichael Lotz 
6117e1490e0SMichael Lotz status_t
disable_port(usb_device _hub,uint8 portIndex)6127e1490e0SMichael Lotz disable_port(usb_device _hub, uint8 portIndex)
6137e1490e0SMichael Lotz {
614*f7325a93SAugustin Cavalier 	BReference<Object> object(gUSBStack->GetObject(_hub), true);
6155ee91867SAugustin Cavalier 	if (!object.IsSet() || (object->Type() & USB_OBJECT_HUB) == 0)
6167e1490e0SMichael Lotz 		return B_DEV_INVALID_PIPE;
6177e1490e0SMichael Lotz 
6185ee91867SAugustin Cavalier 	Hub *hub = (Hub *)object.Get();
6197e1490e0SMichael Lotz 	return hub->DisablePort(portIndex);
6207e1490e0SMichael Lotz }
6217e1490e0SMichael Lotz 
6227e1490e0SMichael Lotz 
62396da8285SMichael Lotz /*
6245b0ec61fSMichael Lotz 	This module exports the USB API v3
62596da8285SMichael Lotz */
6265b0ec61fSMichael Lotz struct usb_module_info gModuleInfoV3 = {
6271501c2bfSNiels Sascha Reedijk 	// First the bus_manager_info:
6281501c2bfSNiels Sascha Reedijk 	{
6291501c2bfSNiels Sascha Reedijk 		{
63055a46882SAugustin Cavalier 			"bus_managers/usb/v3.1",
6311501c2bfSNiels Sascha Reedijk 			B_KEEP_LOADED,				// Keep loaded, even if no driver requires it
6321501c2bfSNiels Sascha Reedijk 			bus_std_ops
6331501c2bfSNiels Sascha Reedijk 		},
6341501c2bfSNiels Sascha Reedijk 		NULL							// the rescan function
6351501c2bfSNiels Sascha Reedijk 	},
63696da8285SMichael Lotz 
637b8c6a851SMichael Lotz 	register_driver,					// register_driver
638b8c6a851SMichael Lotz 	install_notify,						// install_notify
639b8c6a851SMichael Lotz 	uninstall_notify,					// uninstall_notify
640b8c6a851SMichael Lotz 	get_device_descriptor,				// get_device_descriptor
641b8c6a851SMichael Lotz 	get_nth_configuration,				// get_nth_configuration
642b8c6a851SMichael Lotz 	get_configuration,					// get_configuration
643b8c6a851SMichael Lotz 	set_configuration,					// set_configuration
644b8c6a851SMichael Lotz 	set_alt_interface,					// set_alt_interface
645b8c6a851SMichael Lotz 	set_feature,						// set_feature
646b8c6a851SMichael Lotz 	clear_feature, 						// clear_feature
647b8c6a851SMichael Lotz 	get_status, 						// get_status
648b8c6a851SMichael Lotz 	get_descriptor,						// get_descriptor
649b8c6a851SMichael Lotz 	send_request,						// send_request
650b8c6a851SMichael Lotz 	queue_interrupt,					// queue_interrupt
651b8c6a851SMichael Lotz 	queue_bulk,							// queue_bulk
6525b0ec61fSMichael Lotz 	queue_bulk_v,						// queue_bulk_v
65355a46882SAugustin Cavalier 	queue_bulk_v_physical,				// queue_bulk_v_physical
654b8c6a851SMichael Lotz 	queue_isochronous,					// queue_isochronous
655b8c6a851SMichael Lotz 	queue_request,						// queue_request
656b8c6a851SMichael Lotz 	set_pipe_policy,					// set_pipe_policy
657b8c6a851SMichael Lotz 	cancel_queued_transfers,			// cancel_queued_transfers
65855a46882SAugustin Cavalier 	cancel_queued_requests,				// cancel_queued_requests
6597e1490e0SMichael Lotz 	usb_ioctl,							// usb_ioctl
6607e1490e0SMichael Lotz 	get_nth_roothub,					// get_nth_roothub
6617e1490e0SMichael Lotz 	get_nth_child,						// get_nth_child
6627e1490e0SMichael Lotz 	get_device_parent,					// get_device_parent
6637e1490e0SMichael Lotz 	reset_port,							// reset_port
66476ddb69aSJérôme Duval 	disable_port,						// disable_port
6651501c2bfSNiels Sascha Reedijk };
6661501c2bfSNiels Sascha Reedijk 
66796da8285SMichael Lotz 
6685b0ec61fSMichael Lotz //
6695b0ec61fSMichael Lotz // #pragma mark -
6705b0ec61fSMichael Lotz //
6715b0ec61fSMichael Lotz 
6725b0ec61fSMichael Lotz 
6735b0ec61fSMichael Lotz const usb_device_descriptor *
get_device_descriptor_v2(const void * device)6745b0ec61fSMichael Lotz get_device_descriptor_v2(const void *device)
6755b0ec61fSMichael Lotz {
676d8b4cfc9SRene Gollent 	return get_device_descriptor((usb_id)(ssize_t)device);
6775b0ec61fSMichael Lotz }
6785b0ec61fSMichael Lotz 
6795b0ec61fSMichael Lotz 
6805b0ec61fSMichael Lotz const usb_configuration_info *
get_nth_configuration_v2(const void * device,uint index)6815b0ec61fSMichael Lotz get_nth_configuration_v2(const void *device, uint index)
6825b0ec61fSMichael Lotz {
683d8b4cfc9SRene Gollent 	return get_nth_configuration((usb_id)(ssize_t)device, index);
6845b0ec61fSMichael Lotz }
6855b0ec61fSMichael Lotz 
6865b0ec61fSMichael Lotz 
6875b0ec61fSMichael Lotz const usb_configuration_info *
get_configuration_v2(const void * device)6885b0ec61fSMichael Lotz get_configuration_v2(const void *device)
6895b0ec61fSMichael Lotz {
690d8b4cfc9SRene Gollent 	return get_configuration((usb_id)(ssize_t)device);
6915b0ec61fSMichael Lotz }
6925b0ec61fSMichael Lotz 
6935b0ec61fSMichael Lotz 
6945b0ec61fSMichael Lotz status_t
set_configuration_v2(const void * device,const usb_configuration_info * configuration)6955b0ec61fSMichael Lotz set_configuration_v2(const void *device,
6965b0ec61fSMichael Lotz 	const usb_configuration_info *configuration)
6975b0ec61fSMichael Lotz {
698d8b4cfc9SRene Gollent 	return set_configuration((usb_id)(ssize_t)device, configuration);
6995b0ec61fSMichael Lotz }
7005b0ec61fSMichael Lotz 
7015b0ec61fSMichael Lotz 
7025b0ec61fSMichael Lotz status_t
set_alt_interface_v2(const void * device,const usb_interface_info * interface)7035b0ec61fSMichael Lotz set_alt_interface_v2(const void *device, const usb_interface_info *interface)
7045b0ec61fSMichael Lotz {
705d8b4cfc9SRene Gollent 	return set_alt_interface((usb_id)(ssize_t)device, interface);
7065b0ec61fSMichael Lotz }
7075b0ec61fSMichael Lotz 
7085b0ec61fSMichael Lotz 
7095b0ec61fSMichael Lotz status_t
set_feature_v2(const void * object,uint16 selector)7105b0ec61fSMichael Lotz set_feature_v2(const void *object, uint16 selector)
7115b0ec61fSMichael Lotz {
712d8b4cfc9SRene Gollent 	return set_feature((usb_id)(ssize_t)object, selector);
7135b0ec61fSMichael Lotz }
7145b0ec61fSMichael Lotz 
7155b0ec61fSMichael Lotz 
7165b0ec61fSMichael Lotz status_t
clear_feature_v2(const void * object,uint16 selector)7175b0ec61fSMichael Lotz clear_feature_v2(const void *object, uint16 selector)
7185b0ec61fSMichael Lotz {
719d8b4cfc9SRene Gollent 	return clear_feature((usb_id)(ssize_t)object, selector);
7205b0ec61fSMichael Lotz }
7215b0ec61fSMichael Lotz 
7225b0ec61fSMichael Lotz 
7235b0ec61fSMichael Lotz status_t
get_status_v2(const void * object,uint16 * status)7245b0ec61fSMichael Lotz get_status_v2(const void *object, uint16 *status)
7255b0ec61fSMichael Lotz {
726d8b4cfc9SRene Gollent 	return get_status((usb_id)(ssize_t)object, status);
7275b0ec61fSMichael Lotz }
7285b0ec61fSMichael Lotz 
7295b0ec61fSMichael Lotz 
7305b0ec61fSMichael Lotz status_t
get_descriptor_v2(const void * device,uint8 type,uint8 index,uint16 languageID,void * data,size_t dataLength,size_t * actualLength)7315b0ec61fSMichael Lotz get_descriptor_v2(const void *device, uint8 type, uint8 index,
7325b0ec61fSMichael Lotz 	uint16 languageID, void *data, size_t dataLength, size_t *actualLength)
7335b0ec61fSMichael Lotz {
734d8b4cfc9SRene Gollent 	return get_descriptor((usb_id)(ssize_t)device, type, index, languageID, data,
7355b0ec61fSMichael Lotz 		dataLength, actualLength);
7365b0ec61fSMichael Lotz }
7375b0ec61fSMichael Lotz 
7385b0ec61fSMichael Lotz 
7395b0ec61fSMichael Lotz status_t
send_request_v2(const void * device,uint8 requestType,uint8 request,uint16 value,uint16 index,uint16 length,void * data,size_t,size_t * actualLength)7405b0ec61fSMichael Lotz send_request_v2(const void *device, uint8 requestType, uint8 request,
7415b0ec61fSMichael Lotz 	uint16 value, uint16 index, uint16 length, void *data,
7425b0ec61fSMichael Lotz 	size_t /*dataLength*/, size_t *actualLength)
7435b0ec61fSMichael Lotz {
744d8b4cfc9SRene Gollent 	return send_request((usb_id)(ssize_t)device, requestType, request, value, index,
7455b0ec61fSMichael Lotz 		length, data, actualLength);
7465b0ec61fSMichael Lotz }
7475b0ec61fSMichael Lotz 
7485b0ec61fSMichael Lotz 
7495b0ec61fSMichael Lotz status_t
queue_request_v2(const void * device,uint8 requestType,uint8 request,uint16 value,uint16 index,uint16 length,void * data,size_t,usb_callback_func callback,void * callbackCookie)7505b0ec61fSMichael Lotz queue_request_v2(const void *device, uint8 requestType, uint8 request,
7515b0ec61fSMichael Lotz 	uint16 value, uint16 index, uint16 length, void *data,
7525b0ec61fSMichael Lotz 	size_t /*dataLength*/, usb_callback_func callback, void *callbackCookie)
7535b0ec61fSMichael Lotz {
754d8b4cfc9SRene Gollent 	return queue_request((usb_id)(ssize_t)device, requestType, request, value, index,
7555b0ec61fSMichael Lotz 		length, data, callback, callbackCookie);
7565b0ec61fSMichael Lotz }
7575b0ec61fSMichael Lotz 
7585b0ec61fSMichael Lotz 
7595b0ec61fSMichael Lotz status_t
queue_interrupt_v2(const void * pipe,void * data,size_t dataLength,usb_callback_func callback,void * callbackCookie)7605b0ec61fSMichael Lotz queue_interrupt_v2(const void *pipe, void *data, size_t dataLength,
7615b0ec61fSMichael Lotz 	usb_callback_func callback, void *callbackCookie)
7625b0ec61fSMichael Lotz {
763d8b4cfc9SRene Gollent 	return queue_interrupt((usb_id)(ssize_t)pipe, data, dataLength, callback,
7645b0ec61fSMichael Lotz 		callbackCookie);
7655b0ec61fSMichael Lotz }
7665b0ec61fSMichael Lotz 
7675b0ec61fSMichael Lotz 
7685b0ec61fSMichael Lotz status_t
queue_bulk_v2(const void * pipe,void * data,size_t dataLength,usb_callback_func callback,void * callbackCookie)7695b0ec61fSMichael Lotz queue_bulk_v2(const void *pipe, void *data, size_t dataLength,
7705b0ec61fSMichael Lotz 	usb_callback_func callback, void *callbackCookie)
7715b0ec61fSMichael Lotz {
772d8b4cfc9SRene Gollent 	return queue_bulk((usb_id)(ssize_t)pipe, data, dataLength, callback,
7735b0ec61fSMichael Lotz 		callbackCookie);
7745b0ec61fSMichael Lotz }
7755b0ec61fSMichael Lotz 
7765b0ec61fSMichael Lotz 
7775b0ec61fSMichael Lotz status_t
queue_isochronous_v2(const void * pipe,void * data,size_t dataLength,rlea * rleArray,uint16 bufferDurationMS,usb_callback_func callback,void * callbackCookie)7785b0ec61fSMichael Lotz queue_isochronous_v2(const void *pipe, void *data, size_t dataLength,
7795b0ec61fSMichael Lotz 	rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback,
7805b0ec61fSMichael Lotz 	void *callbackCookie)
7815b0ec61fSMichael Lotz {
7821bad4a4eSMichael Lotz 	// ToDo: convert rlea to usb_iso_packet_descriptor
7831bad4a4eSMichael Lotz 	// ToDo: use a flag to indicate that the callback shall produce a rlea
7841bad4a4eSMichael Lotz 	usb_iso_packet_descriptor *packetDesc = NULL;
785d8b4cfc9SRene Gollent 	return queue_isochronous((usb_id)(ssize_t)pipe, data, dataLength, packetDesc, 0,
7861bad4a4eSMichael Lotz 		NULL, 0, callback, callbackCookie);
7875b0ec61fSMichael Lotz }
7885b0ec61fSMichael Lotz 
7895b0ec61fSMichael Lotz 
7905b0ec61fSMichael Lotz status_t
set_pipe_policy_v2(const void * pipe,uint8 maxQueuedPackets,uint16 maxBufferDurationMS,uint16 sampleSize)7915b0ec61fSMichael Lotz set_pipe_policy_v2(const void *pipe, uint8 maxQueuedPackets,
7925b0ec61fSMichael Lotz 	uint16 maxBufferDurationMS, uint16 sampleSize)
7935b0ec61fSMichael Lotz {
794d8b4cfc9SRene Gollent 	return set_pipe_policy((usb_id)(ssize_t)pipe, maxQueuedPackets, maxBufferDurationMS,
7955b0ec61fSMichael Lotz 		sampleSize);
7965b0ec61fSMichael Lotz }
7975b0ec61fSMichael Lotz 
7985b0ec61fSMichael Lotz 
7995b0ec61fSMichael Lotz status_t
cancel_queued_transfers_v2(const void * pipe)8005b0ec61fSMichael Lotz cancel_queued_transfers_v2(const void *pipe)
8015b0ec61fSMichael Lotz {
802d8b4cfc9SRene Gollent 	return cancel_queued_transfers((usb_id)(ssize_t)pipe);
8035b0ec61fSMichael Lotz }
8045b0ec61fSMichael Lotz 
8055b0ec61fSMichael Lotz 
8065b0ec61fSMichael Lotz struct usb_module_info_v2 {
8075b0ec61fSMichael Lotz 	bus_manager_info				binfo;
8085b0ec61fSMichael Lotz 	status_t						(*register_driver)(const char *, const usb_support_descriptor *, size_t, const char *);
8095b0ec61fSMichael Lotz 	status_t						(*install_notify)(const char *, const usb_notify_hooks *);
8105b0ec61fSMichael Lotz 	status_t						(*uninstall_notify)(const char *);
8115b0ec61fSMichael Lotz 	const usb_device_descriptor		*(*get_device_descriptor)(const void *);
8125b0ec61fSMichael Lotz 	const usb_configuration_info	*(*get_nth_configuration)(const void *, uint);
8135b0ec61fSMichael Lotz 	const usb_configuration_info	*(*get_configuration)(const void *);
8145b0ec61fSMichael Lotz 	status_t						(*set_configuration)(const void *, const usb_configuration_info *);
8155b0ec61fSMichael Lotz 	status_t						(*set_alt_interface)(const void *, const usb_interface_info *);
8165b0ec61fSMichael Lotz 	status_t						(*set_feature)(const void *, uint16);
8175b0ec61fSMichael Lotz 	status_t						(*clear_feature)(const void *, uint16);
8185b0ec61fSMichael Lotz 	status_t						(*get_status)(const void *, uint16 *);
8195b0ec61fSMichael Lotz 	status_t						(*get_descriptor)(const void *, uint8, uint8, uint16, void *, size_t, size_t *);
8205b0ec61fSMichael Lotz 	status_t						(*send_request)(const void *, uint8, uint8, uint16, uint16, uint16, void *, size_t, size_t *);
8215b0ec61fSMichael Lotz 	status_t						(*queue_interrupt)(const void *, void *, size_t, usb_callback_func, void *);
8225b0ec61fSMichael Lotz 	status_t						(*queue_bulk)(const void *, void *, size_t, usb_callback_func, void *);
8235b0ec61fSMichael Lotz 	status_t						(*queue_isochronous)(const void *, void *, size_t, rlea *, uint16, usb_callback_func, void *);
8245b0ec61fSMichael Lotz 	status_t						(*queue_request)(const void *, uint8, uint8, uint16, uint16, uint16, void *, size_t, usb_callback_func, void *);
8255b0ec61fSMichael Lotz 	status_t						(*set_pipe_policy)(const void *, uint8, uint16, uint16);
8265b0ec61fSMichael Lotz 	status_t						(*cancel_queued_transfers)(const void *);
8275b0ec61fSMichael Lotz 	status_t						(*usb_ioctl)(uint32 opcode, void *,size_t);
8285b0ec61fSMichael Lotz };
8295b0ec61fSMichael Lotz 
8305b0ec61fSMichael Lotz 
8315b0ec61fSMichael Lotz /*
8325b0ec61fSMichael Lotz 	This module exports the USB API v2
8335b0ec61fSMichael Lotz */
8345b0ec61fSMichael Lotz struct usb_module_info_v2 gModuleInfoV2 = {
8355b0ec61fSMichael Lotz 	// First the bus_manager_info:
8365b0ec61fSMichael Lotz 	{
8375b0ec61fSMichael Lotz 		{
8385b0ec61fSMichael Lotz 			"bus_managers/usb/v2",
8395b0ec61fSMichael Lotz 			B_KEEP_LOADED,				// Keep loaded, even if no driver requires it
8405b0ec61fSMichael Lotz 			bus_std_ops
8415b0ec61fSMichael Lotz 		},
8425b0ec61fSMichael Lotz 		NULL							// the rescan function
8435b0ec61fSMichael Lotz 	},
8445b0ec61fSMichael Lotz 
8455b0ec61fSMichael Lotz 	register_driver,					// register_driver
8465b0ec61fSMichael Lotz 	install_notify,						// install_notify
8475b0ec61fSMichael Lotz 	uninstall_notify,					// uninstall_notify
8485b0ec61fSMichael Lotz 	get_device_descriptor_v2,			// get_device_descriptor
8495b0ec61fSMichael Lotz 	get_nth_configuration_v2,			// get_nth_configuration
8505b0ec61fSMichael Lotz 	get_configuration_v2,				// get_configuration
8515b0ec61fSMichael Lotz 	set_configuration_v2,				// set_configuration
8525b0ec61fSMichael Lotz 	set_alt_interface_v2,				// set_alt_interface
8535b0ec61fSMichael Lotz 	set_feature_v2,						// set_feature
8545b0ec61fSMichael Lotz 	clear_feature_v2,					// clear_feature
8555b0ec61fSMichael Lotz 	get_status_v2, 						// get_status
8565b0ec61fSMichael Lotz 	get_descriptor_v2,					// get_descriptor
8575b0ec61fSMichael Lotz 	send_request_v2,					// send_request
8585b0ec61fSMichael Lotz 	queue_interrupt_v2,					// queue_interrupt
8595b0ec61fSMichael Lotz 	queue_bulk_v2,						// queue_bulk
8605b0ec61fSMichael Lotz 	queue_isochronous_v2,				// queue_isochronous
8615b0ec61fSMichael Lotz 	queue_request_v2,					// queue_request
8625b0ec61fSMichael Lotz 	set_pipe_policy_v2,					// set_pipe_policy
8635b0ec61fSMichael Lotz 	cancel_queued_transfers_v2,			// cancel_queued_transfers
8645b0ec61fSMichael Lotz 	usb_ioctl							// usb_ioctl
8655b0ec61fSMichael Lotz };
8665b0ec61fSMichael Lotz 
8675b0ec61fSMichael Lotz 
8685b0ec61fSMichael Lotz //
8695b0ec61fSMichael Lotz // #pragma mark -
8705b0ec61fSMichael Lotz //
8715b0ec61fSMichael Lotz 
8725b0ec61fSMichael Lotz 
8731eebcfa0SJérôme Duval status_t
usb_added_device(device_node * parent)8741eebcfa0SJérôme Duval usb_added_device(device_node *parent)
8751eebcfa0SJérôme Duval {
8761eebcfa0SJérôme Duval 	return B_OK;
8771eebcfa0SJérôme Duval }
8781eebcfa0SJérôme Duval 
8791eebcfa0SJérôme Duval 
8801eebcfa0SJérôme Duval status_t
usb_get_stack(void ** stack)8811eebcfa0SJérôme Duval usb_get_stack(void** stack)
8821eebcfa0SJérôme Duval {
8831eebcfa0SJérôme Duval 	*stack = gUSBStack;
8841eebcfa0SJérôme Duval 	return B_OK;
8851eebcfa0SJérôme Duval }
8861eebcfa0SJérôme Duval 
8871eebcfa0SJérôme Duval 
8881eebcfa0SJérôme Duval usb_for_controller_interface gForControllerModule = {
8891eebcfa0SJérôme Duval 	{
8901eebcfa0SJérôme Duval 		{
8911eebcfa0SJérôme Duval 			USB_FOR_CONTROLLER_MODULE_NAME,
8921eebcfa0SJérôme Duval 			B_KEEP_LOADED,
8931eebcfa0SJérôme Duval 			&bus_std_ops
8941eebcfa0SJérôme Duval 		},
8951eebcfa0SJérôme Duval 
8961eebcfa0SJérôme Duval 		NULL, // supported devices
8971eebcfa0SJérôme Duval 		usb_added_device,
8981eebcfa0SJérôme Duval 		NULL,
8991eebcfa0SJérôme Duval 		NULL,
9001eebcfa0SJérôme Duval 		NULL
9011eebcfa0SJérôme Duval 	},
9021eebcfa0SJérôme Duval 
9031eebcfa0SJérôme Duval 	usb_get_stack,
9041eebcfa0SJérôme Duval };
9051eebcfa0SJérôme Duval 
9061eebcfa0SJérôme Duval 
907e6ce95c5SJérôme Duval static status_t
device_std_ops(int32 op,...)908e6ce95c5SJérôme Duval device_std_ops(int32 op, ...)
909e6ce95c5SJérôme Duval {
910e6ce95c5SJérôme Duval 	switch (op) {
911e6ce95c5SJérôme Duval 		case B_MODULE_INIT:
912e6ce95c5SJérôme Duval 		{
913e6ce95c5SJérôme Duval 			// Link to USB bus.
914e6ce95c5SJérôme Duval 			// USB device driver must have USB bus loaded, but it calls its
915e6ce95c5SJérôme Duval 			// functions directly instead via official interface, so this
916e6ce95c5SJérôme Duval 			// pointer is never read.
917e6ce95c5SJérôme Duval 			module_info *dummy;
91855a46882SAugustin Cavalier 			return get_module(B_USB_MODULE_NAME, &dummy);
919e6ce95c5SJérôme Duval 		}
920e6ce95c5SJérôme Duval 		case B_MODULE_UNINIT:
92155a46882SAugustin Cavalier 			return put_module(B_USB_MODULE_NAME);
922e6ce95c5SJérôme Duval 
923e6ce95c5SJérôme Duval 		default:
924e6ce95c5SJérôme Duval 			return B_ERROR;
925e6ce95c5SJérôme Duval 	}
926e6ce95c5SJérôme Duval }
927e6ce95c5SJérôme Duval 
928e6ce95c5SJérôme Duval 
929e6ce95c5SJérôme Duval usb_device_interface gUSBDeviceModule = {
930e6ce95c5SJérôme Duval 	{
931e6ce95c5SJérôme Duval 		{
932e6ce95c5SJérôme Duval 			USB_DEVICE_MODULE_NAME,
933e6ce95c5SJérôme Duval 			0,
934e6ce95c5SJérôme Duval 			device_std_ops
935e6ce95c5SJérôme Duval 		},
936e6ce95c5SJérôme Duval 
937e6ce95c5SJérôme Duval 		NULL,	// supported devices
938e6ce95c5SJérôme Duval 		NULL,	// register node
939e6ce95c5SJérôme Duval 	NULL, //usb_init_device,
940e6ce95c5SJérôme Duval 	NULL, //	(void (*)(void *)) usb_uninit_device,
941e6ce95c5SJérôme Duval 		NULL,	// register child devices
942e6ce95c5SJérôme Duval 		NULL,	// rescan
943e6ce95c5SJérôme Duval 	NULL//	(void (*)(void *)) usb_device_removed
944e6ce95c5SJérôme Duval 	},
945e6ce95c5SJérôme Duval };
946e6ce95c5SJérôme Duval 
947e6ce95c5SJérôme Duval 
948e6ce95c5SJérôme Duval module_dependency module_dependencies[] = {
949e6ce95c5SJérôme Duval 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
950e6ce95c5SJérôme Duval 	{}
951e6ce95c5SJérôme Duval };
952e6ce95c5SJérôme Duval 
953e6ce95c5SJérôme Duval 
9541501c2bfSNiels Sascha Reedijk module_info *modules[] = {
9555b0ec61fSMichael Lotz 	(module_info *)&gModuleInfoV2,
9565b0ec61fSMichael Lotz 	(module_info *)&gModuleInfoV3,
9571eebcfa0SJérôme Duval 	(module_info *)&gForControllerModule,
958e6ce95c5SJérôme Duval 	(module_info *)&gUSBDeviceModule,
9591501c2bfSNiels Sascha Reedijk 	NULL
9601501c2bfSNiels Sascha Reedijk };
961