xref: /haiku/src/add-ons/kernel/bus_managers/usb/usb.cpp (revision 64f3c0650321a0951e337baccaf6db98baa5489c)
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:
696da8285SMichael Lotz  *		Niels S. Reedijk
796da8285SMichael Lotz  */
81501c2bfSNiels Sascha Reedijk 
91501c2bfSNiels Sascha Reedijk #include <USB.h>
101501c2bfSNiels Sascha Reedijk #include <util/kernel_cpp.h>
111501c2bfSNiels Sascha Reedijk #include "usb_p.h"
121501c2bfSNiels Sascha Reedijk 
1396da8285SMichael Lotz 
1496da8285SMichael Lotz #define TRACE_USB
1596da8285SMichael Lotz #ifdef TRACE_USB
1696da8285SMichael Lotz #define TRACE(x)	dprintf x
171501c2bfSNiels Sascha Reedijk #else
1896da8285SMichael Lotz #define TRACE(x)	/* nothing */
191501c2bfSNiels Sascha Reedijk #endif
201501c2bfSNiels Sascha Reedijk 
211501c2bfSNiels Sascha Reedijk 
22b8c6a851SMichael Lotz Stack *gUSBStack = NULL;
23b8c6a851SMichael Lotz 
24b8c6a851SMichael Lotz 
251501c2bfSNiels Sascha Reedijk static int32
261501c2bfSNiels Sascha Reedijk bus_std_ops(int32 op, ...)
271501c2bfSNiels Sascha Reedijk {
281501c2bfSNiels Sascha Reedijk 	switch (op) {
2996da8285SMichael Lotz 		case B_MODULE_INIT: {
3096da8285SMichael Lotz #ifdef TRACE_USB
311a2e81b5SNiels Sascha Reedijk 			set_dprintf_enabled(true);
321a2e81b5SNiels Sascha Reedijk 			load_driver_symbols("usb");
331a2e81b5SNiels Sascha Reedijk #endif
34b8c6a851SMichael Lotz 			TRACE(("usb_module: init\n"));
3596da8285SMichael Lotz 
36b8c6a851SMichael Lotz 			Stack *stack = new(std::nothrow) Stack();
37b8c6a851SMichael Lotz 			if (!stack)
38b8c6a851SMichael Lotz 				return B_NO_MEMORY;
39b8c6a851SMichael Lotz 
4096da8285SMichael Lotz 			if (stack->InitCheck() != B_OK) {
411a2e81b5SNiels Sascha Reedijk 				delete stack;
421501c2bfSNiels Sascha Reedijk 				return ENODEV;
431501c2bfSNiels Sascha Reedijk 			}
4496da8285SMichael Lotz 
45b8c6a851SMichael Lotz 			gUSBStack = stack;
461501c2bfSNiels Sascha Reedijk 			break;
4796da8285SMichael Lotz 		}
4896da8285SMichael Lotz 
491501c2bfSNiels Sascha Reedijk 		case B_MODULE_UNINIT:
50b8c6a851SMichael Lotz 			TRACE(("usb_module: bus module: uninit\n"));
51b8c6a851SMichael Lotz 			delete gUSBStack;
52b8c6a851SMichael Lotz 			gUSBStack = NULL;
531501c2bfSNiels Sascha Reedijk 			break;
5496da8285SMichael Lotz 
551501c2bfSNiels Sascha Reedijk 		default:
561501c2bfSNiels Sascha Reedijk 			return EINVAL;
571501c2bfSNiels Sascha Reedijk 	}
5896da8285SMichael Lotz 
591501c2bfSNiels Sascha Reedijk 	return B_OK;
601501c2bfSNiels Sascha Reedijk }
611501c2bfSNiels Sascha Reedijk 
621501c2bfSNiels Sascha Reedijk 
63b8c6a851SMichael Lotz status_t
64b8c6a851SMichael Lotz register_driver(const char *driverName,
65b8c6a851SMichael Lotz 	const usb_support_descriptor *descriptors,
66b8c6a851SMichael Lotz 	size_t count, const char *optionalRepublishDriverName)
67b8c6a851SMichael Lotz {
68b8c6a851SMichael Lotz 	return gUSBStack->RegisterDriver(driverName, descriptors, count,
69b8c6a851SMichael Lotz 		optionalRepublishDriverName);
70b8c6a851SMichael Lotz }
71b8c6a851SMichael Lotz 
72b8c6a851SMichael Lotz 
73b8c6a851SMichael Lotz status_t
74b8c6a851SMichael Lotz install_notify(const char *driverName, const usb_notify_hooks *hooks)
75b8c6a851SMichael Lotz {
76b8c6a851SMichael Lotz 	return gUSBStack->InstallNotify(driverName, hooks);
77b8c6a851SMichael Lotz }
78b8c6a851SMichael Lotz 
79b8c6a851SMichael Lotz 
80b8c6a851SMichael Lotz status_t
81b8c6a851SMichael Lotz uninstall_notify(const char *driverName)
82b8c6a851SMichael Lotz {
83b8c6a851SMichael Lotz 	return gUSBStack->UninstallNotify(driverName);
84b8c6a851SMichael Lotz }
85b8c6a851SMichael Lotz 
86b8c6a851SMichael Lotz 
87b8c6a851SMichael Lotz const usb_device_descriptor *
88b8c6a851SMichael Lotz get_device_descriptor(const usb_device *device)
89b8c6a851SMichael Lotz {
90f1020a6cSMichael Lotz 	TRACE(("usb_module: get_device_descriptor(0x%08x)\n", device));
91b8c6a851SMichael Lotz 	if (!device)
92b8c6a851SMichael Lotz 		return NULL;
93b8c6a851SMichael Lotz 
94b8c6a851SMichael Lotz 	return ((const Device *)device)->DeviceDescriptor();
95b8c6a851SMichael Lotz }
96b8c6a851SMichael Lotz 
97b8c6a851SMichael Lotz 
98b8c6a851SMichael Lotz const usb_configuration_info *
99b8c6a851SMichael Lotz get_nth_configuration(const usb_device *device, uint index)
100b8c6a851SMichael Lotz {
101f1020a6cSMichael Lotz 	TRACE(("usb_module: get_nth_configuration(0x%08x, %d)\n", device, index));
102b8c6a851SMichael Lotz 	if (!device)
103b8c6a851SMichael Lotz 		return NULL;
104b8c6a851SMichael Lotz 
105b8c6a851SMichael Lotz 	return ((const Device *)device)->ConfigurationAt((int32)index);
106b8c6a851SMichael Lotz }
107b8c6a851SMichael Lotz 
108b8c6a851SMichael Lotz 
109b8c6a851SMichael Lotz 
110b8c6a851SMichael Lotz const usb_configuration_info *
111b8c6a851SMichael Lotz get_configuration(const usb_device *device)
112b8c6a851SMichael Lotz {
113f1020a6cSMichael Lotz 	TRACE(("usb_module: get_configuration(0x%08x)\n", device));
114b8c6a851SMichael Lotz 	if (!device)
115b8c6a851SMichael Lotz 		return NULL;
116b8c6a851SMichael Lotz 
117b8c6a851SMichael Lotz 	return ((const Device *)device)->Configuration();
118b8c6a851SMichael Lotz }
119b8c6a851SMichael Lotz 
120b8c6a851SMichael Lotz 
121b8c6a851SMichael Lotz status_t
122b8c6a851SMichael Lotz set_configuration(const usb_device *device,
123b8c6a851SMichael Lotz 	const usb_configuration_info *configuration)
124b8c6a851SMichael Lotz {
125f1020a6cSMichael Lotz 	TRACE(("usb_module: set_configuration(0x%08x, 0x%08x)\n", device, configuration));
126b8c6a851SMichael Lotz 	if (!device)
127b8c6a851SMichael Lotz 		return B_BAD_VALUE;
128b8c6a851SMichael Lotz 
129b8c6a851SMichael Lotz 	return ((Device *)device)->SetConfiguration(configuration);
130b8c6a851SMichael Lotz }
131b8c6a851SMichael Lotz 
132b8c6a851SMichael Lotz 
133b8c6a851SMichael Lotz status_t
134b8c6a851SMichael Lotz set_alt_interface(const usb_device *device,
135b8c6a851SMichael Lotz 	const usb_interface_info *interface)
136b8c6a851SMichael Lotz {
137f1020a6cSMichael Lotz 	TRACE(("usb_module: set_alt_interface(0x%08x, 0x%08x)\n", device, interface));
138b8c6a851SMichael Lotz 	return B_ERROR;
139b8c6a851SMichael Lotz }
140b8c6a851SMichael Lotz 
141b8c6a851SMichael Lotz 
142b8c6a851SMichael Lotz status_t
143b8c6a851SMichael Lotz set_feature(const void *object, uint16 selector)
144b8c6a851SMichael Lotz {
145f1020a6cSMichael Lotz 	TRACE(("usb_module: set_feature(0x%08x, %d)\n", object, selector));
146b8c6a851SMichael Lotz 	if (!object)
147b8c6a851SMichael Lotz 		return B_BAD_VALUE;
148b8c6a851SMichael Lotz 
14949617128SMichael Lotz 	return ((Pipe *)object)->SetFeature(selector);
150b8c6a851SMichael Lotz }
151b8c6a851SMichael Lotz 
152b8c6a851SMichael Lotz 
153b8c6a851SMichael Lotz status_t
154b8c6a851SMichael Lotz clear_feature(const void *object, uint16 selector)
155b8c6a851SMichael Lotz {
156f1020a6cSMichael Lotz 	TRACE(("usb_module: clear_feature(0x%08x, %d)\n", object, selector));
157b8c6a851SMichael Lotz 	if (!object)
158b8c6a851SMichael Lotz 		return B_BAD_VALUE;
159b8c6a851SMichael Lotz 
16049617128SMichael Lotz 	return ((Pipe *)object)->ClearFeature(selector);
161b8c6a851SMichael Lotz }
162b8c6a851SMichael Lotz 
163b8c6a851SMichael Lotz 
164b8c6a851SMichael Lotz status_t
165b8c6a851SMichael Lotz get_status(const void *object, uint16 *status)
166b8c6a851SMichael Lotz {
167f1020a6cSMichael Lotz 	TRACE(("usb_module: get_status(0x%08x, 0x%08x)\n", object, status));
168b8c6a851SMichael Lotz 	if (!object || !status)
169b8c6a851SMichael Lotz 		return B_BAD_VALUE;
170b8c6a851SMichael Lotz 
17149617128SMichael Lotz 	return ((Pipe *)object)->GetStatus(status);
172b8c6a851SMichael Lotz }
173b8c6a851SMichael Lotz 
174b8c6a851SMichael Lotz 
175b8c6a851SMichael Lotz status_t
176b8c6a851SMichael Lotz get_descriptor(const usb_device *device, uint8 type, uint8 index,
177b8c6a851SMichael Lotz 	uint16 languageID, void *data, size_t dataLength, size_t *actualLength)
178b8c6a851SMichael Lotz {
179f1020a6cSMichael Lotz 	TRACE(("usb_module: get_descriptor(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%08x, %d, 0x%08x)\n", device, type, index, languageID, data, dataLength, actualLength));
180b8c6a851SMichael Lotz 	if (!device || !data)
181b8c6a851SMichael Lotz 		return B_BAD_VALUE;
182b8c6a851SMichael Lotz 
183b8c6a851SMichael Lotz 	return ((Device *)device)->GetDescriptor(type, index, languageID,
184b8c6a851SMichael Lotz 		data, dataLength, actualLength);
185b8c6a851SMichael Lotz }
186b8c6a851SMichael Lotz 
187b8c6a851SMichael Lotz 
188b8c6a851SMichael Lotz status_t
189b8c6a851SMichael Lotz send_request(const usb_device *device, uint8 requestType, uint8 request,
190b8c6a851SMichael Lotz 	uint16 value, uint16 index, uint16 length, void *data, size_t dataLength,
191b8c6a851SMichael Lotz 	size_t *actualLength)
192b8c6a851SMichael Lotz {
193f1020a6cSMichael Lotz 	TRACE(("usb_module: send_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, %d, 0x%08x)\n", device, requestType, request, value, index, length, data, dataLength, actualLength));
194b8c6a851SMichael Lotz 	if (!device)
195b8c6a851SMichael Lotz 		return B_BAD_VALUE;
196b8c6a851SMichael Lotz 
197b8c6a851SMichael Lotz 	return ((Device *)device)->SendRequest(requestType, request, value, index,
198b8c6a851SMichael Lotz 		length, data, dataLength, actualLength);
199b8c6a851SMichael Lotz }
200b8c6a851SMichael Lotz 
201b8c6a851SMichael Lotz 
202b8c6a851SMichael Lotz status_t
203b8c6a851SMichael Lotz queue_request(const usb_device *device, uint8 requestType, uint8 request,
204b8c6a851SMichael Lotz 	uint16 value, uint16 index, uint16 length, void *data, size_t dataLength,
205b8c6a851SMichael Lotz 	usb_callback_func callback, void *callbackCookie)
206b8c6a851SMichael Lotz {
207f1020a6cSMichael Lotz 	TRACE(("usb_module: queue_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, %d, 0x%08x, 0x%08x)\n", device, requestType, request, value, index, length, data, dataLength, callback, callbackCookie));
208b8c6a851SMichael Lotz 	if (!device)
209b8c6a851SMichael Lotz 		return B_BAD_VALUE;
210b8c6a851SMichael Lotz 
211b8c6a851SMichael Lotz 	return ((Device *)device)->QueueRequest(requestType, request, value, index,
212b8c6a851SMichael Lotz 		length, data, dataLength, callback, callbackCookie);
213b8c6a851SMichael Lotz }
214b8c6a851SMichael Lotz 
215b8c6a851SMichael Lotz 
216b8c6a851SMichael Lotz status_t
217b8c6a851SMichael Lotz queue_interrupt(const usb_pipe *pipe, void *data, size_t dataLength,
218b8c6a851SMichael Lotz 	usb_callback_func callback, void *callbackCookie)
219b8c6a851SMichael Lotz {
220f1020a6cSMichael Lotz 	TRACE(("usb_module: queue_interrupt(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie));
221b8c6a851SMichael Lotz 	if (((Pipe *)pipe)->Type() != Pipe::Interrupt)
222b8c6a851SMichael Lotz 		return B_BAD_VALUE;
223b8c6a851SMichael Lotz 
224b8c6a851SMichael Lotz 	return ((InterruptPipe *)pipe)->QueueInterrupt(data, dataLength, callback,
225b8c6a851SMichael Lotz 		callbackCookie);
226b8c6a851SMichael Lotz }
227b8c6a851SMichael Lotz 
228b8c6a851SMichael Lotz 
229b8c6a851SMichael Lotz status_t
230b8c6a851SMichael Lotz queue_bulk(const usb_pipe *pipe, void *data, size_t dataLength,
231b8c6a851SMichael Lotz 	usb_callback_func callback, void *callbackCookie)
232b8c6a851SMichael Lotz {
233f1020a6cSMichael Lotz 	TRACE(("usb_module: queue_bulk(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie));
234b8c6a851SMichael Lotz 	if (((Pipe *)pipe)->Type() != Pipe::Bulk)
235b8c6a851SMichael Lotz 		return B_BAD_VALUE;
236b8c6a851SMichael Lotz 
237b8c6a851SMichael Lotz 	return ((BulkPipe *)pipe)->QueueBulk(data, dataLength, callback,
238b8c6a851SMichael Lotz 		callbackCookie);
239b8c6a851SMichael Lotz }
240b8c6a851SMichael Lotz 
241b8c6a851SMichael Lotz 
242b8c6a851SMichael Lotz status_t
243b8c6a851SMichael Lotz queue_isochronous(const usb_pipe *pipe, void *data, size_t dataLength,
244b8c6a851SMichael Lotz 	rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback,
245b8c6a851SMichael Lotz 	void *callbackCookie)
246b8c6a851SMichael Lotz {
247f1020a6cSMichael Lotz 	TRACE(("usb_module: queue_isochronous(0x%08x, 0x%08x, %d, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, rleArray, bufferDurationMS, callback, callbackCookie));
248b8c6a851SMichael Lotz 	if (((Pipe *)pipe)->Type() != Pipe::Isochronous)
249b8c6a851SMichael Lotz 		return B_BAD_VALUE;
250b8c6a851SMichael Lotz 
251b8c6a851SMichael Lotz 	return ((IsochronousPipe *)pipe)->QueueIsochronous(data, dataLength,
252b8c6a851SMichael Lotz 		rleArray, bufferDurationMS, callback, callbackCookie);
253b8c6a851SMichael Lotz }
254b8c6a851SMichael Lotz 
255b8c6a851SMichael Lotz 
256b8c6a851SMichael Lotz status_t
257b8c6a851SMichael Lotz set_pipe_policy(const usb_pipe *pipe, uint8 maxQueuedPackets,
258b8c6a851SMichael Lotz 	uint16 maxBufferDurationMS, uint16 sampleSize)
259b8c6a851SMichael Lotz {
260f1020a6cSMichael Lotz 	TRACE(("usb_module: set_pipe_policy(0x%08x, %d, %d, %d)\n", pipe, maxQueuedPackets, maxBufferDurationMS, sampleSize));
261b8c6a851SMichael Lotz 	return B_ERROR;
262b8c6a851SMichael Lotz }
263b8c6a851SMichael Lotz 
264b8c6a851SMichael Lotz 
265b8c6a851SMichael Lotz status_t
266b8c6a851SMichael Lotz cancel_queued_transfers(const usb_pipe *pipe)
267b8c6a851SMichael Lotz {
268f1020a6cSMichael Lotz 	TRACE(("usb_module: cancel_queued_transfers(0x%08x)\n", pipe));
269b8c6a851SMichael Lotz 	return ((Pipe *)pipe)->CancelQueuedTransfers();
270b8c6a851SMichael Lotz }
271b8c6a851SMichael Lotz 
272b8c6a851SMichael Lotz 
273b8c6a851SMichael Lotz status_t
274b8c6a851SMichael Lotz usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize)
275b8c6a851SMichael Lotz {
276f1020a6cSMichael Lotz 	TRACE(("usb_module: usb_ioctl(0x%08x, 0x%08x, %d)\n", opcode, buffer, bufferSize));
277*64f3c065SMichael Lotz 
278*64f3c065SMichael Lotz 	switch (opcode) {
279*64f3c065SMichael Lotz 		case 'DNAM': {
280*64f3c065SMichael Lotz 			uint32 index = 0;
281*64f3c065SMichael Lotz 			Device *device = *(Device **)buffer;
282*64f3c065SMichael Lotz 			return device->BuildDeviceName((char *)buffer, &index, bufferSize, NULL);
283*64f3c065SMichael Lotz 		}
284*64f3c065SMichael Lotz 	}
285*64f3c065SMichael Lotz 
286*64f3c065SMichael Lotz 	return B_DEV_INVALID_IOCTL;
287b8c6a851SMichael Lotz }
288b8c6a851SMichael Lotz 
289b8c6a851SMichael Lotz 
29096da8285SMichael Lotz /*
2911501c2bfSNiels Sascha Reedijk 	This module exports the USB API
29296da8285SMichael Lotz */
29396da8285SMichael Lotz struct usb_module_info gModuleInfo = {
2941501c2bfSNiels Sascha Reedijk 	// First the bus_manager_info:
2951501c2bfSNiels Sascha Reedijk 	{
2961501c2bfSNiels Sascha Reedijk 		{
297b8c6a851SMichael Lotz 			B_USB_MODULE_NAME,
2981501c2bfSNiels Sascha Reedijk 			B_KEEP_LOADED,				// Keep loaded, even if no driver requires it
2991501c2bfSNiels Sascha Reedijk 			bus_std_ops
3001501c2bfSNiels Sascha Reedijk 		},
3011501c2bfSNiels Sascha Reedijk 		NULL							// the rescan function
3021501c2bfSNiels Sascha Reedijk 	},
30396da8285SMichael Lotz 
304b8c6a851SMichael Lotz 	register_driver,					// register_driver
305b8c6a851SMichael Lotz 	install_notify,						// install_notify
306b8c6a851SMichael Lotz 	uninstall_notify,					// uninstall_notify
307b8c6a851SMichael Lotz 	get_device_descriptor,				// get_device_descriptor
308b8c6a851SMichael Lotz 	get_nth_configuration,				// get_nth_configuration
309b8c6a851SMichael Lotz 	get_configuration,					// get_configuration
310b8c6a851SMichael Lotz 	set_configuration,					// set_configuration
311b8c6a851SMichael Lotz 	set_alt_interface,					// set_alt_interface
312b8c6a851SMichael Lotz 	set_feature,						// set_feature
313b8c6a851SMichael Lotz 	clear_feature, 						// clear_feature
314b8c6a851SMichael Lotz 	get_status, 						// get_status
315b8c6a851SMichael Lotz 	get_descriptor,						// get_descriptor
316b8c6a851SMichael Lotz 	send_request,						// send_request
317b8c6a851SMichael Lotz 	queue_interrupt,					// queue_interrupt
318b8c6a851SMichael Lotz 	queue_bulk,							// queue_bulk
319b8c6a851SMichael Lotz 	queue_isochronous,					// queue_isochronous
320b8c6a851SMichael Lotz 	queue_request,						// queue_request
321b8c6a851SMichael Lotz 	set_pipe_policy,					// set_pipe_policy
322b8c6a851SMichael Lotz 	cancel_queued_transfers,			// cancel_queued_transfers
323b8c6a851SMichael Lotz 	usb_ioctl							// usb_ioctl
3241501c2bfSNiels Sascha Reedijk };
3251501c2bfSNiels Sascha Reedijk 
32696da8285SMichael Lotz 
3271501c2bfSNiels Sascha Reedijk module_info *modules[] = {
32896da8285SMichael Lotz 	(module_info *)&gModuleInfo,
3291501c2bfSNiels Sascha Reedijk 	NULL
3301501c2bfSNiels Sascha Reedijk };
331