Adding usb_raw driver. Written from scratch, but kept the data structures and status codes to be compatible with existing apps. Tested OK with the PTP plugin for Exposure.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18512 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
bf9d24edd2
commit
8c76868794
@ -2,3 +2,4 @@ SubDir HAIKU_TOP src add-ons kernel drivers bus ;
|
|||||||
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel drivers bus pcmcia ;
|
SubInclude HAIKU_TOP src add-ons kernel drivers bus pcmcia ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel drivers bus scsi ;
|
SubInclude HAIKU_TOP src add-ons kernel drivers bus scsi ;
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel drivers bus usb ;
|
||||||
|
5
src/add-ons/kernel/drivers/bus/usb/Jamfile
Normal file
5
src/add-ons/kernel/drivers/bus/usb/Jamfile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel drivers bus usb ;
|
||||||
|
|
||||||
|
KernelAddon usb_raw : kernel drivers bus usb :
|
||||||
|
usb_raw.cpp
|
||||||
|
;
|
661
src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp
Normal file
661
src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp
Normal file
@ -0,0 +1,661 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Michael Lotz <mmlr@mlotz.ch>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <Drivers.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "usb_raw.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define TRACE_USB_RAW
|
||||||
|
#ifdef TRACE_USB_RAW
|
||||||
|
#define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
#define TRACE(x) /* nothing */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define DRIVER_NAME "usb_raw"
|
||||||
|
#define DEVICE_NAME "bus/usb/raw"
|
||||||
|
#define DRIVER_VERSION 0x0015
|
||||||
|
|
||||||
|
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||||
|
usb_module_info *gUSBModule = NULL;
|
||||||
|
raw_device *gDeviceList = NULL;
|
||||||
|
uint32 gDeviceCount = 0;
|
||||||
|
benaphore gDeviceListLock;
|
||||||
|
|
||||||
|
// ToDo: replace with proper device name getter (ioctl to bus manager)
|
||||||
|
uint8 gDeviceLevel;
|
||||||
|
uint8 gDeviceCounters[7];
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
usb_raw_device_added(const usb_device *newDevice, void **cookie)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": device_added()\n"));
|
||||||
|
raw_device *device = (raw_device *)malloc(sizeof(raw_device));
|
||||||
|
|
||||||
|
status_t result = benaphore_init(&device->lock, "usb_raw device lock");
|
||||||
|
if (result < B_OK) {
|
||||||
|
free(device);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->notify = create_sem(0, "usb_raw callback notify");
|
||||||
|
if (device->notify < B_OK) {
|
||||||
|
benaphore_destroy(&device->lock);
|
||||||
|
free(device);
|
||||||
|
return B_NO_MORE_SEMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDo: replace with proper device name getter (ioctl to bus manager)
|
||||||
|
char devicePathString[32];
|
||||||
|
char *devicePath = &devicePathString[0];
|
||||||
|
memset(devicePath, 0, sizeof(devicePath));
|
||||||
|
|
||||||
|
const usb_device_descriptor *deviceDescriptor =
|
||||||
|
gUSBModule->get_device_descriptor(newDevice);
|
||||||
|
if (deviceDescriptor->device_class == 0x09
|
||||||
|
&& deviceDescriptor->vendor_id == 0x0000
|
||||||
|
&& deviceDescriptor->product_id == 0x000) {
|
||||||
|
// root hub
|
||||||
|
memset(gDeviceCounters + 1, 0, sizeof(gDeviceCounters) - 1);
|
||||||
|
gDeviceLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8 i = 0; i <= gDeviceLevel; i++)
|
||||||
|
devicePath += sprintf(devicePath, "/%d", gDeviceCounters[i]);
|
||||||
|
|
||||||
|
gDeviceCounters[gDeviceLevel]++;
|
||||||
|
if (deviceDescriptor->device_class == 0x09) {
|
||||||
|
sprintf(device->name, "bus/usb%s/hub", devicePathString);
|
||||||
|
gDeviceLevel++;
|
||||||
|
} else {
|
||||||
|
sprintf(device->name, "bus/usb%s", devicePathString);
|
||||||
|
}
|
||||||
|
|
||||||
|
device->device = newDevice;
|
||||||
|
|
||||||
|
benaphore_lock(&gDeviceListLock);
|
||||||
|
device->link = (void *)gDeviceList;
|
||||||
|
gDeviceList = device;
|
||||||
|
gDeviceCount++;
|
||||||
|
benaphore_unlock(&gDeviceListLock);
|
||||||
|
|
||||||
|
*cookie = (void *)device;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
usb_raw_device_removed(void *cookie)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": device_removed()\n"));
|
||||||
|
raw_device *device = (raw_device *)cookie;
|
||||||
|
|
||||||
|
benaphore_lock(&gDeviceListLock);
|
||||||
|
if (gDeviceList == device) {
|
||||||
|
gDeviceList = (raw_device *)device->link;
|
||||||
|
} else {
|
||||||
|
raw_device *element = gDeviceList;
|
||||||
|
while (element) {
|
||||||
|
if (element->link == device) {
|
||||||
|
element->link = device->link;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = (raw_device *)element->link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gDeviceCount--;
|
||||||
|
benaphore_unlock(&gDeviceListLock);
|
||||||
|
|
||||||
|
benaphore_lock(&device->lock);
|
||||||
|
benaphore_destroy(&device->lock);
|
||||||
|
delete_sem(device->notify);
|
||||||
|
free(device);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//#pragma mark -
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
usb_raw_open(const char *name, uint32 flags, void **cookie)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": open()\n"));
|
||||||
|
benaphore_lock(&gDeviceListLock);
|
||||||
|
raw_device *element = gDeviceList;
|
||||||
|
while (element) {
|
||||||
|
if (strcmp(name, element->name) == 0) {
|
||||||
|
*cookie = element;
|
||||||
|
benaphore_unlock(&gDeviceListLock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = (raw_device *)element->link;
|
||||||
|
}
|
||||||
|
|
||||||
|
benaphore_unlock(&gDeviceListLock);
|
||||||
|
return B_NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
usb_raw_close(void *cookie)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": close()\n"));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
usb_raw_free(void *cookie)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": free()\n"));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_raw_callback(void *cookie, uint32 status, void *data, size_t actualLength)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": callback()\n"));
|
||||||
|
raw_device *device = (raw_device *)cookie;
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case B_USB_STATUS_SUCCESS:
|
||||||
|
device->status = RAW_STATUS_SUCCESS;
|
||||||
|
break;
|
||||||
|
case B_USB_STATUS_DEVICE_CRC_ERROR:
|
||||||
|
device->status = RAW_STATUS_CRC_ERROR;
|
||||||
|
break;
|
||||||
|
case B_USB_STATUS_DEVICE_TIMEOUT:
|
||||||
|
device->status = RAW_STATUS_TIMEOUT;
|
||||||
|
break;
|
||||||
|
case B_USB_STATUS_DEVICE_STALLED:
|
||||||
|
device->status = RAW_STATUS_STALLED;
|
||||||
|
break;
|
||||||
|
case B_USB_STATUS_IRP_CANCELLED_BY_REQUEST:
|
||||||
|
device->status = RAW_STATUS_ABORTED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
device->status = RAW_STATUS_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->actual_length = actualLength;
|
||||||
|
release_sem(device->notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
usb_raw_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": ioctl\n"));
|
||||||
|
raw_device *device = (raw_device *)cookie;
|
||||||
|
raw_command *command = (raw_command *)buffer;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case RAW_COMMAND_GET_VERSION: {
|
||||||
|
command->version.status = DRIVER_VERSION;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_GET_DEVICE_DESCRIPTOR: {
|
||||||
|
const usb_device_descriptor *deviceDescriptor =
|
||||||
|
gUSBModule->get_device_descriptor(device->device);
|
||||||
|
if (!deviceDescriptor) {
|
||||||
|
command->device.status = RAW_STATUS_ABORTED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(command->device.descriptor, deviceDescriptor,
|
||||||
|
sizeof(usb_device_descriptor));
|
||||||
|
command->device.status = RAW_STATUS_SUCCESS;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR: {
|
||||||
|
const usb_configuration_info *configurationInfo =
|
||||||
|
gUSBModule->get_nth_configuration(device->device,
|
||||||
|
command->config.config_index);
|
||||||
|
if (!configurationInfo) {
|
||||||
|
command->config.status = RAW_STATUS_INVALID_CONFIGURATION;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(command->config.descriptor, configurationInfo->descr,
|
||||||
|
sizeof(usb_configuration_descriptor));
|
||||||
|
command->config.status = RAW_STATUS_SUCCESS;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_GET_INTERFACE_DESCRIPTOR: {
|
||||||
|
const usb_configuration_info *configurationInfo =
|
||||||
|
gUSBModule->get_nth_configuration(device->device,
|
||||||
|
command->interface.config_index);
|
||||||
|
if (!configurationInfo) {
|
||||||
|
command->interface.status = RAW_STATUS_INVALID_CONFIGURATION;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command->interface.interface_index >= configurationInfo->interface_count) {
|
||||||
|
command->interface.status = RAW_STATUS_INVALID_INTERFACE;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usb_interface_info *interfaceInfo =
|
||||||
|
configurationInfo->interface[command->endpoint.interface_index].active;
|
||||||
|
if (!interfaceInfo) {
|
||||||
|
command->interface.status = RAW_STATUS_ABORTED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(command->interface.descriptor, interfaceInfo->descr,
|
||||||
|
sizeof(usb_interface_descriptor));
|
||||||
|
command->interface.status = RAW_STATUS_SUCCESS;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR: {
|
||||||
|
const usb_configuration_info *configurationInfo =
|
||||||
|
gUSBModule->get_nth_configuration(device->device,
|
||||||
|
command->endpoint.config_index);
|
||||||
|
if (!configurationInfo) {
|
||||||
|
command->endpoint.status = RAW_STATUS_INVALID_CONFIGURATION;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command->endpoint.interface_index >= configurationInfo->interface_count) {
|
||||||
|
command->endpoint.status = RAW_STATUS_INVALID_INTERFACE;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usb_interface_info *interfaceInfo =
|
||||||
|
configurationInfo->interface[command->endpoint.interface_index].active;
|
||||||
|
if (!interfaceInfo) {
|
||||||
|
command->endpoint.status = RAW_STATUS_ABORTED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command->endpoint.endpoint_index >= interfaceInfo->endpoint_count) {
|
||||||
|
command->endpoint.status = RAW_STATUS_INVALID_ENDPOINT;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(command->endpoint.descriptor,
|
||||||
|
interfaceInfo->endpoint[command->endpoint.endpoint_index].descr,
|
||||||
|
sizeof(usb_endpoint_descriptor));
|
||||||
|
command->endpoint.status = RAW_STATUS_SUCCESS;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_GET_GENERIC_DESCRIPTOR: {
|
||||||
|
const usb_configuration_info *configurationInfo =
|
||||||
|
gUSBModule->get_nth_configuration(device->device,
|
||||||
|
command->generic.config_index);
|
||||||
|
if (!configurationInfo) {
|
||||||
|
command->generic.status = RAW_STATUS_INVALID_CONFIGURATION;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command->generic.interface_index >= configurationInfo->interface_count) {
|
||||||
|
command->generic.status = RAW_STATUS_INVALID_INTERFACE;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usb_interface_info *interfaceInfo =
|
||||||
|
configurationInfo->interface[command->generic.interface_index].active;
|
||||||
|
if (!interfaceInfo) {
|
||||||
|
command->generic.status = RAW_STATUS_ABORTED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command->generic.generic_index >= interfaceInfo->generic_count) {
|
||||||
|
// ToDo: add RAW_STATUS_INVALID_GENERIC
|
||||||
|
command->generic.status = RAW_STATUS_INVALID_ENDPOINT;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_descriptor *descriptor = interfaceInfo->generic[command->generic.generic_index];
|
||||||
|
if (!descriptor) {
|
||||||
|
command->generic.status = RAW_STATUS_ABORTED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->generic.length > command->generic.length) {
|
||||||
|
command->generic.status = RAW_STATUS_NO_MEMORY;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(command->generic.descriptor, descriptor,
|
||||||
|
descriptor->generic.length);
|
||||||
|
command->generic.status = RAW_STATUS_SUCCESS;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_GET_STRING_DESCRIPTOR: {
|
||||||
|
size_t actualLength = 0;
|
||||||
|
uint8 firstTwoBytes[2];
|
||||||
|
|
||||||
|
if (gUSBModule->get_descriptor(device->device,
|
||||||
|
USB_DESCRIPTOR_STRING, command->string.string_index, 0,
|
||||||
|
firstTwoBytes, 2, &actualLength) < B_OK
|
||||||
|
|| actualLength != 2
|
||||||
|
|| firstTwoBytes[1] != USB_DESCRIPTOR_STRING) {
|
||||||
|
command->string.status = RAW_STATUS_ABORTED;
|
||||||
|
command->string.length = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 stringLength = MIN(firstTwoBytes[0], command->string.length);
|
||||||
|
char *string = (char *)malloc(stringLength);
|
||||||
|
if (!string) {
|
||||||
|
command->string.status = RAW_STATUS_ABORTED;
|
||||||
|
command->string.length = 0;
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gUSBModule->get_descriptor(device->device,
|
||||||
|
USB_DESCRIPTOR_STRING, command->string.string_index, 0,
|
||||||
|
string, stringLength, &actualLength) < B_OK
|
||||||
|
|| actualLength != stringLength) {
|
||||||
|
command->string.status = RAW_STATUS_ABORTED;
|
||||||
|
command->string.length = 0;
|
||||||
|
free(string);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(command->string.descriptor, string, stringLength);
|
||||||
|
command->string.status = RAW_STATUS_SUCCESS;
|
||||||
|
command->string.length = stringLength;
|
||||||
|
free(string);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_GET_DESCRIPTOR: {
|
||||||
|
size_t actualLength = 0;
|
||||||
|
uint8 firstTwoBytes[2];
|
||||||
|
|
||||||
|
if (gUSBModule->get_descriptor(device->device,
|
||||||
|
command->descriptor.type, command->descriptor.index,
|
||||||
|
command->descriptor.language_id, firstTwoBytes, 2,
|
||||||
|
&actualLength) < B_OK
|
||||||
|
|| actualLength != 2
|
||||||
|
|| firstTwoBytes[1] != command->descriptor.type) {
|
||||||
|
command->descriptor.status = RAW_STATUS_ABORTED;
|
||||||
|
command->descriptor.length = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 length = MIN(firstTwoBytes[0], command->descriptor.length);
|
||||||
|
uint8 *buffer = (uint8 *)malloc(length);
|
||||||
|
if (!buffer) {
|
||||||
|
command->descriptor.status = RAW_STATUS_ABORTED;
|
||||||
|
command->descriptor.length = 0;
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gUSBModule->get_descriptor(device->device,
|
||||||
|
command->descriptor.type, command->descriptor.index,
|
||||||
|
command->descriptor.language_id, buffer, length,
|
||||||
|
&actualLength) < B_OK
|
||||||
|
|| actualLength != length) {
|
||||||
|
command->descriptor.status = RAW_STATUS_ABORTED;
|
||||||
|
command->descriptor.length = 0;
|
||||||
|
free(buffer);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(command->descriptor.data, buffer, length);
|
||||||
|
command->descriptor.status = RAW_STATUS_SUCCESS;
|
||||||
|
command->descriptor.length = length;
|
||||||
|
free(buffer);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_SET_CONFIGURATION: {
|
||||||
|
const usb_configuration_info *configurationInfo =
|
||||||
|
gUSBModule->get_nth_configuration(device->device,
|
||||||
|
command->config.config_index);
|
||||||
|
if (!configurationInfo) {
|
||||||
|
command->config.status = RAW_STATUS_INVALID_CONFIGURATION;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gUSBModule->set_configuration(device->device,
|
||||||
|
configurationInfo) < B_OK) {
|
||||||
|
command->config.status = RAW_STATUS_FAILED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command->config.status = RAW_STATUS_SUCCESS;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_CONTROL_TRANSFER: {
|
||||||
|
if (command->control.length > B_PAGE_SIZE) {
|
||||||
|
command->control.status = RAW_STATUS_FAILED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
benaphore_lock(&device->lock);
|
||||||
|
memcpy(device->buffer, command->control.data, command->control.length);
|
||||||
|
if (gUSBModule->queue_request(device->device,
|
||||||
|
command->control.request_type, command->control.request,
|
||||||
|
command->control.value, command->control.index,
|
||||||
|
command->control.length, device->buffer, command->control.length,
|
||||||
|
usb_raw_callback, device) < B_OK) {
|
||||||
|
command->control.status = RAW_STATUS_FAILED;
|
||||||
|
command->control.length = 0;
|
||||||
|
benaphore_unlock(&device->lock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
acquire_sem(device->notify);
|
||||||
|
memcpy(command->control.data, device->buffer, command->control.length);
|
||||||
|
command->control.status = device->status;
|
||||||
|
command->control.length = device->actual_length;
|
||||||
|
benaphore_unlock(&device->lock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAW_COMMAND_INTERRUPT_TRANSFER:
|
||||||
|
case RAW_COMMAND_BULK_TRANSFER: {
|
||||||
|
if (command->transfer.length > B_PAGE_SIZE) {
|
||||||
|
command->transfer.status = RAW_STATUS_FAILED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usb_configuration_info *configurationInfo =
|
||||||
|
gUSBModule->get_configuration(device->device);
|
||||||
|
if (!configurationInfo) {
|
||||||
|
command->transfer.status = RAW_STATUS_INVALID_CONFIGURATION;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command->transfer.interface >= configurationInfo->interface_count) {
|
||||||
|
command->transfer.status = RAW_STATUS_INVALID_INTERFACE;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usb_interface_info *interfaceInfo =
|
||||||
|
configurationInfo->interface[command->transfer.interface].active;
|
||||||
|
if (!interfaceInfo) {
|
||||||
|
command->transfer.status = RAW_STATUS_ABORTED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command->transfer.endpoint >= interfaceInfo->endpoint_count) {
|
||||||
|
command->transfer.status = RAW_STATUS_INVALID_ENDPOINT;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usb_endpoint_info *endpointInfo =
|
||||||
|
&interfaceInfo->endpoint[command->transfer.endpoint];
|
||||||
|
if (!endpointInfo->handle) {
|
||||||
|
command->transfer.status = RAW_STATUS_INVALID_ENDPOINT;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
benaphore_lock(&device->lock);
|
||||||
|
memcpy(device->buffer, command->transfer.data, command->transfer.length);
|
||||||
|
|
||||||
|
status_t status;
|
||||||
|
if (op == RAW_COMMAND_INTERRUPT_TRANSFER) {
|
||||||
|
status = gUSBModule->queue_interrupt(endpointInfo->handle,
|
||||||
|
device->buffer, command->transfer.length, usb_raw_callback,
|
||||||
|
device);
|
||||||
|
} else {
|
||||||
|
status = gUSBModule->queue_bulk(endpointInfo->handle,
|
||||||
|
device->buffer, command->transfer.length, usb_raw_callback,
|
||||||
|
device);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status < B_OK) {
|
||||||
|
command->transfer.status = RAW_STATUS_FAILED;
|
||||||
|
command->transfer.length = 0;
|
||||||
|
benaphore_unlock(&device->lock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
acquire_sem(device->notify);
|
||||||
|
memcpy(command->transfer.data, device->buffer, command->transfer.length);
|
||||||
|
command->transfer.status = device->status;
|
||||||
|
command->transfer.length = device->actual_length;
|
||||||
|
benaphore_unlock(&device->lock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_DEV_INVALID_IOCTL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
usb_raw_read(void *cookie, off_t position, void *buffer, size_t *length)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": read()\n"));
|
||||||
|
*length = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
usb_raw_write(void *cookie, off_t position, const void *buffer, size_t *length)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": write()\n"));
|
||||||
|
*length = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//#pragma mark -
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
init_hardware()
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": init_hardware()\n"));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
init_driver()
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": init_driver()\n"));
|
||||||
|
static usb_notify_hooks notifyHooks = {
|
||||||
|
&usb_raw_device_added,
|
||||||
|
&usb_raw_device_removed
|
||||||
|
};
|
||||||
|
|
||||||
|
gDeviceLevel = 0;
|
||||||
|
memset(gDeviceCounters, 0, sizeof(gDeviceCounters));
|
||||||
|
|
||||||
|
gDeviceList = NULL;
|
||||||
|
gDeviceCount = 0;
|
||||||
|
status_t result = benaphore_init(&gDeviceListLock, "usb_raw device list lock");
|
||||||
|
if (result < B_OK) {
|
||||||
|
TRACE((DRIVER_NAME": failed to create device list lock\n"));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE((DRIVER_NAME": trying module %s\n", B_USB_MODULE_NAME));
|
||||||
|
result = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule);
|
||||||
|
if (result < B_OK) {
|
||||||
|
TRACE((DRIVER_NAME": getting module failed 0x%08x\n", result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL);
|
||||||
|
gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
uninit_driver()
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": uninit_driver()\n"));
|
||||||
|
gUSBModule->uninstall_notify(DRIVER_NAME);
|
||||||
|
benaphore_lock(&gDeviceListLock);
|
||||||
|
benaphore_destroy(&gDeviceListLock);
|
||||||
|
put_module(B_USB_MODULE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char **
|
||||||
|
publish_devices(void)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": publish_devices()\n"));
|
||||||
|
benaphore_lock(&gDeviceListLock);
|
||||||
|
const char **deviceNames = (const char **)malloc(sizeof(char *) * (gDeviceCount + 2));
|
||||||
|
|
||||||
|
uint8 index = 0;
|
||||||
|
deviceNames[index++] = DEVICE_NAME;
|
||||||
|
|
||||||
|
raw_device *element = gDeviceList;
|
||||||
|
while (element) {
|
||||||
|
deviceNames[index++] = element->name;
|
||||||
|
element = (raw_device *)element->link;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceNames[index++] = NULL;
|
||||||
|
benaphore_unlock(&gDeviceListLock);
|
||||||
|
return deviceNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_hooks *
|
||||||
|
find_device(const char *name)
|
||||||
|
{
|
||||||
|
TRACE((DRIVER_NAME": find_device()\n"));
|
||||||
|
static device_hooks hooks = {
|
||||||
|
&usb_raw_open,
|
||||||
|
&usb_raw_close,
|
||||||
|
&usb_raw_free,
|
||||||
|
&usb_raw_ioctl,
|
||||||
|
&usb_raw_read,
|
||||||
|
&usb_raw_write,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
return &hooks;
|
||||||
|
}
|
147
src/add-ons/kernel/drivers/bus/usb/usb_raw.h
Normal file
147
src/add-ons/kernel/drivers/bus/usb/usb_raw.h
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Michael Lotz <mmlr@mlotz.ch>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _USB_RAW_H_
|
||||||
|
#define _USB_RAW_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <lock.h>
|
||||||
|
#include <USB.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RAW_COMMAND_GET_VERSION = 0x1000,
|
||||||
|
|
||||||
|
RAW_COMMAND_GET_DEVICE_DESCRIPTOR = 0x2000,
|
||||||
|
RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR,
|
||||||
|
RAW_COMMAND_GET_INTERFACE_DESCRIPTOR,
|
||||||
|
RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR,
|
||||||
|
RAW_COMMAND_GET_STRING_DESCRIPTOR,
|
||||||
|
RAW_COMMAND_GET_GENERIC_DESCRIPTOR,
|
||||||
|
|
||||||
|
RAW_COMMAND_SET_CONFIGURATION = 0x3000,
|
||||||
|
RAW_COMMAND_SET_FEATURE,
|
||||||
|
RAW_COMMAND_CLEAR_FEATURE,
|
||||||
|
RAW_COMMAND_GET_STATUS,
|
||||||
|
RAW_COMMAND_GET_DESCRIPTOR,
|
||||||
|
|
||||||
|
RAW_COMMAND_CONTROL_TRANSFER = 0x4000,
|
||||||
|
RAW_COMMAND_INTERRUPT_TRANSFER,
|
||||||
|
RAW_COMMAND_BULK_TRANSFER
|
||||||
|
} raw_command_id;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RAW_STATUS_SUCCESS = 0,
|
||||||
|
|
||||||
|
RAW_STATUS_FAILED,
|
||||||
|
RAW_STATUS_ABORTED,
|
||||||
|
RAW_STATUS_STALLED,
|
||||||
|
RAW_STATUS_CRC_ERROR,
|
||||||
|
RAW_STATUS_TIMEOUT,
|
||||||
|
|
||||||
|
RAW_STATUS_INVALID_CONFIGURATION,
|
||||||
|
RAW_STATUS_INVALID_INTERFACE,
|
||||||
|
RAW_STATUS_INVALID_ENDPOINT,
|
||||||
|
RAW_STATUS_INVALID_STRING,
|
||||||
|
|
||||||
|
RAW_STATUS_NO_MEMORY
|
||||||
|
} raw_command_status;
|
||||||
|
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
} version;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
usb_device_descriptor *descriptor;
|
||||||
|
} device;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
usb_configuration_descriptor *descriptor;
|
||||||
|
uint32 config_index;
|
||||||
|
} config;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
usb_interface_descriptor *descriptor;
|
||||||
|
uint32 config_index;
|
||||||
|
uint32 interface_index;
|
||||||
|
} interface;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
usb_endpoint_descriptor *descriptor;
|
||||||
|
uint32 config_index;
|
||||||
|
uint32 interface_index;
|
||||||
|
uint32 endpoint_index;
|
||||||
|
} endpoint;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
usb_string_descriptor *descriptor;
|
||||||
|
uint32 string_index;
|
||||||
|
size_t length;
|
||||||
|
} string;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
usb_descriptor *descriptor;
|
||||||
|
uint32 config_index;
|
||||||
|
uint32 interface_index;
|
||||||
|
uint32 generic_index;
|
||||||
|
size_t length;
|
||||||
|
} generic;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
uint8 type;
|
||||||
|
uint8 index;
|
||||||
|
uint16 language_id;
|
||||||
|
void *data;
|
||||||
|
size_t length;
|
||||||
|
} descriptor;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
uint8 request_type;
|
||||||
|
uint8 request;
|
||||||
|
uint16 value;
|
||||||
|
uint16 index;
|
||||||
|
uint16 length;
|
||||||
|
void *data;
|
||||||
|
} control;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
uint32 interface;
|
||||||
|
uint32 endpoint;
|
||||||
|
void *data;
|
||||||
|
size_t length;
|
||||||
|
} transfer;
|
||||||
|
} raw_command;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const usb_device *device;
|
||||||
|
benaphore lock;
|
||||||
|
|
||||||
|
char name[32];
|
||||||
|
void *link;
|
||||||
|
|
||||||
|
sem_id notify;
|
||||||
|
status_t status;
|
||||||
|
size_t actual_length;
|
||||||
|
|
||||||
|
uint8 buffer[B_PAGE_SIZE];
|
||||||
|
} raw_device;
|
||||||
|
|
||||||
|
#endif // _USB_RAW_H_
|
Loading…
Reference in New Issue
Block a user