Rewriting the usb_hid driver. It has now gotten a driver part and a device part

structured into the HIDDevice base class and KeyboardDevice and MouseDevice
subclasses. This can be extended easily to support more device types like game
controllers, joysticks and other HID devices. The parsing code remains untouched
while the interpretation code has been integrated into the device classes.
The driver should work much the same way as before including the boot protocol
only keyboard limitation. On the other hand composite devices that combine
multiple devices should now work, as long as they expose those devices as two
seperate interfaces.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25657 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2008-05-25 22:01:08 +00:00
parent e26120ae27
commit 9e48bf8e42
18 changed files with 1663 additions and 1454 deletions
@@ -0,0 +1,50 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <[email protected]>
Distributed under the terms of the MIT license.
*/
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
#ifndef _BEOS_COMPATIBILITY_H_
#define _BEOS_COMPATIBILITY_H_
#include <OS.h>
typedef struct mutex {
sem_id sem;
int32 count;
} mutex;
static inline void
mutex_init(mutex *lock, const char *name)
{
lock->sem = create_sem(0, name);
lock->count = 0;
}
static inline void
mutex_destroy(mutex *lock)
{
delete_sem(lock->sem);
}
static inline status_t
mutex_lock(mutex *lock)
{
if (atomic_add(&lock->count, -1) < 0)
return acquire_sem(lock->sem);
return B_OK;
}
static inline void
mutex_unlock(mutex *lock)
{
if (atomic_add(&lock->count, 1) < -1)
release_sem(lock->sem);
}
#endif /* !HAIKU_TARGET_PLATFORM_HAIKU */
#endif /* _BEOS_COMPATIBILITY_H_ */
@@ -0,0 +1,191 @@
/*
Generic device list for use in drivers.
Copyright (C) 2008 Michael Lotz <[email protected]>
Distributed under the terms of the MIT license.
*/
#include "DeviceList.h"
#include <kernel_cpp.h>
#include <stdlib.h>
#include <string.h>
struct device_list_entry {
char * name;
void * device;
device_list_entry * next;
};
DeviceList::DeviceList()
: fDeviceList(NULL),
fDeviceCount(0),
fPublishList(NULL)
{
}
DeviceList::~DeviceList()
{
_FreePublishList();
device_list_entry *current = fDeviceList;
while (current) {
device_list_entry *next = current->next;
free(current->name);
delete current;
current = next;
}
}
status_t
DeviceList::AddDevice(const char *name, void *device)
{
device_list_entry *entry = new device_list_entry;
if (entry == NULL)
return B_NO_MEMORY;
entry->name = strdup(name);
if (entry->name == NULL)
return B_NO_MEMORY;
entry->device = device;
entry->next = NULL;
if (fDeviceList == NULL)
fDeviceList = entry;
else {
device_list_entry *current = fDeviceList;
while (current) {
if (current->next == NULL) {
current->next = entry;
break;
}
current = current->next;
}
}
fDeviceCount++;
return B_OK;
}
status_t
DeviceList::RemoveDevice(const char *name, void *device)
{
if (name == NULL && device == NULL)
return B_BAD_VALUE;
device_list_entry *previous = NULL;
device_list_entry *current = fDeviceList;
while (current) {
if ((name != NULL && strcmp(current->name, name) == 0)
|| (device != NULL && current->device == device)) {
if (previous == NULL)
fDeviceList = current->next;
else
previous->next = current->next;
free(current->name);
delete current;
fDeviceCount--;
return B_OK;
}
current = current->next;
}
return B_ENTRY_NOT_FOUND;
}
void *
DeviceList::FindDevice(const char *name, void *device)
{
if (name == NULL && device == NULL)
return NULL;
device_list_entry *current = fDeviceList;
while (current) {
if ((name != NULL && strcmp(current->name, name) == 0)
|| (device != NULL && current->device == device))
return current->device;
current = current->next;
}
return NULL;
}
int32
DeviceList::CountDevices(const char *baseName)
{
if (baseName == NULL)
return fDeviceCount;
int32 count = 0;
int32 baseNameLength = strlen(baseName);
device_list_entry *current = fDeviceList;
while (current) {
if (strncmp(current->name, baseName, baseNameLength) == 0)
count++;
current = current->next;
}
return count;
}
void *
DeviceList::DeviceAt(int32 index)
{
device_list_entry *current = fDeviceList;
while (current) {
if (index-- == 0)
return current->device;
current = current->next;
}
return NULL;
}
const char **
DeviceList::PublishDevices()
{
_FreePublishList();
fPublishList = (char **)malloc((fDeviceCount + 1) * sizeof(char *));
if (fPublishList == NULL)
return NULL;
int32 index = 0;
device_list_entry *current = fDeviceList;
while (current) {
fPublishList[index++] = strdup(current->name);
current = current->next;
}
fPublishList[index] = NULL;
return (const char **)fPublishList;
}
void
DeviceList::_FreePublishList()
{
if (fPublishList == NULL)
return;
int32 index = 0;
while (fPublishList[index] != NULL) {
free(fPublishList[index]);
index++;
}
free(fPublishList);
fPublishList = NULL;
}
@@ -0,0 +1,35 @@
/*
Generic device list for use in drivers.
Copyright (C) 2008 Michael Lotz <[email protected]>
Distributed under the terms of the MIT license.
*/
#ifndef _DEVICE_LIST_H_
#define _DEVICE_LIST_H_
#include <OS.h>
struct device_list_entry;
class DeviceList {
public:
DeviceList();
~DeviceList();
status_t AddDevice(const char *name, void *device);
status_t RemoveDevice(const char *name, void *device = NULL);
void * FindDevice(const char *name, void *device = NULL);
int32 CountDevices(const char *baseName = NULL);
void * DeviceAt(int32 index);
const char ** PublishDevices();
private:
void _FreePublishList();
device_list_entry * fDeviceList;
int32 fDeviceCount;
char ** fPublishList;
};
#endif // _DEVICE_LIST_H_
@@ -0,0 +1,293 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <[email protected]>
Distributed under the terms of the MIT license.
Some parts of the code are based on the previous usb_hid driver which
was written by Jérôme Duval.
*/
#include "DeviceList.h"
#include "Driver.h"
#include "HIDDevice.h"
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
#include <lock.h> // for mutex
#else
#include "BeOSCompatibility.h" // for pseudo mutex
#endif
int32 api_version = B_CUR_DRIVER_API_VERSION;
usb_module_info *gUSBModule = NULL;
DeviceList *gDeviceList = NULL;
static int32 sParentCookie = 0;
static mutex sDriverLock;
// #pragma mark - notify hooks
static status_t
usb_hid_device_added(usb_device device, void **cookie)
{
TRACE("device_added()\n");
const usb_device_descriptor *deviceDescriptor
= gUSBModule->get_device_descriptor(device);
TRACE("vendor id: 0x%04x; product id: 0x%04x\n",
deviceDescriptor->vendor_id, deviceDescriptor->product_id);
// wacom devices are handled by the dedicated wacom driver
if (deviceDescriptor->vendor_id == USB_VENDOR_WACOM)
return B_ERROR;
const usb_configuration_info *config
= gUSBModule->get_nth_configuration(device, USB_DEFAULT_CONFIGURATION);
if (config == NULL) {
TRACE_ALWAYS("cannot get default configuration\n");
return B_ERROR;
}
// ensure default configuration is set
status_t result = gUSBModule->set_configuration(device, config);
if (result != B_OK) {
TRACE_ALWAYS("set_configuration() failed 0x%08lx\n", result);
return result;
}
// refresh config
config = gUSBModule->get_configuration(device);
if (config == NULL) {
TRACE_ALWAYS("cannot get current configuration\n");
return B_ERROR;
}
bool devicesFound = false;
int32 parentCookie = atomic_add(&sParentCookie, 1);
for (size_t i = 0; i < config->interface_count; i++) {
const usb_interface_info *interface = config->interface[i].active;
uint8 interfaceClass = interface->descr->interface_class;
uint8 interfaceSubclass = interface->descr->interface_subclass;
uint8 interfaceProtocol = interface->descr->interface_protocol;
TRACE("interface %lu: class: %u; subclass: %u; protocol: %u\n",
i, interfaceClass, interfaceSubclass, interfaceProtocol);
if (interfaceClass == USB_INTERFACE_CLASS_HID
&& interfaceSubclass == USB_INTERFACE_SUBCLASS_HID_BOOT) {
mutex_lock(&sDriverLock);
HIDDevice *hidDevice = HIDDevice::MakeHIDDevice(device, config, i);
if (hidDevice != NULL && hidDevice->InitCheck() == B_OK) {
hidDevice->SetParentCookie(parentCookie);
gDeviceList->AddDevice(hidDevice->Name(), hidDevice);
devicesFound = true;
} else
delete hidDevice;
mutex_unlock(&sDriverLock);
}
}
if (!devicesFound)
return B_ERROR;
*cookie = (void *)parentCookie;
return B_OK;
}
static status_t
usb_hid_device_removed(void *cookie)
{
mutex_lock(&sDriverLock);
int32 parentCookie = (int32)cookie;
TRACE("device_removed(%ld)\n", parentCookie);
for (int32 i = 0; i < gDeviceList->CountDevices(); i++) {
HIDDevice *device = (HIDDevice *)gDeviceList->DeviceAt(i);
if (!device)
continue;
if (device->ParentCookie() == parentCookie) {
// this device belongs to the one removed
if (device->IsOpen()) {
// the device will be deleted upon being freed
device->Removed();
} else {
// remove the device and start over
gDeviceList->RemoveDevice(NULL, device);
i = -1;
}
}
}
mutex_unlock(&sDriverLock);
return B_OK;
}
// #pragma mark - driver hooks
static status_t
usb_hid_open(const char *name, uint32 flags, void **cookie)
{
TRACE("open(%s, %lu, %p)\n", name, flags, cookie);
mutex_lock(&sDriverLock);
HIDDevice *device = (HIDDevice *)gDeviceList->FindDevice(name);
if (device == NULL) {
mutex_unlock(&sDriverLock);
return B_ENTRY_NOT_FOUND;
}
status_t result = device->Open(flags);
*cookie = device;
mutex_unlock(&sDriverLock);
return result;
}
static status_t
usb_hid_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
{
TRACE("read(%p, %Ld, %p, %lu)\n", cookie, position, buffer, *numBytes);
HIDDevice *device = (HIDDevice *)cookie;
return device->Read((uint8 *)buffer, numBytes);
}
static status_t
usb_hid_write(void *cookie, off_t position, const void *buffer,
size_t *numBytes)
{
TRACE("write(%p, %Ld, %p, %lu)\n", cookie, position, buffer, *numBytes);
HIDDevice *device = (HIDDevice *)cookie;
return device->Write((const uint8 *)buffer, numBytes);
}
static status_t
usb_hid_control(void *cookie, uint32 op, void *buffer, size_t length)
{
TRACE("control(%p, %lu, %p, %lu)\n", cookie, op, buffer, length);
HIDDevice *device = (HIDDevice *)cookie;
return device->Control(op, buffer, length);
}
static status_t
usb_hid_close(void *cookie)
{
TRACE("close(%p)\n", cookie);
HIDDevice *device = (HIDDevice *)cookie;
return device->Close();
}
static status_t
usb_hid_free(void *cookie)
{
TRACE("free(%p)\n", cookie);
HIDDevice *device = (HIDDevice *)cookie;
mutex_lock(&sDriverLock);
status_t status = device->Free();
if (gDeviceList->RemoveDevice(NULL, device) == B_OK) {
// the device is removed already but as it was open the removed hook
// has not deleted the object
delete device;
}
mutex_unlock(&sDriverLock);
return status;
}
// #pragma mark - driver API
status_t
init_hardware()
{
TRACE("init_hardware() " __DATE__ " " __TIME__ "\n");
return B_OK;
}
status_t
init_driver()
{
TRACE("init_driver() " __DATE__ " " __TIME__ "\n");
if (get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule) != B_OK)
return B_ERROR;
gDeviceList = new DeviceList();
if (gDeviceList == NULL) {
put_module(B_USB_MODULE_NAME);
return B_NO_MEMORY;
}
static usb_notify_hooks notifyHooks = {
&usb_hid_device_added,
&usb_hid_device_removed
};
static usb_support_descriptor supportDescriptor = {
USB_INTERFACE_CLASS_HID, 0, 0, 0, 0
};
gUSBModule->register_driver(DRIVER_NAME, &supportDescriptor, 1, NULL);
gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
TRACE("init_driver() OK\n");
return B_OK;
}
void
uninit_driver()
{
TRACE("uninit_driver()\n");
gUSBModule->uninstall_notify(DRIVER_NAME);
put_module(B_USB_MODULE_NAME);
delete gDeviceList;
gDeviceList = NULL;
}
const char **
publish_devices()
{
TRACE("publish_devices()\n");
const char **publishList = gDeviceList->PublishDevices();
int32 index = 0;
while (publishList[index] != NULL) {
TRACE("publishing %s\n", publishList[index]);
index++;
}
return publishList;
}
device_hooks *
find_device(const char *name)
{
static device_hooks hooks = {
usb_hid_open,
usb_hid_close,
usb_hid_free,
usb_hid_control,
usb_hid_read,
usb_hid_write,
NULL, /* select */
NULL /* deselect */
};
TRACE("find_device(%s)\n", name);
if (gDeviceList->FindDevice(name) == NULL) {
TRACE_ALWAYS("didn't find device %s\n", name);
return NULL;
}
return &hooks;
}
@@ -0,0 +1,43 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <[email protected]>
Distributed under the terms of the MIT license.
*/
#ifndef _USB_HID_DRIVER_H_
#define _USB_HID_DRIVER_H_
#include <Drivers.h>
#include <KernelExport.h>
#include <OS.h>
#include <USB3.h>
#include "DeviceList.h"
#include "kernel_cpp.h"
#define DRIVER_NAME "usb_hid"
#define USB_INTERFACE_CLASS_HID 3
#define USB_INTERFACE_SUBCLASS_HID_BOOT 1
#define USB_DEFAULT_CONFIGURATION 0
#define USB_VENDOR_WACOM 0x056a
#define USB_HID_DEVICE_TYPE_KEYBOARD 0x06090105
#define USB_HID_DEVICE_TYPE_MOUSE 0x02090105
extern usb_module_info *gUSBModule;
extern DeviceList *gDeviceList;
extern "C" {
status_t usb_hid_device_added(usb_device device, void **cookie);
status_t usb_hid_device_removed(void *cookie);
status_t init_hardware();
void uninit_driver();
const char ** publish_devices();
device_hooks * find_device(const char *name);
}
#define TRACE(x...) /*dprintf(DRIVER_NAME ": " x)*/
#define TRACE_ALWAYS(x...) dprintf(DRIVER_NAME ": " x)
#endif //_USB_HID_DRIVER_H_
@@ -0,0 +1,344 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <[email protected]>
Distributed under the terms of the MIT license.
*/
#include "Driver.h"
#include "HIDDevice.h"
#include <usb/USB_hid.h>
#include <stdio.h>
#include <string.h>
// includes for the different device types
#include "KeyboardDevice.h"
#include "MouseDevice.h"
HIDDevice::HIDDevice(usb_device device, usb_pipe interruptPipe,
size_t interfaceIndex, report_insn *instructions, size_t instructionCount,
size_t totalReportSize, size_t ringBufferSize)
: fStatus(B_NO_INIT),
fDevice(device),
fInterruptPipe(interruptPipe),
fInterfaceIndex(interfaceIndex),
fInstructions(instructions),
fInstructionCount(instructionCount),
fTotalReportSize(totalReportSize),
fTransferUnprocessed(false),
fTransferStatus(B_ERROR),
fTransferActualLength(0),
fTransferBuffer(NULL),
fTransferNotifySem(-1),
fName(NULL),
fParentCookie(-1),
fOpen(false),
fRemoved(false),
fRingBuffer(NULL)
{
if (ringBufferSize > 0)
fRingBuffer = create_ring_buffer(ringBufferSize);
fTransferNotifySem = create_sem(0, "hid device transfer notify sem");
if (fTransferNotifySem < B_OK) {
fStatus = fTransferNotifySem;
return;
}
fTransferBuffer = (uint8 *)malloc(fTotalReportSize);
if (fTransferBuffer == NULL) {
fStatus = B_NO_MEMORY;
return;
}
fStatus = B_OK;
}
HIDDevice::~HIDDevice()
{
if (fRingBuffer) {
delete_ring_buffer(fRingBuffer);
fRingBuffer = NULL;
}
if (fTransferNotifySem >= 0)
delete_sem(fTransferNotifySem);
free(fTransferBuffer);
free(fName);
}
HIDDevice *
HIDDevice::MakeHIDDevice(usb_device device,
const usb_configuration_info *config, size_t interfaceIndex)
{
// read HID descriptor
size_t descriptorLength = sizeof(usb_hid_descriptor);
usb_hid_descriptor *hidDescriptor = (usb_hid_descriptor *)malloc(descriptorLength);
if (hidDescriptor == NULL)
return NULL;
status_t result = gUSBModule->send_request(device,
USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_STANDARD,
USB_REQUEST_GET_DESCRIPTOR,
USB_HID_DESCRIPTOR_HID << 8, interfaceIndex, descriptorLength,
hidDescriptor, &descriptorLength);
TRACE("get_hid_desc: result: 0x%08lx; length: %lu\n", result, descriptorLength);
if (result == B_OK)
descriptorLength = hidDescriptor->descriptor_info[0].descriptor_length;
else
descriptorLength = 256; /* XXX */
free(hidDescriptor);
uint8 *reportDescriptor = (uint8 *)malloc(descriptorLength);
if (reportDescriptor == NULL)
return NULL;
result = gUSBModule->send_request(device,
USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_STANDARD,
USB_REQUEST_GET_DESCRIPTOR,
USB_HID_DESCRIPTOR_REPORT << 8, interfaceIndex, descriptorLength,
reportDescriptor, &descriptorLength);
TRACE("get_hid_rep_desc: result: 0x%08lx; length: %lu\n", result, descriptorLength);
if (result != B_OK) {
free(reportDescriptor);
return NULL;
}
#if 1
// save report descriptor for troubleshooting
const usb_device_descriptor *deviceDescriptor
= gUSBModule->get_device_descriptor(device);
char outputFile[128];
sprintf(outputFile, "/tmp/usb_hid_report_descriptor_%04x_%04x.bin",
deviceDescriptor->vendor_id, deviceDescriptor->product_id);
int fd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd >= 0) {
write(fd, reportDescriptor, descriptorLength);
close(fd);
}
#endif
// decompose report descriptor
size_t itemCount = descriptorLength;
decomp_item *items = (decomp_item *)malloc(sizeof(decomp_item) * itemCount);
if (items == NULL) {
free(reportDescriptor);
return NULL;
}
decompose_report_descriptor(reportDescriptor, descriptorLength, items,
&itemCount);
uint32 deviceType = *(uint32 *)reportDescriptor;
free(reportDescriptor);
// parse report descriptor
size_t instructionCount = itemCount;
report_insn *instructions
= (report_insn *)malloc(sizeof(report_insn) * instructionCount);
if (instructions == NULL) {
free(items);
return NULL;
}
int firstReportID = 0;
size_t totalReportSize = 0;
parse_report_descriptor(items, itemCount, instructions,
&instructionCount, &totalReportSize, &firstReportID);
free(items);
report_insn *finalInstructions = (report_insn *)realloc(instructions,
sizeof(report_insn) * instructionCount);
if (finalInstructions == NULL) {
free(instructions);
return NULL;
}
TRACE("%lu items, %lu instructions, %lu bytes\n", itemCount,
instructionCount, totalReportSize);
// find the interrupt in pipe
usb_pipe interruptPipe = 0;
usb_interface_info *interface = config->interface[interfaceIndex].active;
for (size_t i = 0; i < interface->endpoint_count; i++) {
usb_endpoint_descriptor *descriptor = interface->endpoint[i].descr;
if ((descriptor->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
&& (descriptor->attributes & USB_ENDPOINT_ATTR_MASK) == USB_ENDPOINT_ATTR_INTERRUPT) {
interruptPipe = interface->endpoint[i].handle;
break;
}
}
if (interruptPipe == 0) {
TRACE_ALWAYS("didn't find a suitable interrupt pipe\n");
free(finalInstructions);
return NULL;
}
// determine device type and create the device object
if (deviceType == USB_HID_DEVICE_TYPE_KEYBOARD) {
return new KeyboardDevice(device, interruptPipe, interfaceIndex,
finalInstructions, instructionCount, totalReportSize);
} else if (deviceType == USB_HID_DEVICE_TYPE_MOUSE) {
return new MouseDevice(device, interruptPipe, interfaceIndex,
finalInstructions, instructionCount, totalReportSize);
}
TRACE_ALWAYS("unsupported device type 0x%08lx\n", deviceType);
free(finalInstructions);
return NULL;
}
void
HIDDevice::SetBaseName(const char *baseName)
{
// As devices can be un- and replugged at will, we cannot simply rely on
// a device count. If there is just one keyboard, this does not mean that
// it uses the 0 name. There might have been two keyboards and the one
// using 0 might have been unplugged. So we just generate names until we
// find one that is not currently in use.
int32 index = 0;
char nameBuffer[128];
while (true) {
sprintf(nameBuffer, "%s%ld", baseName, index++);
if (gDeviceList->FindDevice(nameBuffer) == NULL) {
// this name is still free, use it
free(fName);
fName = strdup(nameBuffer);
return;
}
}
}
void
HIDDevice::SetParentCookie(int32 cookie)
{
fParentCookie = cookie;
}
status_t
HIDDevice::Open(uint32 flags)
{
fOpen = true;
return B_OK;
}
status_t
HIDDevice::Close()
{
fOpen = false;
return B_OK;
}
status_t
HIDDevice::Free()
{
return B_OK;
}
status_t
HIDDevice::Read(uint8 *buffer, size_t *numBytes)
{
TRACE_ALWAYS("read on hid device\n");
*numBytes = 0;
return B_ERROR;
}
status_t
HIDDevice::Write(const uint8 *buffer, size_t *numBytes)
{
TRACE_ALWAYS("write on hid device\n");
*numBytes = 0;
return B_ERROR;
}
status_t
HIDDevice::Control(uint32 op, void *buffer, size_t length)
{
TRACE_ALWAYS("control on base class\n");
return B_ERROR;
}
void
HIDDevice::Removed()
{
fRemoved = true;
}
void
HIDDevice::_SetTransferProcessed()
{
fTransferUnprocessed = false;
}
bool
HIDDevice::_IsTransferUnprocessed()
{
return fTransferUnprocessed;
}
status_t
HIDDevice::_ScheduleTransfer()
{
if (fTransferUnprocessed)
return B_BUSY;
status_t result = gUSBModule->queue_interrupt(fInterruptPipe,
fTransferBuffer, fTotalReportSize, _TransferCallback, this);
if (result < B_OK) {
TRACE_ALWAYS("failed to schedule interrupt transfer 0x%08lx\n", result);
return result;
}
fTransferUnprocessed = true;
return B_OK;
}
int32
HIDDevice::_RingBufferReadable()
{
return ring_buffer_readable(fRingBuffer);
}
status_t
HIDDevice::_RingBufferRead(void *buffer, size_t length)
{
ring_buffer_user_read(fRingBuffer, (uint8 *)buffer, length);
return B_OK;
}
status_t
HIDDevice::_RingBufferWrite(const void *buffer, size_t length)
{
ring_buffer_write(fRingBuffer, (const uint8 *)buffer, length);
return B_OK;
}
void
HIDDevice::_TransferCallback(void *cookie, status_t status, void *data,
size_t actualLength)
{
HIDDevice *device = (HIDDevice *)cookie;
device->fTransferStatus = status;
device->fTransferActualLength = actualLength;
release_sem_etc(device->fTransferNotifySem, 1, B_DO_NOT_RESCHEDULE);
}
@@ -0,0 +1,87 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <[email protected]>
Distributed under the terms of the MIT license.
*/
#ifndef _USB_HID_DEVICE_H_
#define _USB_HID_DEVICE_H_
#include "hidparse.h"
#include "ring_buffer.h"
#include <USB3.h>
class HIDDevice {
public:
HIDDevice(usb_device device,
usb_pipe interruptPipe,
size_t interfaceIndex,
report_insn *instructions,
size_t instructionCount,
size_t totalReportSize,
size_t ringBufferSize);
virtual ~HIDDevice();
static HIDDevice * MakeHIDDevice(usb_device device,
const usb_configuration_info *config,
size_t interfaceIndex);
void SetBaseName(const char *baseName);
const char * Name() { return fName; };
void SetParentCookie(int32 cookie);
int32 ParentCookie() { return fParentCookie; };
status_t InitCheck() { return fStatus; };
virtual status_t Open(uint32 flags);
bool IsOpen() { return fOpen; };
virtual status_t Close();
virtual status_t Free();
virtual status_t Read(uint8 *buffer, size_t *numBytes);
virtual status_t Write(const uint8 *buffer, size_t *numBytes);
virtual status_t Control(uint32 op, void *buffer, size_t length);
virtual void Removed();
bool IsRemoved() { return fRemoved; };
protected:
void _SetTransferProcessed();
bool _IsTransferUnprocessed();
status_t _ScheduleTransfer();
int32 _RingBufferReadable();
status_t _RingBufferRead(void *buffer, size_t length);
status_t _RingBufferWrite(const void *buffer,
size_t length);
status_t fStatus;
usb_device fDevice;
usb_pipe fInterruptPipe;
size_t fInterfaceIndex;
report_insn * fInstructions;
size_t fInstructionCount;
size_t fTotalReportSize;
// transfer data
bool fTransferUnprocessed;
status_t fTransferStatus;
size_t fTransferActualLength;
uint8 * fTransferBuffer;
sem_id fTransferNotifySem;
private:
static void _TransferCallback(void *cookie,
status_t status, void *data,
size_t actualLength);
char * fName;
int32 fParentCookie;
bool fOpen;
bool fRemoved;
struct ring_buffer * fRingBuffer;
};
#endif // _USB_HID_DEVICE_H_
@@ -2,6 +2,8 @@ SubDir HAIKU_TOP src add-ons kernel drivers input usb_hid ;
SetSubDirSupportedPlatformsBeOSCompatible ;
SubDirC++Flags -fno-rtti ;
SubDirSysHdrs $(HAIKU_TOP) headers os drivers ;
UsePrivateHeaders [ FDirName kernel util ] input ;
UsePrivateHeaders kernel ;
@@ -12,23 +14,19 @@ if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
}
KernelAddon usb_hid :
hid.c
DeviceList.cpp
Driver.cpp
HIDDevice.cpp
KeyboardDevice.cpp
MouseDevice.cpp
hidparse.c
devlist.c
$(buffer_impl)
;
SEARCH on [ FGristFiles ring_buffer.cpp ] = [ FDirName $(HAIKU_TOP) src system kernel util ] ;
ObjectHdrs [ FGristFiles hid$(SUFOBJ) ]
: [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR) preferences devices ] ;
Includes [ FGristFiles hid.c ] :
<src!preferences!devices>usbdevs.h <src!preferences!devices>usbdevs_data.h ;
Package haiku-inputkit-cvs :
usb_hid :
boot home config add-ons kernel drivers bin ;
PackageDriverSymLink haiku-inputkit-cvs : input usb_hid ;
@@ -0,0 +1,348 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
Distributed under the terms of the MIT license.
Interpretation code based on the previous usb_hid driver which was written
by Jérôme Duval.
*/
#include "Driver.h"
#include "KeyboardDevice.h"
#include <string.h>
#include <usb/USB_hid.h>
// input server private for raw_key_info, KB_READ, etc...
#include "kb_mouse_driver.h"
KeyboardDevice::KeyboardDevice(usb_device device, usb_pipe interruptPipe,
size_t interfaceIndex, report_insn *instructions, size_t instructionCount,
size_t totalReportSize)
: HIDDevice(device, interruptPipe, interfaceIndex, instructions,
instructionCount, totalReportSize, 512),
fRepeatDelay(300000),
fRepeatRate(35000),
fLastTransferBuffer(NULL)
{
fCurrentRepeatDelay = B_INFINITE_TIMEOUT;
fCurrentRepeatKey = 0;
fLastTransferBuffer = (uint8 *)malloc(totalReportSize);
if (fLastTransferBuffer == NULL) {
fStatus = B_NO_MEMORY;
return;
}
SetBaseName("input/keyboard/usb/");
}
KeyboardDevice::~KeyboardDevice()
{
free(fLastTransferBuffer);
}
status_t
KeyboardDevice::Control(uint32 op, void *buffer, size_t length)
{
switch (op) {
case KB_READ:
while (_RingBufferReadable() == 0) {
if (!_IsTransferUnprocessed()) {
status_t result = _ScheduleTransfer();
if (result != B_OK)
return result;
}
// NOTE: this thread is now blocking until the semaphore is
// released from the callback function or the repeat timeout
// expires
status_t result = acquire_sem_etc(fTransferNotifySem, 1,
B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, fCurrentRepeatDelay);
if (result == B_OK) {
result = _InterpretBuffer();
_SetTransferProcessed();
if (result != B_OK)
return result;
} else if (result == B_TIMED_OUT) {
// this case is for handling key repeats, it means
// no interrupt transfer has happened
_WriteKey(fCurrentRepeatKey, true);
// the next timeout is reduced to the repeat_rate
fCurrentRepeatDelay = fRepeatRate;
} else if (result == B_INTERRUPTED)
continue;
else if (result != B_OK)
return result;
}
// process what is in the ring_buffer, it could be written
// there because we handled an interrupt transfer or because
// we wrote the current repeat key
return _RingBufferRead(buffer, sizeof(raw_key_info));
case KB_SET_LEDS:
return _SetLEDs((uint8 *)buffer);
}
TRACE_ALWAYS("keyboard device unhandled control 0x%08lx\n", op);
return B_ERROR;
}
void
KeyboardDevice::_WriteKey(uint32 key, bool down)
{
raw_key_info info;
info.be_keycode = key;
info.is_keydown = down;
info.timestamp = system_time();
_RingBufferWrite(&info, sizeof(raw_key_info));
}
status_t
KeyboardDevice::_SetLEDs(uint8 *data)
{
uint8 leds = 0;
if (data[0] == 1)
leds |= (1 << 0);
if (data[1] == 1)
leds |= (1 << 1);
if (data[2] == 1)
leds |= (1 << 2);
size_t actualLength;
return gUSBModule->send_request(fDevice,
USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_CLASS,
USB_REQUEST_HID_SET_REPORT,
0x200 | 0 /* TODO: report id */, fInterfaceIndex,
sizeof(leds), &leds, &actualLength);
}
status_t
KeyboardDevice::_InterpretBuffer()
{
static uint32 sModifierTable[] = {
KEY_ControlL,
KEY_ShiftL,
KEY_AltL,
KEY_WinL,
KEY_ControlR,
KEY_ShiftR,
KEY_AltR,
KEY_WinR
};
static uint32 sKeyTable[] = {
0x00, // ERROR
0x00, // ERROR
0x00, // ERROR
0x00, // ERROR
0x3c, // A
0x50, // B
0x4e, // C
0x3e, // D
0x29, // E
0x3f, // F
0x40, // G
0x41, // H
0x2e, // I
0x42, // J
0x43, // K
0x44, // L
0x52, // M
0x51, // N
0x2f, // O
0x30, // P
0x27, // Q
0x2a, // R
0x3d, // S
0x2b, // T
0x2d, // U
0x4f, // V
0x28, // W
0x4d, // X
0x2c, // Y
0x4c, // Z
0x12, // 1
0x13, // 2
0x14, // 3
0x15, // 4
0x16, // 5
0x17, // 6
0x18, // 7
0x19, // 8
0x1a, // 9
0x1b, // 0
0x47, // enter
0x01, // Esc
0x1e, // Backspace
0x26, // Tab
0x5e, // Space
0x1c, // -
0x1d, // =
0x31, // [
0x32, // ]
0x00, // unmapped
0x33, // \
0x45, // ;
0x46, // '
0x11, // `
0x53, // ,
0x54, // .
0x55, // /
KEY_CapsLock, // Caps
0x02, // F1
0x03, // F2
0x04, // F3
0x05, // F4
0x06, // F5
0x07, // F6
0x08, // F7
0x09, // F8
0x0a, // F9
0x0b, // F10
0x0c, // F11
0x0d, // F12
0x0e, // PrintScreen
KEY_Scroll, // Scroll Lock
KEY_Pause, // Pause (0x7f with Ctrl)
0x1f, // Insert
0x20, // Home
0x21, // Page up
0x34, // Delete
0x35, // End
0x36, // Page down
0x63, // Right arrow
0x61, // Left arrow
0x62, // Down arrow
0x57, // Up arrow
0x22, // Num Lock
0x23, // Pad /
0x24, // Pad *
0x25, // Pad -
0x3a, // Pad +
0x5b, // Pad Enter
0x58, // Pad 1
0x59, // Pad 2
0x5a, // Pad 3
0x48, // Pad 4
0x49, // Pad 5
0x4a, // Pad 6
0x37, // Pad 7
0x38, // Pad 8
0x39, // Pad 9
0x64, // Pad 0
0x65, // Pad .
0x69, // <
KEY_Menu, // Menu
KEY_Power, // Power
KEY_NumEqual, // Pad =
0x00, // F13 unmapped
0x00, // F14 unmapped
0x00, // F15 unmapped
0x00, // F16 unmapped
0x00, // F17 unmapped
0x00, // F18 unmapped
0x00, // F19 unmapped
0x00, // F20 unmapped
0x00, // F21 unmapped
0x00, // F22 unmapped
0x00, // F23 unmapped
0x00, // F24 unmapped
0x00, // Execute unmapped
0x00, // Help unmapped
0x00, // Menu unmapped
0x00, // Select unmapped
0x00, // Stop unmapped
0x00, // Again unmapped
0x00, // Undo unmapped
0x00, // Cut unmapped
0x00, // Copy unmapped
0x00, // Paste unmapped
0x00, // Find unmapped
0x00, // Mute unmapped
0x00, // Volume up unmapped
0x00, // Volume down unmapped
0x00, // CapsLock unmapped
0x00, // NumLock unmapped
0x00, // Scroll lock unmapped
0x70, // Keypad . on Brazilian ABNT2
0x00, // = sign
0x6b, // Ro (\\ key, japanese)
0x6e, // Katakana/Hiragana, second key right to spacebar, japanese
0x6a, // Yen (macron key, japanese)
0x6d, // Henkan, first key right to spacebar, japanese
0x6c, // Muhenkan, key left to spacebar, japanese
};
static size_t sKeyTableSize = sizeof(sKeyTable) / sizeof(sKeyTable[0]);
uint8 modifierChange = fLastTransferBuffer[0] ^ fTransferBuffer[0];
for (uint8 i = 0; modifierChange; i++, modifierChange >>= 1) {
if (modifierChange & 1)
_WriteKey(sModifierTable[i], (fTransferBuffer[0] >> i) & 1);
}
bool keyDown = false;
uint8 *current = fLastTransferBuffer;
uint8 *compare = fTransferBuffer;
for (int32 twice = 0; twice < 2; twice++) {
for (size_t i = 2; i < fTotalReportSize; i++) {
if (current[i] != 0x00 && current[i] != 0x01) {
bool found = false;
for (size_t j = 2; j < fTotalReportSize; j++) {
if (compare[j] == current[i]) {
found = true;
break;
}
}
if (found)
continue;
// a change occured
uint32 key = 0;
if (current[i] < sKeyTableSize)
key = sKeyTable[current[i]];
if (key == KEY_Pause && (current[0] & 1))
key = KEY_Break;
else if (key == 0xe && (current[0] & 1))
key = KEY_SysRq;
#if HAIKU_TARGET_PLATFORM_HAIKU
else if (keyDown && key == 0x0d) // ToDo: remove again
panic("keyboard requested halt.\n");
#endif
else if (key == 0) {
// unmapped key
key = 0x200000 + current[i];
}
_WriteKey(key, keyDown);
if (keyDown) {
// repeat handling
fCurrentRepeatKey = key;
fCurrentRepeatDelay = fRepeatDelay;
} else {
// cancel the repeats if they are for this key
if (fCurrentRepeatKey == key)
fCurrentRepeatDelay = B_INFINITE_TIMEOUT;
}
} else
break;
}
current = fTransferBuffer;
compare = fLastTransferBuffer;
keyDown = true;
}
memcpy(fLastTransferBuffer, fTransferBuffer, fTotalReportSize);
return B_OK;
}
@@ -0,0 +1,36 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
Distributed under the terms of the MIT license.
*/
#ifndef _USB_KEYBOARD_DEVICE_H_
#define _USB_KEYBOARD_DEVICE_H_
#include "HIDDevice.h"
class KeyboardDevice : public HIDDevice {
public:
KeyboardDevice(usb_device device,
usb_pipe interruptPipe,
size_t interfaceIndex,
report_insn *instructions,
size_t instructionCount,
size_t totalReportSize);
virtual ~KeyboardDevice();
virtual status_t Control(uint32 op, void *buffer, size_t length);
private:
void _WriteKey(uint32 key, bool down);
status_t _SetLEDs(uint8 *data);
status_t _InterpretBuffer();
bigtime_t fRepeatDelay;
bigtime_t fRepeatRate;
bigtime_t fCurrentRepeatDelay;
uint32 fCurrentRepeatKey;
uint8 * fLastTransferBuffer;
};
#endif // _USB_KEYBOARD_DEVICE_H_
@@ -0,0 +1,132 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
Distributed under the terms of the MIT license.
Interpretation code based on the previous usb_hid driver which was written
by Jérôme Duval.
*/
#include "Driver.h"
#include "MouseDevice.h"
#include <string.h>
#include <usb/USB_hid.h>
// input server private for mouse_movement, MS_READ, etc...
#include "kb_mouse_driver.h"
MouseDevice::MouseDevice(usb_device device, usb_pipe interruptPipe,
size_t interfaceIndex, report_insn *instructions, size_t instructionCount,
size_t totalReportSize)
: HIDDevice(device, interruptPipe, interfaceIndex, instructions,
instructionCount, totalReportSize, 512),
fLastButtons(0),
fClickCount(0),
fLastClickTime(0),
fClickSpeed(250000),
fMaxButtons(16)
{
SetBaseName("input/mouse/usb/");
}
status_t
MouseDevice::Control(uint32 op, void *buffer, size_t length)
{
switch (op) {
case MS_READ:
while (_RingBufferReadable() == 0) {
if (!_IsTransferUnprocessed()) {
status_t result = _ScheduleTransfer();
if (result != B_OK)
return result;
}
// NOTE: this thread is now blocking until the semaphore is
// released in the callback function
status_t result = acquire_sem_etc(fTransferNotifySem, 1,
B_CAN_INTERRUPT, 0);
if (result == B_INTERRUPTED)
continue;
else if (result != B_OK)
return result;
result = _InterpretBuffer();
_SetTransferProcessed();
if (result != B_OK)
return result;
}
return _RingBufferRead(buffer, sizeof(mouse_movement));
case MS_NUM_EVENTS:
return _RingBufferReadable() / sizeof(mouse_movement);
case MS_SET_CLICKSPEED:
#ifdef __HAIKU__
return user_memcpy(&fClickSpeed, buffer, sizeof(bigtime_t));
#else
fClickSpeed = *(bigtime_t *)buffer;
return B_OK;
#endif
}
return B_ERROR;
}
status_t
MouseDevice::_InterpretBuffer()
{
mouse_movement info;
memset(&info, 0, sizeof(info));
for (size_t i = 0; i < fInstructionCount; i++) {
const report_insn *instruction = &fInstructions[i];
int32 value = (((fTransferBuffer[instruction->byte_idx + 1] << 8)
| fTransferBuffer[instruction->byte_idx]) >> instruction->bit_pos)
& ((1 << instruction->num_bits) - 1);
switch (instruction->usage_page) {
case USAGE_PAGE_BUTTON:
if (instruction->usage_id - 1 < fMaxButtons)
info.buttons |= (value & 1) << (instruction->usage_id - 1);
break;
case USAGE_PAGE_GENERIC_DESKTOP:
if (instruction->is_phy_signed)
value = sign_extend(value, instruction->num_bits);
switch (instruction->usage_id) {
case USAGE_ID_X:
info.xdelta = value;
break;
case USAGE_ID_Y:
info.ydelta = -value;
break;
case USAGE_ID_WHEEL:
info.wheel_ydelta = -value;
break;
}
break;
}
}
bigtime_t timestamp = system_time();
if (info.buttons != 0) {
if (fLastButtons == 0) {
if (fLastClickTime + fClickSpeed > timestamp)
fClickCount++;
else
fClickCount = 1;
}
fLastClickTime = timestamp;
info.clicks = fClickCount;
}
fLastButtons = info.buttons;
info.timestamp = timestamp;
return _RingBufferWrite(&info, sizeof(mouse_movement));
}
@@ -0,0 +1,32 @@
/*
Driver for USB Human Interface Devices.
Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
Distributed under the terms of the MIT license.
*/
#ifndef _USB_MOUSE_DEVICE_H_
#define _USB_MOUSE_DEVICE_H_
#include "HIDDevice.h"
class MouseDevice : public HIDDevice {
public:
MouseDevice(usb_device device,
usb_pipe interruptPipe,
size_t interfaceIndex,
report_insn *instructions,
size_t instructionCount,
size_t totalReportSize);
virtual status_t Control(uint32 op, void *buffer, size_t length);
private:
status_t _InterpretBuffer();
uint32 fLastButtons;
uint32 fClickCount;
bigtime_t fLastClickTime;
bigtime_t fClickSpeed;
uint32 fMaxButtons;
};
#endif // _USB_MOUSE_DEVICE_H_
@@ -1,128 +0,0 @@
/*
* Copyright 2004-2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*
* Some portions of code are copyrighted by
* USB Joystick driver for BeOS R5
* Copyright 2000 (C) ITO, Takayuki. All rights reserved
*/
#include "hid.h"
#include <stdlib.h>
#include <string.h>
sem_id gDeviceListLock = -1;
bool gDeviceListChanged = true; /* added or removed */
/* dynamically generated */
char **gDeviceNames = NULL;
static hid_device_info *sDeviceList = NULL;
static int sDeviceCount = 0;
void
add_device_info(hid_device_info *device)
{
assert(device != NULL);
acquire_sem(gDeviceListLock);
device->next = sDeviceList;
sDeviceList = device;
sDeviceCount++;
gDeviceListChanged = true;
release_sem(gDeviceListLock);
}
void
remove_device_info(hid_device_info *device)
{
assert(device != NULL);
acquire_sem(gDeviceListLock);
if (sDeviceList == device) {
sDeviceList = device->next;
--sDeviceCount;
gDeviceListChanged = true;
} else {
hid_device_info *previous;
for (previous = sDeviceList; previous != NULL; previous = previous->next) {
if (previous->next == device) {
previous->next = device->next;
--sDeviceCount;
gDeviceListChanged = true;
break;
}
}
assert(previous != NULL);
}
release_sem(gDeviceListLock);
}
hid_device_info *
search_device_info(const char* name)
{
hid_device_info *device;
acquire_sem(gDeviceListLock);
for (device = sDeviceList; device != NULL; device = device->next) {
if (strcmp(device->name, name) == 0)
break;
}
release_sem(gDeviceListLock);
return device;
}
// #pragma mark - device names
void
alloc_device_names(void)
{
assert(gDeviceNames == NULL);
gDeviceNames = malloc(sizeof(char *) * (sDeviceCount + 1));
}
void
free_device_names(void)
{
if (gDeviceNames != NULL) {
int i;
for (i = 0; gDeviceNames [i] != NULL; i++) {
free(gDeviceNames[i]);
}
free(gDeviceNames);
gDeviceNames = NULL;
}
}
void
rebuild_device_names(void)
{
int i;
hid_device_info *device;
assert(gDeviceNames != NULL);
acquire_sem(gDeviceListLock);
for (i = 0, device = sDeviceList; device != NULL; device = device->next) {
gDeviceNames[i++] = strdup(device->name);
DPRINTF_INFO((MY_ID "publishing %s\n", device->name));
}
gDeviceNames[i] = NULL;
release_sem(gDeviceListLock);
}
File diff suppressed because it is too large Load Diff
@@ -1,125 +0,0 @@
/*
* Copyright 2004-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*
* Some portions of code are copyrighted by
* USB Joystick driver for BeOS R5
* Copyright 2000 (C) ITO, Takayuki. All rights reserved
*/
#ifndef _HID_H_
#define _HID_H_
#include "hidparse.h"
#include "ring_buffer.h"
#include <Drivers.h>
#include <USB.h>
#include <usb/USB_hid.h>
#if DEBUG
#define DPRINTF_INFO(x) dprintf x
#define DPRINTF_ERR(x) dprintf x
#else
#define DPRINTF_INFO(x)
#define DPRINTF_ERR(x) dprintf x
#endif
/* driver specific definitions */
#define DRIVER_NAME "usb_hid"
#define MY_ID "\033[34m" DRIVER_NAME ":\033[m "
#define MY_ERR "\033[31merror:\033[m "
#define MY_WARN "\033[31mwarning:\033[m "
#define assert(x) \
((x) ? 0 : dprintf (MY_ID "assertion failed at " __FILE__ ", line %d\n", __LINE__))
/* 0-origin */
#define DEFAULT_CONFIGURATION 0
#define BUF_SIZ B_PAGE_SIZE
struct driver_cookie;
struct hid_repeat_timer {
bigtime_t current_delay;
uint32 key;
};
typedef struct hid_device_info {
/* list structure */
struct hid_device_info *next;
/* maintain device */
sem_id sem_cb;
sem_id sem_lock;
area_id buffer_area;
void *buffer;
uint8 last_buffer[32];
const usb_device *dev;
uint16 ifno;
char name[30];
struct ring_buffer *rbuf;
bool active;
int open;
struct driver_cookie *open_fds;
/* workarea for transfer */
int usbd_status, bus_status, cmd_status;
int actual_length;
const usb_endpoint_info *ept;
bool transfer_scheduled;
report_insn *insns;
size_t num_insns;
size_t total_report_size;
int num_buttons, num_axes, num_hats;
bigtime_t timestamp;
uint flags;
bool is_keyboard;
// double click (please move this into the input_server one day)
uint32 last_buttons;
uint32 click_count;
bigtime_t click_speed;
bigtime_t last_click_time;
// key repeats
struct hid_repeat_timer repeat_timer;
bigtime_t repeat_delay;
bigtime_t repeat_rate;
} hid_device_info;
/* hid.c */
extern usb_module_info* usb;
extern const char* my_driver_name;
extern const char* keyboard_base_name;
extern const char* mouse_base_name;
hid_device_info* create_device(const usb_device *dev,
const usb_interface_info *ii, uint16 ifno, bool is_keyboard);
void delete_device(hid_device_info *device);
/* devlist.c */
extern sem_id gDeviceListLock;
extern bool gDeviceListChanged;
void add_device_info(hid_device_info *device);
void remove_device_info(hid_device_info *device);
hid_device_info *search_device_info(const char *name);
extern char **gDeviceNames;
void alloc_device_names(void);
void free_device_names(void);
void rebuild_device_names(void);
#endif // _HID_H_
@@ -41,6 +41,16 @@
decompose report descriptor into array of uniform structure
*/
int
sign_extend(int value, int size)
{
if (value & (1 << (size - 1)))
return value | (UINT_MAX << size);
return value;
}
int
decompose_report_descriptor(const unsigned char *desc,
size_t desc_len, decomp_item *items, size_t *num_items)
@@ -149,6 +149,12 @@ typedef struct
} report_insn;
#if defined(__cplusplus)
extern "C" {
#endif
int sign_extend(int value, int size);
int decompose_report_descriptor
(const unsigned char *desc,
size_t desc_len,
@@ -162,3 +168,7 @@ int parse_report_descriptor
size_t *num_insns,
size_t *total_report_size,
int *first_report_id);
#if defined(__cplusplus)
}
#endif
@@ -0,0 +1,45 @@
#ifndef _KERNEL_CPP_H_
#define _KERNEL_CPP_H_
#include <malloc.h>
inline void *
operator new(size_t size)
{
return malloc(size);
}
inline void *
operator new[](size_t size)
{
return malloc(size);
}
inline void
operator delete(void *pointer)
{
free(pointer);
}
inline void
operator delete[](void *pointer)
{
free(pointer);
}
inline void
terminate(void)
{
}
static inline void
__throw()
{
}
#endif // _KERNEL_CPP_H_