Files
haiku-beta6/src/add-ons/kernel/bus_managers/usb/usb.cpp
T
Michael Lotz 8fedfdfcf8 * Rewrote some stack internals (again). Everything is now created using a parent object that shares the BusManager and Stack information to reduce individual constructors.
* Don't inherit Device and Interface from pipes anymore. The device has a default pipe member now.
* Since the parent of each Object is now known, we can send control messages using the default pipe of the device from all attached elements (pipes and interfaces).
* Fixed the generic {Set|Clear}Feature() and GetStatus() calls to include the endpoint address for pipe specific requests.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18710 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-08-30 17:59:23 +00:00

580 lines
16 KiB
C++

/*
* Copyright 2003-2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <[email protected]>
* Niels S. Reedijk
*/
#define TRACE_USB
#include <util/kernel_cpp.h>
#include "usb_p.h"
#include <USB_rle.h>
Stack *gUSBStack = NULL;
static int32
bus_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT: {
if (gUSBStack)
return B_OK;
#ifdef TRACE_USB
set_dprintf_enabled(true);
load_driver_symbols("usb");
TRACE(("usb_module: init\n"));
#endif
Stack *stack = new(std::nothrow) Stack();
if (!stack)
return B_NO_MEMORY;
if (stack->InitCheck() != B_OK) {
delete stack;
return ENODEV;
}
gUSBStack = stack;
break;
}
case B_MODULE_UNINIT:
TRACE(("usb_module: bus module: uninit\n"));
delete gUSBStack;
gUSBStack = NULL;
break;
default:
return EINVAL;
}
return B_OK;
}
status_t
register_driver(const char *driverName,
const usb_support_descriptor *descriptors,
size_t count, const char *optionalRepublishDriverName)
{
return gUSBStack->RegisterDriver(driverName, descriptors, count,
optionalRepublishDriverName);
}
status_t
install_notify(const char *driverName, const usb_notify_hooks *hooks)
{
return gUSBStack->InstallNotify(driverName, hooks);
}
status_t
uninstall_notify(const char *driverName)
{
return gUSBStack->UninstallNotify(driverName);
}
const usb_device_descriptor *
get_device_descriptor(usb_device device)
{
TRACE(("usb_module: get_device_descriptor(0x%08x)\n", device));
Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return NULL;
return ((Device *)object)->DeviceDescriptor();
}
const usb_configuration_info *
get_nth_configuration(usb_device device, uint index)
{
TRACE(("usb_module: get_nth_configuration(0x%08x, %d)\n", device, index));
Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return NULL;
return ((Device *)object)->ConfigurationAt((int32)index);
}
const usb_configuration_info *
get_configuration(usb_device device)
{
TRACE(("usb_module: get_configuration(0x%08x)\n", device));
Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return NULL;
return ((Device *)object)->Configuration();
}
status_t
set_configuration(usb_device device,
const usb_configuration_info *configuration)
{
TRACE(("usb_module: set_configuration(0x%08x, 0x%08x)\n", device, configuration));
Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE;
return ((Device *)object)->SetConfiguration(configuration);
}
status_t
set_alt_interface(usb_device device, const usb_interface_info *interface)
{
TRACE(("usb_module: set_alt_interface(0x%08x, 0x%08x)\n", device, interface));
Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE;
return B_ERROR;
}
status_t
set_feature(usb_id handle, uint16 selector)
{
TRACE(("usb_module: set_feature(0x%08x, %d)\n", handle, selector));
Object *object = gUSBStack->GetObject(handle);
if (!object)
return B_BAD_VALUE;
return object->SetFeature(selector);
}
status_t
clear_feature(usb_id handle, uint16 selector)
{
TRACE(("usb_module: clear_feature(0x%08x, %d)\n", handle, selector));
Object *object = gUSBStack->GetObject(handle);
if (!object)
return B_BAD_VALUE;
return object->ClearFeature(selector);
}
status_t
get_status(usb_id handle, uint16 *status)
{
TRACE(("usb_module: get_status(0x%08x, 0x%08x)\n", handle, status));
if (!status)
return B_BAD_VALUE;
Object *object = gUSBStack->GetObject(handle);
if (!object)
return B_BAD_VALUE;
return object->GetStatus(status);
}
status_t
get_descriptor(usb_device device, uint8 type, uint8 index, uint16 languageID,
void *data, size_t dataLength, size_t *actualLength)
{
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));
Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE;
return ((Device *)object)->GetDescriptor(type, index, languageID,
data, dataLength, actualLength);
}
status_t
send_request(usb_device device, uint8 requestType, uint8 request,
uint16 value, uint16 index, uint16 length, void *data, size_t *actualLength)
{
TRACE(("usb_module: send_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, 0x%08x)\n", device, requestType, request, value, index, length, data, actualLength));
Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE;
return ((Device *)object)->DefaultPipe()->SendRequest(requestType, request,
value, index, length, data, length, actualLength);
}
status_t
queue_request(usb_device device, uint8 requestType, uint8 request,
uint16 value, uint16 index, uint16 length, void *data,
usb_callback_func callback, void *callbackCookie)
{
TRACE(("usb_module: queue_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, 0x%08x, 0x%08x)\n", device, requestType, request, value, index, length, data, callback, callbackCookie));
Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE;
return ((Device *)object)->DefaultPipe()->QueueRequest(requestType,
request, value, index, length, data, length, callback, callbackCookie);
}
status_t
queue_interrupt(usb_pipe pipe, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
TRACE(("usb_module: queue_interrupt(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie));
Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_INTERRUPT_PIPE) == 0)
return B_BAD_VALUE;
return ((InterruptPipe *)object)->QueueInterrupt(data, dataLength, callback,
callbackCookie);
}
status_t
queue_bulk(usb_pipe pipe, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
TRACE(("usb_module: queue_bulk(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie));
Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0)
return B_BAD_VALUE;
return ((BulkPipe *)object)->QueueBulk(data, dataLength, callback,
callbackCookie);
}
status_t
queue_bulk_v(usb_pipe pipe, iovec *vector, size_t vectorCount,
usb_callback_func callback, void *callbackCookie)
{
TRACE(("usb_module: queue_bulk(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, vector, vectorCount, callback, callbackCookie));
Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0)
return B_BAD_VALUE;
return ((BulkPipe *)object)->QueueBulkV(vector, vectorCount, callback,
callbackCookie);
}
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)
{
TRACE(("usb_module: queue_isochronous(0x%08x, 0x%08x, %d, 0x%08x, %d, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pipe, data, dataLength, packetDesc, packetCount, startingFrameNumber, flags, callback, callbackCookie));
Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0)
return B_BAD_VALUE;
return ((IsochronousPipe *)object)->QueueIsochronous(data, dataLength,
packetDesc, packetCount, startingFrameNumber, flags, callback,
callbackCookie);
}
status_t
set_pipe_policy(usb_pipe pipe, uint8 maxQueuedPackets,
uint16 maxBufferDurationMS, uint16 sampleSize)
{
TRACE(("usb_module: set_pipe_policy(0x%08x, %d, %d, %d)\n", pipe, maxQueuedPackets, maxBufferDurationMS, sampleSize));
Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0)
return B_BAD_VALUE;
return B_ERROR;
}
status_t
cancel_queued_transfers(usb_pipe pipe)
{
TRACE(("usb_module: cancel_queued_transfers(0x%08x)\n", pipe));
Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
return B_BAD_VALUE;
return ((Pipe *)object)->CancelQueuedTransfers();
}
status_t
usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize)
{
TRACE(("usb_module: usb_ioctl(0x%08x, 0x%08x, %d)\n", opcode, buffer, bufferSize));
switch (opcode) {
case 'DNAM': {
Object *object = gUSBStack->GetObject(*(usb_id *)buffer);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE;
uint32 index = 0;
return ((Device *)object)->BuildDeviceName((char *)buffer, &index,
bufferSize, NULL);
}
}
return B_DEV_INVALID_IOCTL;
}
/*
This module exports the USB API v3
*/
struct usb_module_info gModuleInfoV3 = {
// First the bus_manager_info:
{
{
"bus_managers/usb/v3",
B_KEEP_LOADED, // Keep loaded, even if no driver requires it
bus_std_ops
},
NULL // the rescan function
},
register_driver, // register_driver
install_notify, // install_notify
uninstall_notify, // uninstall_notify
get_device_descriptor, // get_device_descriptor
get_nth_configuration, // get_nth_configuration
get_configuration, // get_configuration
set_configuration, // set_configuration
set_alt_interface, // set_alt_interface
set_feature, // set_feature
clear_feature, // clear_feature
get_status, // get_status
get_descriptor, // get_descriptor
send_request, // send_request
queue_interrupt, // queue_interrupt
queue_bulk, // queue_bulk
queue_bulk_v, // queue_bulk_v
queue_isochronous, // queue_isochronous
queue_request, // queue_request
set_pipe_policy, // set_pipe_policy
cancel_queued_transfers, // cancel_queued_transfers
usb_ioctl // usb_ioctl
};
//
// #pragma mark -
//
const usb_device_descriptor *
get_device_descriptor_v2(const void *device)
{
return get_device_descriptor((usb_id)device);
}
const usb_configuration_info *
get_nth_configuration_v2(const void *device, uint index)
{
return get_nth_configuration((usb_id)device, index);
}
const usb_configuration_info *
get_configuration_v2(const void *device)
{
return get_configuration((usb_id)device);
}
status_t
set_configuration_v2(const void *device,
const usb_configuration_info *configuration)
{
return set_configuration((usb_id)device, configuration);
}
status_t
set_alt_interface_v2(const void *device, const usb_interface_info *interface)
{
return set_alt_interface((usb_id)device, interface);
}
status_t
set_feature_v2(const void *object, uint16 selector)
{
return set_feature((usb_id)object, selector);
}
status_t
clear_feature_v2(const void *object, uint16 selector)
{
return clear_feature((usb_id)object, selector);
}
status_t
get_status_v2(const void *object, uint16 *status)
{
return get_status((usb_id)object, status);
}
status_t
get_descriptor_v2(const void *device, uint8 type, uint8 index,
uint16 languageID, void *data, size_t dataLength, size_t *actualLength)
{
return get_descriptor((usb_id)device, type, index, languageID, data,
dataLength, actualLength);
}
status_t
send_request_v2(const void *device, uint8 requestType, uint8 request,
uint16 value, uint16 index, uint16 length, void *data,
size_t /*dataLength*/, size_t *actualLength)
{
return send_request((usb_id)device, requestType, request, value, index,
length, data, actualLength);
}
status_t
queue_request_v2(const void *device, uint8 requestType, uint8 request,
uint16 value, uint16 index, uint16 length, void *data,
size_t /*dataLength*/, usb_callback_func callback, void *callbackCookie)
{
return queue_request((usb_id)device, requestType, request, value, index,
length, data, callback, callbackCookie);
}
status_t
queue_interrupt_v2(const void *pipe, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
return queue_interrupt((usb_id)pipe, data, dataLength, callback,
callbackCookie);
}
status_t
queue_bulk_v2(const void *pipe, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
return queue_bulk((usb_id)pipe, data, dataLength, callback,
callbackCookie);
}
status_t
queue_isochronous_v2(const void *pipe, void *data, size_t dataLength,
rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback,
void *callbackCookie)
{
// ToDo: convert rlea to usb_iso_packet_descriptor
// ToDo: use a flag to indicate that the callback shall produce a rlea
usb_iso_packet_descriptor *packetDesc = NULL;
return queue_isochronous((usb_id)pipe, data, dataLength, packetDesc, 0,
NULL, 0, callback, callbackCookie);
}
status_t
set_pipe_policy_v2(const void *pipe, uint8 maxQueuedPackets,
uint16 maxBufferDurationMS, uint16 sampleSize)
{
return set_pipe_policy((usb_id)pipe, maxQueuedPackets, maxBufferDurationMS,
sampleSize);
}
status_t
cancel_queued_transfers_v2(const void *pipe)
{
return cancel_queued_transfers((usb_id)pipe);
}
struct usb_module_info_v2 {
bus_manager_info binfo;
status_t (*register_driver)(const char *, const usb_support_descriptor *, size_t, const char *);
status_t (*install_notify)(const char *, const usb_notify_hooks *);
status_t (*uninstall_notify)(const char *);
const usb_device_descriptor *(*get_device_descriptor)(const void *);
const usb_configuration_info *(*get_nth_configuration)(const void *, uint);
const usb_configuration_info *(*get_configuration)(const void *);
status_t (*set_configuration)(const void *, const usb_configuration_info *);
status_t (*set_alt_interface)(const void *, const usb_interface_info *);
status_t (*set_feature)(const void *, uint16);
status_t (*clear_feature)(const void *, uint16);
status_t (*get_status)(const void *, uint16 *);
status_t (*get_descriptor)(const void *, uint8, uint8, uint16, void *, size_t, size_t *);
status_t (*send_request)(const void *, uint8, uint8, uint16, uint16, uint16, void *, size_t, size_t *);
status_t (*queue_interrupt)(const void *, void *, size_t, usb_callback_func, void *);
status_t (*queue_bulk)(const void *, void *, size_t, usb_callback_func, void *);
status_t (*queue_isochronous)(const void *, void *, size_t, rlea *, uint16, usb_callback_func, void *);
status_t (*queue_request)(const void *, uint8, uint8, uint16, uint16, uint16, void *, size_t, usb_callback_func, void *);
status_t (*set_pipe_policy)(const void *, uint8, uint16, uint16);
status_t (*cancel_queued_transfers)(const void *);
status_t (*usb_ioctl)(uint32 opcode, void *,size_t);
};
/*
This module exports the USB API v2
*/
struct usb_module_info_v2 gModuleInfoV2 = {
// First the bus_manager_info:
{
{
"bus_managers/usb/v2",
B_KEEP_LOADED, // Keep loaded, even if no driver requires it
bus_std_ops
},
NULL // the rescan function
},
register_driver, // register_driver
install_notify, // install_notify
uninstall_notify, // uninstall_notify
get_device_descriptor_v2, // get_device_descriptor
get_nth_configuration_v2, // get_nth_configuration
get_configuration_v2, // get_configuration
set_configuration_v2, // set_configuration
set_alt_interface_v2, // set_alt_interface
set_feature_v2, // set_feature
clear_feature_v2, // clear_feature
get_status_v2, // get_status
get_descriptor_v2, // get_descriptor
send_request_v2, // send_request
queue_interrupt_v2, // queue_interrupt
queue_bulk_v2, // queue_bulk
queue_isochronous_v2, // queue_isochronous
queue_request_v2, // queue_request
set_pipe_policy_v2, // set_pipe_policy
cancel_queued_transfers_v2, // cancel_queued_transfers
usb_ioctl // usb_ioctl
};
//
// #pragma mark -
//
module_info *modules[] = {
(module_info *)&gModuleInfoV2,
(module_info *)&gModuleInfoV3,
NULL
};