* added a kernel driver for Wacom USB tablets.
* the driver should be generic for all Wacom tablets, but there is a special control transfer to put the devices in to "absolute mode", it may not work with future tablets. The driver allows to use read devices, for which there is a special protocol. If the read request has a certain size, then the driver will transmit info on the device, like the vendor and product id as well as the max the packet size, for reads larger than that, it will issue an interrupt transfer and put the raw data received from the device behind the info header git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23666 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -2,3 +2,4 @@ SubDir HAIKU_TOP src add-ons kernel drivers input ;
|
|||||||
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel drivers input ps2_hid ;
|
SubInclude HAIKU_TOP src add-ons kernel drivers input ps2_hid ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel drivers input usb_hid ;
|
SubInclude HAIKU_TOP src add-ons kernel drivers input usb_hid ;
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel drivers input wacom ;
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel drivers input wacom ;
|
||||||
|
|
||||||
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
|
|
||||||
|
SubDirSysHdrs $(HAIKU_TOP) headers os drivers ;
|
||||||
|
|
||||||
|
KernelAddon wacom :
|
||||||
|
wacom.c
|
||||||
|
;
|
||||||
|
|
||||||
|
Package haiku-inputkit-cvs :
|
||||||
|
wacpm :
|
||||||
|
boot home config add-ons kernel drivers bin ;
|
||||||
|
|
||||||
|
PackageDriverSymLink haiku-inputkit-cvs : input wacom ;
|
||||||
|
|
||||||
@@ -0,0 +1,684 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005-2008, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* Portions of this code are based on Be Sample Code released under the
|
||||||
|
* Be Sample Code license. (USB sound device driver sample code IIRC.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <Drivers.h>
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <OS.h>
|
||||||
|
#include <USB3.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define DEBUG_DRIVER 0
|
||||||
|
|
||||||
|
#if DEBUG_DRIVER
|
||||||
|
# define DPRINTF_INFO(x) dprintf x;
|
||||||
|
# define DPRINTF_ERR(x) dprintf x;
|
||||||
|
#else
|
||||||
|
# define DPRINTF_INFO(x)
|
||||||
|
# define DPRINTF_ERR(x) dprintf x;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct wacom_device wacom_device;
|
||||||
|
|
||||||
|
struct wacom_device {
|
||||||
|
wacom_device* next;
|
||||||
|
|
||||||
|
int open;
|
||||||
|
int number;
|
||||||
|
|
||||||
|
usb_device dev;
|
||||||
|
|
||||||
|
usb_pipe pipe;
|
||||||
|
char* data;
|
||||||
|
size_t max_packet_size;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
uint16 vendor;
|
||||||
|
uint16 product;
|
||||||
|
|
||||||
|
sem_id notify_lock;
|
||||||
|
uint32 status;
|
||||||
|
};
|
||||||
|
|
||||||
|
// handy strings for referring to ourself
|
||||||
|
#define ID "wacom: "
|
||||||
|
static const char* kDriverName = "wacom";
|
||||||
|
static const char* kBasePublishPath = "input/wacom/usb/";
|
||||||
|
|
||||||
|
// list of device instances and names for publishing
|
||||||
|
static wacom_device* sDeviceList = NULL;
|
||||||
|
static sem_id sDeviceListLock = -1;
|
||||||
|
static int sDeviceCount = 0;
|
||||||
|
|
||||||
|
static char** sDeviceNames = NULL;
|
||||||
|
|
||||||
|
// handle for the USB bus manager
|
||||||
|
static usb_module_info* usb;
|
||||||
|
|
||||||
|
// These rather inelegant routines are used to assign numbers to
|
||||||
|
// device instances so that they have unique names in devfs.
|
||||||
|
|
||||||
|
static uint32 sDeviceNumbers = 0;
|
||||||
|
|
||||||
|
// get_number
|
||||||
|
static int
|
||||||
|
get_number()
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
|
||||||
|
for (num = 0; num < 32; num++) {
|
||||||
|
if (!(sDeviceNumbers & (1 << num))) {
|
||||||
|
sDeviceNumbers |= (1 << num);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// put_number
|
||||||
|
static void
|
||||||
|
put_number(int num)
|
||||||
|
{
|
||||||
|
sDeviceNumbers &= ~(1 << num);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #pragma mark - Device addition and removal
|
||||||
|
//
|
||||||
|
// add_device() and remove_device() are used to create and tear down
|
||||||
|
// device instances. They are driver by the callbacks device_added()
|
||||||
|
// and device_removed() which are invoked by the USB bus manager.
|
||||||
|
|
||||||
|
// add_device
|
||||||
|
static wacom_device*
|
||||||
|
add_device(usb_device dev)
|
||||||
|
{
|
||||||
|
wacom_device *md = NULL;
|
||||||
|
int num, ifc, alt;
|
||||||
|
const usb_interface_info *ii;
|
||||||
|
status_t st;
|
||||||
|
const usb_device_descriptor* udd;
|
||||||
|
const usb_configuration_info *conf;
|
||||||
|
bool setConfiguration = false;
|
||||||
|
|
||||||
|
// we need these two for a Wacom tablet
|
||||||
|
size_t controlTransferLength;
|
||||||
|
char repData[2] = { 0x02, 0x02 };
|
||||||
|
|
||||||
|
conf = usb->get_configuration(dev);
|
||||||
|
DPRINTF_INFO((ID "add_device(%ld, %p)\n", dev, conf));
|
||||||
|
|
||||||
|
if ((num = get_number()) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
udd = usb->get_device_descriptor(dev);
|
||||||
|
// only pick up wacom tablets
|
||||||
|
if (udd && udd->vendor_id == 0x056a) {
|
||||||
|
|
||||||
|
DPRINTF_ERR((ID "add_device() - wacom detected\n"));
|
||||||
|
|
||||||
|
// see if the device has been configured already
|
||||||
|
if (!conf) {
|
||||||
|
conf = usb->get_nth_configuration(dev, 0);
|
||||||
|
setConfiguration = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conf)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
for (ifc = 0; ifc < conf->interface_count; ifc++) {
|
||||||
|
DPRINTF_INFO((ID "add_device() - examining interface: %d\n", ifc));
|
||||||
|
for (alt = 0; alt < conf->interface[ifc].alt_count; alt++) {
|
||||||
|
ii = &conf->interface[ifc].alt[alt];
|
||||||
|
DPRINTF_INFO((ID "add_device() - examining alt interface: %d\n", alt));
|
||||||
|
|
||||||
|
|
||||||
|
// does it have the correct type of interface?
|
||||||
|
if (ii->descr->interface_class != 3) continue;
|
||||||
|
if (ii->descr->interface_subclass != 1) continue;
|
||||||
|
if (ii->endpoint_count != 1) continue;
|
||||||
|
|
||||||
|
// only accept input endpoints
|
||||||
|
if (ii->endpoint[0].descr->endpoint_address & 0x80) {
|
||||||
|
DPRINTF_INFO((ID "add_device() - found input endpoint\n"));
|
||||||
|
goto got_one;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
put_number(num);
|
||||||
|
if (md) {
|
||||||
|
if (md->data)
|
||||||
|
free(md->data);
|
||||||
|
free(md);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
got_one:
|
||||||
|
if ((md = (wacom_device *) malloc(sizeof(wacom_device))) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
md->dev = dev;
|
||||||
|
md->number = num;
|
||||||
|
md->open = 1;
|
||||||
|
md->notify_lock = -1;
|
||||||
|
md->data = NULL;
|
||||||
|
|
||||||
|
if (setConfiguration) {
|
||||||
|
// the configuration has to be set yet (was not the current one)
|
||||||
|
DPRINTF_INFO((ID "add_device() - setting configuration...\n"));
|
||||||
|
if ((st = usb->set_configuration(dev, conf)) != B_OK) {
|
||||||
|
dprintf(ID "add_device() -> set_configuration() returns %ld\n", st);
|
||||||
|
goto fail;
|
||||||
|
} else
|
||||||
|
DPRINTF_ERR((ID " ... success!\n"));
|
||||||
|
|
||||||
|
if (conf->interface[ifc].active != ii) {
|
||||||
|
// the interface we found is not the active one and has to be set
|
||||||
|
DPRINTF_INFO((ID "add_device() - setting interface: %p...\n", ii));
|
||||||
|
if ((st = usb->set_alt_interface(dev, ii)) != B_OK) {
|
||||||
|
dprintf(ID "add_device() -> set_alt_interface() returns %ld\n", st);
|
||||||
|
goto fail;
|
||||||
|
} else
|
||||||
|
DPRINTF_ERR((ID " ... success!\n"));
|
||||||
|
}
|
||||||
|
// see if the device is a Wacom tablet and needs some special treatment
|
||||||
|
// let's hope Wacom doesn't produce normal mice any time soon, or this
|
||||||
|
// check will have to be more specific about product_id...hehe
|
||||||
|
if (udd->vendor_id == 0x056a) {
|
||||||
|
// do the control transfers to set up absolute mode (default is HID mode)
|
||||||
|
controlTransferLength = 0;
|
||||||
|
st = usb->send_request(dev, 0x21, 0x0b, 1, 0, 0, 0,
|
||||||
|
&controlTransferLength);
|
||||||
|
|
||||||
|
if (st < B_OK)
|
||||||
|
dprintf(ID "add_device() - control transfer 1 failed: %ld\n", st);
|
||||||
|
|
||||||
|
// "set interface" -> ?!?
|
||||||
|
controlTransferLength = 2;
|
||||||
|
st = usb->send_request(dev, 0x21, 0x09, (3 << 8) + 2, 1, 2, repData,
|
||||||
|
&controlTransferLength);
|
||||||
|
|
||||||
|
if (st < B_OK)
|
||||||
|
dprintf(ID "add_device() - control transfer 2 failed: %ld\n", st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure the rest of the wacom_device
|
||||||
|
md->pipe = ii->endpoint[0].handle;
|
||||||
|
//DPRINTF_INFO((ID "add_device() - pipe id = %ld\n", md->pipe));
|
||||||
|
md->length = 0;
|
||||||
|
md->max_packet_size = ii->endpoint[0].descr->max_packet_size;
|
||||||
|
md->data = (char*)malloc(md->max_packet_size);
|
||||||
|
if (md->data == NULL)
|
||||||
|
goto fail;
|
||||||
|
//DPRINTF_INFO((ID "add_device() - max packet length = %ld\n", md->max_packet_size));
|
||||||
|
md->status = 0;//B_USB_STATUS_SUCCESS;
|
||||||
|
md->vendor = udd->vendor_id;
|
||||||
|
md->product = udd->product_id;
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "add_device() - added %p (/dev/%s%d)\n", md, kBasePublishPath, num));
|
||||||
|
|
||||||
|
// add it to the list of devices so it will be published, etc
|
||||||
|
acquire_sem(sDeviceListLock);
|
||||||
|
md->next = sDeviceList;
|
||||||
|
sDeviceList = md;
|
||||||
|
sDeviceCount++;
|
||||||
|
release_sem(sDeviceListLock);
|
||||||
|
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove_device
|
||||||
|
static void
|
||||||
|
remove_device(wacom_device *md)
|
||||||
|
{
|
||||||
|
put_number(md->number);
|
||||||
|
|
||||||
|
usb->cancel_queued_transfers(md->pipe);
|
||||||
|
|
||||||
|
delete_sem(md->notify_lock);
|
||||||
|
if (md->data)
|
||||||
|
free(md->data);
|
||||||
|
free(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
// device_added
|
||||||
|
static status_t
|
||||||
|
device_added(usb_device dev, void** cookie)
|
||||||
|
{
|
||||||
|
wacom_device* md;
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "device_added(%ld,...)\n", dev));
|
||||||
|
|
||||||
|
// first see, if this device is already added
|
||||||
|
acquire_sem(sDeviceListLock);
|
||||||
|
for (md = sDeviceList; md; md = md->next) {
|
||||||
|
DPRINTF_ERR((ID "device_added() - old device: %ld\n", md->dev));
|
||||||
|
if (md->dev == dev) {
|
||||||
|
DPRINTF_ERR((ID "device_added() - already added - done!\n"));
|
||||||
|
*cookie = (void*)md;
|
||||||
|
release_sem(sDeviceListLock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_sem(sDeviceListLock);
|
||||||
|
|
||||||
|
if ((md = add_device(dev)) != NULL) {
|
||||||
|
*cookie = (void*)md;
|
||||||
|
DPRINTF_INFO((ID "device_added() - done!\n"));
|
||||||
|
return B_OK;
|
||||||
|
} else
|
||||||
|
DPRINTF_ERR((ID "device_added() - failed to add device!\n"));
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// device_removed
|
||||||
|
static status_t
|
||||||
|
device_removed(void *cookie)
|
||||||
|
{
|
||||||
|
wacom_device *md = (wacom_device *) cookie;
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "device_removed(%p)\n", md));
|
||||||
|
|
||||||
|
if (md) {
|
||||||
|
|
||||||
|
acquire_sem(sDeviceListLock);
|
||||||
|
|
||||||
|
// remove it from the list of devices
|
||||||
|
if (md == sDeviceList) {
|
||||||
|
sDeviceList = md->next;
|
||||||
|
} else {
|
||||||
|
wacom_device *n;
|
||||||
|
for (n = sDeviceList; n; n = n->next) {
|
||||||
|
if (n->next == md) {
|
||||||
|
n->next = md->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sDeviceCount--;
|
||||||
|
|
||||||
|
// tear it down if it's not open --
|
||||||
|
// otherwise the last device_free() will handle it
|
||||||
|
|
||||||
|
md->open--;
|
||||||
|
|
||||||
|
DPRINTF_ERR((ID "device_removed() open: %d\n", md->open));
|
||||||
|
|
||||||
|
if (md->open == 0) {
|
||||||
|
remove_device(md);
|
||||||
|
} else {
|
||||||
|
dprintf(ID "device /dev/%s%d still open -- marked for removal\n",
|
||||||
|
kBasePublishPath, md->number);
|
||||||
|
}
|
||||||
|
|
||||||
|
release_sem(sDeviceListLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #pragma mark - Device Hooks
|
||||||
|
//
|
||||||
|
// Here we implement the posixy driver hooks (open/close/read/write/ioctl)
|
||||||
|
|
||||||
|
// device_open
|
||||||
|
static status_t
|
||||||
|
device_open(const char *dname, uint32 flags, void **cookie)
|
||||||
|
{
|
||||||
|
wacom_device *md;
|
||||||
|
int n;
|
||||||
|
status_t ret = B_ERROR;
|
||||||
|
|
||||||
|
char controlDevicePath[1024];
|
||||||
|
sprintf(controlDevicePath, "%s%s", kBasePublishPath, "control");
|
||||||
|
if (strcmp(dname, controlDevicePath) == 0) {
|
||||||
|
dprintf(ID "device_open() -> refuse to open control device\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = atoi(dname + strlen(kBasePublishPath));
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "device_open(\"%s\",%d,...)\n", dname, flags));
|
||||||
|
|
||||||
|
acquire_sem(sDeviceListLock);
|
||||||
|
for (md = sDeviceList; md; md = md->next) {
|
||||||
|
if (md->number == n) {
|
||||||
|
// if (md->open <= 1) {
|
||||||
|
md->open++;
|
||||||
|
*cookie = md;
|
||||||
|
DPRINTF_ERR((ID "device_open() open: %d\n", md->open));
|
||||||
|
|
||||||
|
if (md->notify_lock < 0) {
|
||||||
|
if ((md->notify_lock = create_sem(0, "notify_lock")) < 0) {
|
||||||
|
ret = md->notify_lock;
|
||||||
|
md->open--;
|
||||||
|
*cookie = NULL;
|
||||||
|
dprintf(ID "device_open() -> create_sem() returns %ld\n", ret);
|
||||||
|
} else {
|
||||||
|
ret = B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_sem(sDeviceListLock);
|
||||||
|
return ret;
|
||||||
|
// } else {
|
||||||
|
// dprintf(ID "device_open() -> device is already open %ld\n", ret);
|
||||||
|
// release_sem(sDeviceListLock);
|
||||||
|
// return B_ERROR;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_sem(sDeviceListLock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// device_close
|
||||||
|
static status_t
|
||||||
|
device_close (void *cookie)
|
||||||
|
{
|
||||||
|
#if DEBUG_DRIVER
|
||||||
|
wacom_device *md = (wacom_device*) cookie;
|
||||||
|
DPRINTF_ERR((ID "device_close() name = \"%s%d\"\n", kBasePublishPath, md->number));
|
||||||
|
#endif
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// device_free
|
||||||
|
static status_t
|
||||||
|
device_free(void *cookie)
|
||||||
|
{
|
||||||
|
wacom_device *md = (wacom_device *)cookie;
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "device_free() name = \"%s%d\"\n", kBasePublishPath, md->number));
|
||||||
|
|
||||||
|
acquire_sem(sDeviceListLock);
|
||||||
|
|
||||||
|
md->open--;
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "device_free() open: %ld\n", md->open));
|
||||||
|
|
||||||
|
if (md->open == 0) {
|
||||||
|
remove_device(md);
|
||||||
|
}
|
||||||
|
release_sem(sDeviceListLock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// device_interupt_callback
|
||||||
|
static void
|
||||||
|
device_interupt_callback(void* cookie, uint32 status,
|
||||||
|
void* data, uint32 actual_len)
|
||||||
|
{
|
||||||
|
wacom_device* md = (wacom_device*)cookie;
|
||||||
|
uint32 length = min_c(actual_len, md->max_packet_size);
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "device_interupt_callback(%p) name = \"%s%d\" -> "
|
||||||
|
"status: %ld, length: %ld\n", cookie, kBasePublishPath, md->number,
|
||||||
|
status, actual_len));
|
||||||
|
|
||||||
|
md->status = status;
|
||||||
|
if (md->notify_lock >= 0) {
|
||||||
|
if (status == 0/*B_USB_STATUS_SUCCESS*/) {
|
||||||
|
memcpy(md->data, data, length);
|
||||||
|
md->length = length;
|
||||||
|
} else {
|
||||||
|
md->length = 0;
|
||||||
|
}
|
||||||
|
release_sem(md->notify_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "device_interupt_callback() - done\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// read_header
|
||||||
|
static void
|
||||||
|
read_header(const wacom_device* md, void* buffer)
|
||||||
|
{
|
||||||
|
uint16* ids = (uint16*)buffer;
|
||||||
|
uint32* size = (uint32*)buffer;
|
||||||
|
|
||||||
|
ids[0] = md->vendor;
|
||||||
|
ids[1] = md->product;
|
||||||
|
size[1] = md->max_packet_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// device_read
|
||||||
|
static status_t
|
||||||
|
device_read(void* cookie, off_t pos, void* buf, size_t* count)
|
||||||
|
{
|
||||||
|
wacom_device* md = (wacom_device*) cookie;
|
||||||
|
status_t ret = B_BAD_VALUE;
|
||||||
|
uint8* buffer = (uint8*)buf;
|
||||||
|
uint32 dataLength;
|
||||||
|
|
||||||
|
if (!md)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = md->notify_lock;
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "device_read(%p,%Ld,0x%x,%d) name = \"%s%d\"\n",
|
||||||
|
cookie, pos, buf, *count, kBasePublishPath, md->number));
|
||||||
|
|
||||||
|
if (ret >= B_OK) {
|
||||||
|
// what the client "reads" is decided depending on how much bytes are provided
|
||||||
|
// 8 bytes are needed to "read" vendor id, product id and max packet size
|
||||||
|
// in case the client wants to read more than 8 bytes, a usb interupt transfer
|
||||||
|
// is scheduled, and an error report is returned as appropriate
|
||||||
|
if (*count > 8) {
|
||||||
|
// queue the interrupt transfer
|
||||||
|
ret = usb->queue_interrupt(md->pipe, md->data, md->max_packet_size,
|
||||||
|
device_interupt_callback, md);
|
||||||
|
if (ret >= B_OK) {
|
||||||
|
// we will block here until the interrupt transfer has been done
|
||||||
|
ret = acquire_sem_etc(md->notify_lock, 1, B_RELATIVE_TIMEOUT, 500 * 1000);
|
||||||
|
// handle time out
|
||||||
|
if (ret < B_OK) {
|
||||||
|
// usb->cancel_queued_transfers(md->pipe);
|
||||||
|
if (ret == B_TIMED_OUT) {
|
||||||
|
// a time_out is ok, since it only means that the device
|
||||||
|
// had nothing to report (ie mouse/pen was not moved) within
|
||||||
|
// the given time interval
|
||||||
|
DPRINTF_INFO((ID "device_read(%p) name = \"%s%d\" -> "
|
||||||
|
"B_TIMED_OUT\n", cookie, kBasePublishPath, md->number));
|
||||||
|
*count = 8;
|
||||||
|
read_header(md, buffer);
|
||||||
|
ret = B_OK;
|
||||||
|
} else {
|
||||||
|
// any other error trying to acquire the semaphore
|
||||||
|
*count = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (md->status == 0/*B_USBD_SUCCESS*/) {
|
||||||
|
DPRINTF_INFO((ID "interrupt transfer - success\n"));
|
||||||
|
// copy the data from the buffer
|
||||||
|
dataLength = min_c(md->length, *count - 8);
|
||||||
|
*count = dataLength + 8;
|
||||||
|
read_header(md, buffer);
|
||||||
|
memcpy(buffer + 8, md->data, dataLength);
|
||||||
|
} else {
|
||||||
|
// an error happened during the interrupt transfer
|
||||||
|
*count = 0;
|
||||||
|
dprintf(ID "interrupt transfer - failure: %ld\n", md->status);
|
||||||
|
ret = B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*count = 0;
|
||||||
|
dprintf(ID "device_read(%p) name = \"%s%d\" -> error queuing interrupt: %ld\n",
|
||||||
|
cookie, kBasePublishPath, md->number, ret);
|
||||||
|
}
|
||||||
|
} else if (*count == 8) {
|
||||||
|
read_header(md, buffer);
|
||||||
|
ret = B_OK;
|
||||||
|
} else {
|
||||||
|
dprintf(ID "device_read(%p) name = \"%s%d\" -> buffer size must be at least 8 bytes!\n",
|
||||||
|
cookie, kBasePublishPath, md->number);
|
||||||
|
*count = 0;
|
||||||
|
ret = B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// device_write
|
||||||
|
static status_t
|
||||||
|
device_write(void *cookie, off_t pos, const void *buf, size_t *count)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// device_control
|
||||||
|
static status_t
|
||||||
|
device_control (void *cookie, uint32 msg, void *arg1, size_t len)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #pragma mark - Driver Hooks
|
||||||
|
//
|
||||||
|
// These functions provide the glue used by DevFS to load/unload
|
||||||
|
// the driver and also handle registering with the USB bus manager
|
||||||
|
// to receive device added and removed events
|
||||||
|
|
||||||
|
static usb_notify_hooks notify_hooks =
|
||||||
|
{
|
||||||
|
&device_added,
|
||||||
|
&device_removed
|
||||||
|
};
|
||||||
|
|
||||||
|
static const usb_support_descriptor kSupportedDevices[] =
|
||||||
|
{
|
||||||
|
{ 3, 1, 2, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// init_hardware
|
||||||
|
status_t
|
||||||
|
init_hardware(void)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init_driver
|
||||||
|
status_t
|
||||||
|
init_driver(void)
|
||||||
|
{
|
||||||
|
DPRINTF_INFO((ID "init_driver(), built %s %s\n", __DATE__, __TIME__));
|
||||||
|
|
||||||
|
#if DEBUG_DRIVER
|
||||||
|
if (load_driver_symbols(kDriverName) == B_OK) {
|
||||||
|
DPRINTF_INFO((ID "loaded symbols\n"));
|
||||||
|
} else {
|
||||||
|
DPRINTF_ERR((ID "no driver symbols loaded!\n"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (get_module(B_USB_MODULE_NAME, (module_info**) &usb) != B_OK) {
|
||||||
|
DPRINTF_ERR((ID "cannot get module \"%s\"\n", B_USB_MODULE_NAME));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sDeviceListLock = create_sem(1,"sDeviceListLock")) < 0) {
|
||||||
|
put_module(B_USB_MODULE_NAME);
|
||||||
|
return sDeviceListLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb->register_driver(kDriverName, kSupportedDevices, 1, NULL);
|
||||||
|
usb->install_notify(kDriverName, ¬ify_hooks);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// uninit_driver
|
||||||
|
void
|
||||||
|
uninit_driver(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "uninit_driver()\n"));
|
||||||
|
|
||||||
|
usb->uninstall_notify(kDriverName);
|
||||||
|
|
||||||
|
delete_sem(sDeviceListLock);
|
||||||
|
|
||||||
|
put_module(B_USB_MODULE_NAME);
|
||||||
|
|
||||||
|
if (sDeviceNames) {
|
||||||
|
for (i = 0; sDeviceNames[i]; i++)
|
||||||
|
free(sDeviceNames[i]);
|
||||||
|
free(sDeviceNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "uninit_driver() done\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish_devices
|
||||||
|
const char**
|
||||||
|
publish_devices()
|
||||||
|
{
|
||||||
|
wacom_device *md;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DPRINTF_INFO((ID "publish_devices()\n"));
|
||||||
|
|
||||||
|
if (sDeviceNames) {
|
||||||
|
for (i = 0; sDeviceNames[i]; i++)
|
||||||
|
free((char *) sDeviceNames[i]);
|
||||||
|
free(sDeviceNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
acquire_sem(sDeviceListLock);
|
||||||
|
sDeviceNames = (char **) malloc(sizeof(char*) * (sDeviceCount + 2));
|
||||||
|
if (sDeviceNames) {
|
||||||
|
for (i = 0, md = sDeviceList; md; md = md->next) {
|
||||||
|
if ((sDeviceNames[i] = (char *) malloc(strlen(kBasePublishPath) + 4))) {
|
||||||
|
sprintf(sDeviceNames[i],"%s%d",kBasePublishPath,md->number);
|
||||||
|
DPRINTF_INFO((ID "publishing: \"/dev/%s\"\n",sDeviceNames[i]));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// publish the currently fake control device
|
||||||
|
if ((sDeviceNames[i] = (char *) malloc(strlen(kBasePublishPath) + 8))) {
|
||||||
|
sprintf(sDeviceNames[i], "%s%s", kBasePublishPath, "control");
|
||||||
|
}
|
||||||
|
|
||||||
|
sDeviceNames[i + 1] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
release_sem(sDeviceListLock);
|
||||||
|
|
||||||
|
return (const char **) sDeviceNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_hooks sDeviceHooks = {
|
||||||
|
device_open,
|
||||||
|
device_close,
|
||||||
|
device_free,
|
||||||
|
device_control,
|
||||||
|
device_read,
|
||||||
|
device_write
|
||||||
|
};
|
||||||
|
|
||||||
|
// find_device
|
||||||
|
device_hooks*
|
||||||
|
find_device(const char* name)
|
||||||
|
{
|
||||||
|
return &sDeviceHooks;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user