Commit d96835d3 authored by Vojtech Pavlik's avatar Vojtech Pavlik

[PATCH] Update of USB input drivers to the latest versions

Now that the input core changes have made it into 2.5 I can finally
update the USB input drivers to their latest versions.

Here is a patch that does that.

In detail:

	HID driver:
		Fix a bug in descriptor parsing (array/variable),
			namely visible with Logitech new joysticks and mice
		Fix bugs in logical/physical min/max parsing
		Fix bugs in exponent parsing
		Remove workaround for low-speed devices with >8 byte
			reports, fix this in a correct way (bigger irq
			request)
		Untangle some code (fetc_item())
		Implement asynchronous input/output/feature report
			reading and writing
		Implement (hopefully) proper locking in the above
		Implement support for devices with an output endpoint
		Add some support functions for force feedback support
			currently in development
		Add entries to the debug dump code, including FF and
			exponents
		Add more mappings into the hid-input interface
		Cleanups here and there

	usbkbd driver:

		Make LED URBS use GFP_ATOMIC, they'll be called from a
			completion handler
		Remove dependency on hid.h

	usbmouse driver:

		Just conversion to the new input core, minor cleanups

	wacom driver:

		Just conversion to the new input core.
parent 61251b87
/*
* $Id: hid-core.c,v 1.8 2001/05/23 12:02:18 vojtech Exp $
* $Id: hid-core.c,v 1.42 2002/01/27 00:22:46 vojtech Exp $
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* USB HID support for Linux
*
* Sponsored by SuSE
*/
/*
......@@ -25,8 +23,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/module.h>
......@@ -56,9 +54,10 @@
* Version Information
*/
#define DRIVER_VERSION "v1.8"
#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>"
#define DRIVER_DESC "USB HID support drivers"
#define DRIVER_VERSION "v1.31"
#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL"
static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
......@@ -205,16 +204,11 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
return -1;
}
if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */
if (parser->global.logical_maximum <= parser->global.logical_minimum) {
dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
return -1;
}
usages = parser->local.usage_index;
/* Hint: we can assume usages < MAX_USAGE here */
} else { /* VARIABLE */
usages = parser->global.report_count;
if (parser->global.logical_maximum <= parser->global.logical_minimum) {
dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
return -1;
}
usages = parser->local.usage_index;
offset = report->size;
report->size += parser->global.report_size * parser->global.report_count;
......@@ -311,7 +305,10 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
return 0;
case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
parser->global.logical_maximum = item_sdata(item);
if (parser->global.logical_minimum < 0)
parser->global.logical_maximum = item_sdata(item);
else
parser->global.logical_maximum = item_udata(item);
return 0;
case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
......@@ -319,11 +316,14 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
return 0;
case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
parser->global.physical_maximum = item_sdata(item);
if (parser->global.physical_minimum < 0)
parser->global.physical_maximum = item_sdata(item);
else
parser->global.physical_maximum = item_udata(item);
return 0;
case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
parser->global.unit_exponent = item_udata(item);
parser->global.unit_exponent = item_sdata(item);
return 0;
case HID_GLOBAL_ITEM_TAG_UNIT:
......@@ -508,8 +508,6 @@ static void hid_free_report(struct hid_report *report)
for (n = 0; n < report->maxfield; n++)
kfree(report->field[n]);
if (report->data)
kfree(report->data);
kfree(report);
}
......@@ -538,60 +536,64 @@ static void hid_free_device(struct hid_device *device)
* items, though they are not used yet.
*/
static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
{
if ((end - start) > 0) {
u8 b;
__u8 b = *start++;
item->type = (b >> 2) & 3;
item->tag = (b >> 4) & 15;
if ((end - start) <= 0)
return NULL;
if (item->tag == HID_ITEM_TAG_LONG) {
b = *start++;
item->format = HID_ITEM_FORMAT_LONG;
item->type = (b >> 2) & 3;
item->tag = (b >> 4) & 15;
if ((end - start) >= 2) {
if (item->tag == HID_ITEM_TAG_LONG) {
item->size = *start++;
item->tag = *start++;
item->format = HID_ITEM_FORMAT_LONG;
if ((end - start) >= item->size) {
item->data.longdata = start;
start += item->size;
return start;
}
}
} else {
if ((end - start) < 2)
return NULL;
item->format = HID_ITEM_FORMAT_SHORT;
item->size = b & 3;
switch (item->size) {
case 0:
return start;
case 1:
if ((end - start) >= 1) {
item->data.u8 = *start++;
return start;
}
break;
case 2:
if ((end - start) >= 2) {
item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++));
return start;
}
case 3:
item->size++;
if ((end - start) >= 4) {
item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++));
return start;
}
}
}
item->size = *start++;
item->tag = *start++;
if ((end - start) < item->size)
return NULL;
item->data.longdata = start;
start += item->size;
return start;
}
item->format = HID_ITEM_FORMAT_SHORT;
item->size = b & 3;
switch (item->size) {
case 0:
return start;
case 1:
if ((end - start) < 1)
return NULL;
item->data.u8 = *start++;
return start;
case 2:
if ((end - start) < 2)
return NULL;
item->data.u16 = le16_to_cpu(get_unaligned(((__u16*)start)++));
return start;
case 3:
item->size++;
if ((end - start) < 4)
return NULL;
item->data.u32 = le32_to_cpu(get_unaligned(((__u32*)start)++));
return start;
}
return NULL;
}
......@@ -638,12 +640,14 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
end = start + size;
while ((start = fetch_item(start, end, &item)) != 0) {
if (item.format != HID_ITEM_FORMAT_SHORT) {
dbg("unexpected long global item");
hid_free_device(device);
kfree(parser);
return NULL;
}
if (dispatch_type[item.type](parser, &item)) {
dbg("item %u %u %u %u parsing failed\n",
item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
......@@ -742,7 +746,6 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s
#endif
}
/*
* Analyse a received field, and fetch the data from it. The field
* content is stored for next report processing (we do differential
......@@ -797,9 +800,12 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u
memcpy(field->value, value, count * sizeof(__s32));
}
static int hid_input_report(int type, u8 *data, int len, struct hid_device *hid)
static int hid_input_report(int type, struct urb *urb)
{
struct hid_device *hid = urb->context;
struct hid_report_enum *report_enum = hid->report_enum + type;
u8 *data = urb->transfer_buffer;
int len = urb->actual_length;
struct hid_report *report;
int n, size;
......@@ -818,92 +824,46 @@ static int hid_input_report(int type, u8 *data, int len, struct hid_device *hid)
len--;
}
if (!(report = report_enum->report_id_hash[n])) {
dbg("undefined report_id %d received", n);
#ifdef DEBUG
printk(KERN_DEBUG __FILE__ ": report (size %u) = ", len);
for (n = 0; n < len; n++)
printk(" %02x", data[n]);
printk("\n");
#ifdef DEBUG_DATA
{
int i;
printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);
for (i = 0; i < n; i++)
printk(" %02x", data[i]);
printk("\n");
}
#endif
if (!(report = report_enum->report_id_hash[n])) {
dbg("undefined report_id %d received", n);
return -1;
}
size = ((report->size - 1) >> 3) + 1;
if (len < size) {
if (size <= 8) {
dbg("report %d is too short, (%d < %d)", report->id, len, size);
return -1;
}
/*
* Some low-speed devices have large reports and maxpacketsize 8.
* We buffer the data in that case and parse it when we got it all.
* Works only for unnumbered reports. Doesn't make sense for numbered
* reports anyway - then they don't need to be large.
*/
if (!report->data)
if (!(report->data = kmalloc(size, GFP_ATOMIC))) {
dbg("couldn't allocate report buffer");
return -1;
}
if (report->idx + len > size) {
dbg("report data buffer overflow");
report->idx = 0;
return -1;
}
memcpy(report->data + report->idx, data, len);
report->idx += len;
if (report->idx < size)
return 0;
data = report->data;
dbg("report %d is too short, (%d < %d)", report->id, len, size);
return -1;
}
for (n = 0; n < report->maxfield; n++)
hid_input_field(hid, report->field[n], data);
report->idx = 0;
return 0;
}
/*
* Interrupt input handler.
* Input interrupt completion handler.
*/
static void hid_irq(struct urb *urb)
static void hid_irq_in(struct urb *urb)
{
if (urb->status) {
dbg("nonzero status in irq %d", urb->status);
dbg("nonzero status in input irq %d", urb->status);
return;
}
hid_input_report(HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, urb->context);
}
/*
* hid_read_report() reads in report values without waiting for an irq urb.
*/
void hid_read_report(struct hid_device *hid, struct hid_report *report)
{
int len = ((report->size - 1) >> 3) + 1 + hid->report_enum[report->type].numbered;
u8 data[len];
int read;
if ((read = hid_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, data, len)) != len) {
dbg("reading report type %d id %d failed len %d read %d", report->type + 1, report->id, len, read);
return;
}
hid_input_report(report->type, data, len, hid);
hid_input_report(HID_INPUT_REPORT, urb);
}
/*
......@@ -949,7 +909,8 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
hid_dump_input(field->usage + offset, value);
if (offset >= field->report_count) {
dbg("offset exceeds report_count");
dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
hid_dump_field(field, 8);
return -1;
}
if (field->logical_minimum < 0) {
......@@ -958,11 +919,6 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
return -1;
}
}
if ( (value > field->logical_maximum)
|| (value < field->logical_minimum)) {
dbg("value %d is invalid", value);
return -1;
}
field->value[offset] = value;
return 0;
}
......@@ -986,14 +942,56 @@ int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code,
return -1;
}
/*
* Find a report with a specified HID usage.
*/
int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type)
{
struct hid_report_enum *report_enum = hid->report_enum + type;
struct list_head *list = report_enum->report_list.next;
int i, j;
while (list != &report_enum->report_list) {
*report = (struct hid_report *) list;
list = list->next;
for (i = 0; i < (*report)->maxfield; i++) {
struct hid_field *field = (*report)->field[i];
for (j = 0; j < field->maxusage; j++)
if (field->logical == wanted_usage)
return j;
}
}
return -1;
}
int hid_find_field_in_report(struct hid_report *report, __u32 wanted_usage, struct hid_field **field)
{
int i, j;
for (i = 0; i < report->maxfield; i++) {
*field = report->field[i];
for (j = 0; j < (*field)->maxusage; j++)
if ((*field)->usage[j].hid == wanted_usage)
return j;
}
return -1;
}
static int hid_submit_out(struct hid_device *hid)
{
hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.wLength);
hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
hid->urbout.dev = hid->dev;
struct hid_report *report;
report = hid->out[hid->outtail];
hid_output_report(report, hid->outbuf);
hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1;
hid->urbout->dev = hid->dev;
if (usb_submit_urb(&hid->urbout, GFP_KERNEL)) {
dbg("submitting out urb");
if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) {
err("usb_submit_urb(out) failed");
return -1;
}
......@@ -1001,33 +999,168 @@ static int hid_submit_out(struct hid_device *hid)
return 0;
}
static int hid_submit_ctrl(struct hid_device *hid)
{
struct hid_report *report;
unsigned char dir;
report = hid->ctrl[hid->ctrltail].report;
dir = hid->ctrl[hid->ctrltail].dir;
if (dir == USB_DIR_OUT)
hid_output_report(report, hid->ctrlbuf);
hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + ((report->id > 0) && (dir != USB_DIR_OUT));
hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0);
hid->urbctrl->dev = hid->dev;
hid->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
hid->cr.bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
hid->cr.wValue = ((report->type + 1) << 8) | report->id;
hid->cr.wIndex = cpu_to_le16(hid->ifnum);
hid->cr.wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length);
dbg("submitting ctrl urb");
if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) {
err("usb_submit_urb(ctrl) failed");
return -1;
}
return 0;
}
/*
* Output interrupt completion handler.
*/
static void hid_irq_out(struct urb *urb)
{
struct hid_device *hid = urb->context;
unsigned long flags;
if (urb->status)
warn("output irq status %d received", urb->status);
spin_lock_irqsave(&hid->outlock, flags);
hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
if (hid->outhead != hid->outtail) {
hid_submit_out(hid);
return;
}
clear_bit(HID_OUT_RUNNING, &hid->iofl);
spin_unlock_irqrestore(&hid->outlock, flags);
wake_up(&hid->wait);
}
/*
* Control pipe completion handler.
*/
static void hid_ctrl(struct urb *urb)
{
struct hid_device *hid = urb->context;
unsigned long flags;
if (urb->status)
warn("ctrl urb status %d received", urb->status);
hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
spin_lock_irqsave(&hid->ctrllock, flags);
if (hid->outhead != hid->outtail)
hid_submit_out(hid);
if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb);
hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
if (hid->ctrlhead != hid->ctrltail) {
hid_submit_ctrl(hid);
return;
}
clear_bit(HID_CTRL_RUNNING, &hid->iofl);
spin_unlock_irqrestore(&hid->ctrllock, flags);
wake_up(&hid->wait);
}
void hid_write_report(struct hid_device *hid, struct hid_report *report)
void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
{
hid_output_report(report, hid->out[hid->outhead].buffer);
int head;
unsigned long flags;
hid->out[hid->outhead].dr.wValue = cpu_to_le16(0x200 | report->id);
hid->out[hid->outhead].dr.wLength = cpu_to_le16((report->size + 7) >> 3);
if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
spin_lock_irqsave(&hid->outlock, flags);
if (hid->outhead == hid->outtail)
hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) {
spin_unlock_irqrestore(&hid->outlock, flags);
warn("output queue full");
return;
}
if (hid->urbout.status != -EINPROGRESS)
hid_submit_out(hid);
hid->out[hid->outhead] = report;
hid->outhead = head;
if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl))
hid_submit_out(hid);
spin_unlock_irqrestore(&hid->outlock, flags);
return;
}
spin_lock_irqsave(&hid->ctrllock, flags);
if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) {
spin_unlock_irqrestore(&hid->ctrllock, flags);
warn("control queue full");
return;
}
hid->ctrl[hid->ctrlhead].report = report;
hid->ctrl[hid->ctrlhead].dir = dir;
hid->ctrlhead = head;
if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl))
hid_submit_ctrl(hid);
spin_unlock_irqrestore(&hid->ctrllock, flags);
}
int hid_wait_io(struct hid_device *hid)
{
DECLARE_WAITQUEUE(wait, current);
int timeout = 10*HZ;
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&hid->wait, &wait);
while (timeout && test_bit(HID_CTRL_RUNNING, &hid->iofl) &&
test_bit(HID_OUT_RUNNING, &hid->iofl))
timeout = schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
remove_wait_queue(&hid->wait, &wait);
if (!timeout) {
dbg("timeout waiting for ctrl or out queue to clear");
return -1;
}
return 0;
}
static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
unsigned char type, void *buf, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
(type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT);
}
int hid_open(struct hid_device *hid)
......@@ -1035,9 +1168,9 @@ int hid_open(struct hid_device *hid)
if (hid->open++)
return 0;
hid->urb.dev = hid->dev;
hid->urbin->dev = hid->dev;
if (usb_submit_urb(&hid->urb, GFP_KERNEL))
if (usb_submit_urb(hid->urbin, GFP_KERNEL))
return -EIO;
return 0;
......@@ -1046,30 +1179,52 @@ int hid_open(struct hid_device *hid)
void hid_close(struct hid_device *hid)
{
if (!--hid->open)
usb_unlink_urb(&hid->urb);
usb_unlink_urb(hid->urbin);
}
/*
* Initialize all readable reports
* Initialize all reports
*/
void hid_init_reports(struct hid_device *hid)
{
int i;
struct hid_report *report;
struct hid_report_enum *report_enum;
struct hid_report *report;
struct list_head *list;
int len;
for (i = 0; i < HID_REPORT_TYPES; i++) {
if (i == HID_FEATURE_REPORT || i == HID_INPUT_REPORT) {
report_enum = hid->report_enum + i;
list = report_enum->report_list.next;
while (list != &report_enum->report_list) {
report = (struct hid_report *) list;
hid_set_idle(hid->dev, hid->ifnum, 0, report->id);
hid_read_report(hid, report);
list = list->next;
}
}
report_enum = hid->report_enum + HID_INPUT_REPORT;
list = report_enum->report_list.next;
while (list != &report_enum->report_list) {
report = (struct hid_report *) list;
hid_submit_report(hid, report, USB_DIR_IN);
list = list->next;
}
report_enum = hid->report_enum + HID_FEATURE_REPORT;
list = report_enum->report_list.next;
while (list != &report_enum->report_list) {
report = (struct hid_report *) list;
hid_submit_report(hid, report, USB_DIR_IN);
list = list->next;
}
if (hid_wait_io(hid)) {
warn("timeout initializing reports\n");
return;
}
report_enum = hid->report_enum + HID_INPUT_REPORT;
list = report_enum->report_list.next;
while (list != &report_enum->report_list) {
report = (struct hid_report *) list;
len = ((report->size - 1) >> 3) + 1 + report_enum->numbered;
if (len > hid->urbin->transfer_buffer_length)
hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE;
usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id,
hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
list = list->next;
}
}
......@@ -1077,6 +1232,10 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010
#define USB_DEVICE_ID_WACOM_INTUOS 0x0020
#define USB_VENDOR_ID_GRIFFIN 0x077d
#define USB_DEVICE_ID_POWERMATE 0x0410
#define USB_DEVICE_ID_SOUNDKNOB 0x04AA
struct hid_blacklist {
__u16 idVendor;
__u16 idProduct;
......@@ -1087,19 +1246,11 @@ struct hid_blacklist {
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB },
{ 0, 0 }
};
static int get_class_descriptor(struct usb_device *dev, int ifnum,
unsigned char type, void *buf, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
(type << 8), ifnum, buf, size,
HZ * USB_CTRL_GET_TIMEOUT);
}
static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
{
struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;
......@@ -1131,7 +1282,7 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
{
__u8 rdesc[rsize];
if ((n = get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
if ((n = hid_get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
dbg("reading report descriptor failed");
return NULL;
}
......@@ -1152,73 +1303,83 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
for (n = 0; n < interface->bNumEndpoints; n++) {
struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n];
int pipe, maxp;
int pipe;
if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */
continue;
if (!(endpoint->bEndpointAddress & 0x80)) /* Not an input endpoint */
continue;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval);
break;
if (endpoint->bEndpointAddress & USB_DIR_IN) {
if (hid->urbin)
continue;
if (!(hid->urbin = usb_alloc_urb(0)))
goto fail;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
FILL_INT_URB(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval);
} else {
if (hid->urbout)
continue;
if (!(hid->urbout = usb_alloc_urb(0)))
goto fail;
pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress);
FILL_BULK_URB(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid);
}
}
if (n == interface->bNumEndpoints) {
dbg("couldn't find an input interrupt endpoint");
hid_free_device(hid);
return NULL;
if (!hid->urbin) {
err("couldn't find an input interrupt endpoint");
goto fail;
}
init_waitqueue_head(&hid->wait);
hid->outlock = SPIN_LOCK_UNLOCKED;
hid->ctrllock = SPIN_LOCK_UNLOCKED;
hid->version = hdesc->bcdHID;
hid->country = hdesc->bCountryCode;
hid->dev = dev;
hid->ifnum = interface->bInterfaceNumber;
for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
hid->out[n].dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
hid->out[n].dr.bRequest = HID_REQ_SET_REPORT;
hid->out[n].dr.wIndex = cpu_to_le16(hid->ifnum);
}
hid->name[0] = 0;
if (!(buf = kmalloc(63, GFP_KERNEL)))
return NULL;
if (!(buf = kmalloc(64, GFP_KERNEL)))
goto fail;
if (usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) {
if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) {
strcat(hid->name, buf);
if (usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0)
sprintf(hid->name, "%s %s", hid->name, buf);
} else
sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
kfree(buf);
usb_make_path(dev, buf, 63);
sprintf(hid->phys, "%s/input%d", buf, ifnum);
FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0),
(void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid);
if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
hid->uniq[0] = 0;
/*
* Some devices don't like this and crash. I don't know of any devices
* needing this, so it is disabled for now.
*/
kfree(buf);
#if 0
if (interface->bInterfaceSubClass == 1)
hid_set_protocol(dev, hid->ifnum, 1);
#endif
hid->urbctrl = usb_alloc_urb(0);
FILL_CONTROL_URB(hid->urbctrl, dev, 0, (void*) &hid->cr, hid->ctrlbuf, 1, hid_ctrl, hid);
return hid;
fail:
hid_free_device(hid);
if (hid->urbin) usb_free_urb(hid->urbin);
if (hid->urbout) usb_free_urb(hid->urbout);
if (hid->urbctrl) usb_free_urb(hid->urbctrl);
return NULL;
}
static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
struct hid_device *hid;
char path[64];
int i;
char *c;
......@@ -1236,10 +1397,16 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
if (!hiddev_connect(hid))
hid->claimed |= HID_CLAIMED_HIDDEV;
#endif
if (!hid->claimed) {
hid_free_device(hid);
return NULL;
}
printk(KERN_INFO);
if (hid->claimed & HID_CLAIMED_INPUT)
printk("input%d", hid->input.number);
printk("input");
if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
printk(",");
if (hid->claimed & HID_CLAIMED_HIDDEV)
......@@ -1252,9 +1419,10 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
break;
}
printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n",
hid->version >> 8, hid->version & 0xff, c, hid->name,
dev->bus->busnum, dev->devnum, ifnum);
usb_make_path(dev, path, 63);
printk(": USB HID v%x.%02x %s [%s] on %s\n",
hid->version >> 8, hid->version & 0xff, c, hid->name, path);
return hid;
}
......@@ -1264,7 +1432,14 @@ static void hid_disconnect(struct usb_device *dev, void *ptr)
struct hid_device *hid = ptr;
dbg("cleanup called");
usb_unlink_urb(&hid->urb);
usb_unlink_urb(hid->urbin);
usb_unlink_urb(hid->urbout);
usb_unlink_urb(hid->urbctrl);
usb_free_urb(hid->urbin);
usb_free_urb(hid->urbctrl);
if (hid->urbout)
usb_free_urb(hid->urbout);
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hid);
......@@ -1276,8 +1451,7 @@ static void hid_disconnect(struct usb_device *dev, void *ptr)
}
static struct usb_device_id hid_usb_ids [] = {
{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
bInterfaceClass: USB_INTERFACE_CLASS_HID },
{ bInterfaceClass: USB_INTERFACE_CLASS_HID },
{ } /* Terminating entry */
};
......@@ -1296,8 +1470,7 @@ static int __init hid_init(void)
hiddev_init();
#endif
usb_register(&hid_driver);
info(DRIVER_VERSION " " DRIVER_AUTHOR);
info(DRIVER_DESC);
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
}
......@@ -1313,6 +1486,6 @@ static void __exit hid_exit(void)
module_init(hid_init);
module_exit(hid_exit);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
/*
* $Id: hid-debug.h,v 1.3 2001/05/10 15:56:07 vojtech Exp $
* $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
*
* (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de>
* (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
* (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
*
* Some debug stuff for the HID parser.
*
* Sponsored by SuSE
*/
/*
......@@ -25,8 +23,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
struct hid_usage_entry {
......@@ -36,6 +34,7 @@ struct hid_usage_entry {
};
static struct hid_usage_entry hid_usage_table[] = {
{ 0, 0, "Undefined" },
{ 1, 0, "GenericDesktop" },
{0, 0x01, "Pointer"},
{0, 0x02, "Mouse"},
......@@ -87,6 +86,7 @@ static struct hid_usage_entry hid_usage_table[] = {
{ 7, 0, "Keyboard" },
{ 8, 0, "LED" },
{ 9, 0, "Button" },
{ 10, 0, "Ordinal" },
{ 12, 0, "Hotkey" },
{ 13, 0, "Digitizers" },
{0, 0x01, "Digitizer"},
......@@ -112,6 +112,112 @@ static struct hid_usage_entry hid_usage_table[] = {
{0, 0x45, "Eraser"},
{0, 0x46, "TabletPick"},
{ 15, 0, "PhysicalInterfaceDevice" },
{0, 0x00, "Undefined"},
{0, 0x01, "Physical_Interface_Device"},
{0, 0x20, "Normal"},
{0, 0x21, "Set_Effect_Report"},
{0, 0x22, "Effect_Block_Index"},
{0, 0x23, "Parameter_Block_Offset"},
{0, 0x24, "ROM_Flag"},
{0, 0x25, "Effect_Type"},
{0, 0x26, "ET_Constant_Force"},
{0, 0x27, "ET_Ramp"},
{0, 0x28, "ET_Custom_Force_Data"},
{0, 0x30, "ET_Square"},
{0, 0x31, "ET_Sine"},
{0, 0x32, "ET_Triangle"},
{0, 0x33, "ET_Sawtooth_Up"},
{0, 0x34, "ET_Sawtooth_Down"},
{0, 0x40, "ET_Spring"},
{0, 0x41, "ET_Damper"},
{0, 0x42, "ET_Inertia"},
{0, 0x43, "ET_Friction"},
{0, 0x50, "Duration"},
{0, 0x51, "Sample_Period"},
{0, 0x52, "Gain"},
{0, 0x53, "Trigger_Button"},
{0, 0x54, "Trigger_Repeat_Interval"},
{0, 0x55, "Axes_Enable"},
{0, 0x56, "Direction_Enable"},
{0, 0x57, "Direction"},
{0, 0x58, "Type_Specific_Block_Offset"},
{0, 0x59, "Block_Type"},
{0, 0x5A, "Set_Envelope_Report"},
{0, 0x5B, "Attack_Level"},
{0, 0x5C, "Attack_Time"},
{0, 0x5D, "Fade_Level"},
{0, 0x5E, "Fade_Time"},
{0, 0x5F, "Set_Condition_Report"},
{0, 0x60, "CP_Offset"},
{0, 0x61, "Positive_Coefficient"},
{0, 0x62, "Negative_Coefficient"},
{0, 0x63, "Positive_Saturation"},
{0, 0x64, "Negative_Saturation"},
{0, 0x65, "Dead_Band"},
{0, 0x66, "Download_Force_Sample"},
{0, 0x67, "Isoch_Custom_Force_Enable"},
{0, 0x68, "Custom_Force_Data_Report"},
{0, 0x69, "Custom_Force_Data"},
{0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
{0, 0x6B, "Set_Custom_Force_Report"},
{0, 0x6C, "Custom_Force_Data_Offset"},
{0, 0x6D, "Sample_Count"},
{0, 0x6E, "Set_Periodic_Report"},
{0, 0x6F, "Offset"},
{0, 0x70, "Magnitude"},
{0, 0x71, "Phase"},
{0, 0x72, "Period"},
{0, 0x73, "Set_Constant_Force_Report"},
{0, 0x74, "Set_Ramp_Force_Report"},
{0, 0x75, "Ramp_Start"},
{0, 0x76, "Ramp_End"},
{0, 0x77, "Effect_Operation_Report"},
{0, 0x78, "Effect_Operation"},
{0, 0x79, "Op_Effect_Start"},
{0, 0x7A, "Op_Effect_Start_Solo"},
{0, 0x7B, "Op_Effect_Stop"},
{0, 0x7C, "Loop_Count"},
{0, 0x7D, "Device_Gain_Report"},
{0, 0x7E, "Device_Gain"},
{0, 0x7F, "PID_Pool_Report"},
{0, 0x80, "RAM_Pool_Size"},
{0, 0x81, "ROM_Pool_Size"},
{0, 0x82, "ROM_Effect_Block_Count"},
{0, 0x83, "Simultaneous_Effects_Max"},
{0, 0x84, "Pool_Alignment"},
{0, 0x85, "PID_Pool_Move_Report"},
{0, 0x86, "Move_Source"},
{0, 0x87, "Move_Destination"},
{0, 0x88, "Move_Length"},
{0, 0x89, "PID_Block_Load_Report"},
{0, 0x8B, "Block_Load_Status"},
{0, 0x8C, "Block_Load_Success"},
{0, 0x8D, "Block_Load_Full"},
{0, 0x8E, "Block_Load_Error"},
{0, 0x8F, "Block_Handle"},
{0, 0x90, "PID_Block_Free_Report"},
{0, 0x91, "Type_Specific_Block_Handle"},
{0, 0x92, "PID_State_Report"},
{0, 0x94, "Effect_Playing"},
{0, 0x95, "PID_Device_Control_Report"},
{0, 0x96, "PID_Device_Control"},
{0, 0x97, "DC_Enable_Actuators"},
{0, 0x98, "DC_Disable_Actuators"},
{0, 0x99, "DC_Stop_All_Effects"},
{0, 0x9A, "DC_Device_Reset"},
{0, 0x9B, "DC_Device_Pause"},
{0, 0x9C, "DC_Device_Continue"},
{0, 0x9F, "Device_Paused"},
{0, 0xA0, "Actuators_Enabled"},
{0, 0xA4, "Safety_Switch"},
{0, 0xA5, "Actuator_Override_Switch"},
{0, 0xA6, "Actuator_Power"},
{0, 0xA7, "Start_Delay"},
{0, 0xA8, "Parameter_Block_Size"},
{0, 0xA9, "Device_Managed_Pool"},
{0, 0xAA, "Shared_Parameter_Blocks"},
{0, 0xAB, "Create_New_Effect_Report"},
{0, 0xAC, "RAM_Pool_Available"},
{ 0, 0, NULL }
};
......@@ -176,7 +282,50 @@ static void hid_dump_field(struct hid_field *field, int n) {
tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
}
if (field->unit) {
tab(n); printk("Unit(%u)\n", field->unit);
char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
char *units[5][8] = {
{ "None", "None", "None", "None", "None", "None", "None", "None" },
{ "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
{ "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
{ "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
{ "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
};
int i;
int sys;
__u32 data = field->unit;
/* First nibble tells us which system we're in. */
sys = data & 0xf;
data >>= 4;
if(sys > 4) {
tab(n); printk("Unit(Invalid)\n");
}
else {
int earlier_unit = 0;
tab(n); printk("Unit(%s : ", systems[sys]);
for (i=1 ; i<sizeof(__u32)*2 ; i++) {
char nibble = data & 0xf;
data >>= 4;
if (nibble != 0) {
if(earlier_unit++ > 0)
printk("*");
printk("%s", units[sys][i]);
if(nibble != 1) {
/* This is a _signed_ nibble(!) */
int val = nibble & 0x7;
if(nibble & 0x08)
val = -((0x7 & ~val) +1);
printk("^%d", val);
}
}
}
printk(")\n");
}
}
tab(n); printk("Report Size(%u)\n", field->report_size);
tab(n); printk("Report Count(%u)\n", field->report_count);
......
/*
* $Id: hid-input.c,v 1.5 2001/05/23 09:25:02 vojtech Exp $
* $Id: hid-input.c,v 1.18 2001/11/07 09:01:18 vojtech Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* USB HID to Linux Input mapping module
*
* Sponsored by SuSE
* USB HID to Linux Input mapping
*/
/*
......@@ -24,13 +22,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/usb.h>
......@@ -61,12 +58,13 @@ static unsigned char hid_keyboard[256] = {
static struct {
__s32 x;
__s32 y;
} hid_hat_to_axis[] = {{0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
static void hidinput_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage)
{
struct input_dev *input = &device->input;
int max;
int is_abs = 0;
unsigned long *bit;
switch (usage->hid & HID_USAGE_PAGE) {
......@@ -198,6 +196,7 @@ static void hidinput_configure_usage(struct hid_device *device, struct hid_field
case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
set_bit(EV_REP, input->evbit);
switch (usage->hid & HID_USAGE) {
case 0x000: usage->code = 0; break;
case 0x034: usage->code = KEY_SLEEP; break;
......@@ -205,14 +204,21 @@ static void hidinput_configure_usage(struct hid_device *device, struct hid_field
case 0x08a: usage->code = KEY_WWW; break;
case 0x095: usage->code = KEY_HELP; break;
case 0x0b0: usage->code = KEY_PLAY; break;
case 0x0b1: usage->code = KEY_PAUSE; break;
case 0x0b2: usage->code = KEY_RECORD; break;
case 0x0b3: usage->code = KEY_FASTFORWARD; break;
case 0x0b4: usage->code = KEY_REWIND; break;
case 0x0b5: usage->code = KEY_NEXTSONG; break;
case 0x0b6: usage->code = KEY_PREVIOUSSONG; break;
case 0x0b7: usage->code = KEY_STOPCD; break;
case 0x0b8: usage->code = KEY_EJECTCD; break;
case 0x0cd: usage->code = KEY_PLAYPAUSE; break;
case 0x0e0: is_abs = 1;
usage->code = ABS_VOLUME;
break;
case 0x0e2: usage->code = KEY_MUTE; break;
case 0x0e5: usage->code = KEY_BASSBOOST; break;
case 0x0e9: usage->code = KEY_VOLUMEUP; break;
case 0x0ea: usage->code = KEY_VOLUMEDOWN; break;
......@@ -220,7 +226,6 @@ static void hidinput_configure_usage(struct hid_device *device, struct hid_field
case 0x18a: usage->code = KEY_MAIL; break;
case 0x192: usage->code = KEY_CALC; break;
case 0x194: usage->code = KEY_FILE; break;
case 0x21a: usage->code = KEY_UNDO; break;
case 0x21b: usage->code = KEY_COPY; break;
case 0x21c: usage->code = KEY_CUT; break;
......@@ -234,6 +239,34 @@ static void hidinput_configure_usage(struct hid_device *device, struct hid_field
case 0x227: usage->code = KEY_REFRESH; break;
case 0x22a: usage->code = KEY_BOOKMARKS; break;
default: usage->code = KEY_UNKNOWN; break;
}
if (is_abs) {
usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
} else {
usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
}
break;
case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
set_bit(EV_REP, input->evbit);
switch (usage->hid & HID_USAGE) {
case 0x021: usage->code = KEY_PRINT; break;
case 0x070: usage->code = KEY_HP; break;
case 0x071: usage->code = KEY_CAMERA; break;
case 0x072: usage->code = KEY_SOUND; break;
case 0x073: usage->code = KEY_QUESTION; break;
case 0x080: usage->code = KEY_EMAIL; break;
case 0x081: usage->code = KEY_CHAT; break;
case 0x082: usage->code = KEY_SEARCH; break;
case 0x083: usage->code = KEY_CONNECT; break;
case 0x084: usage->code = KEY_FINANCE; break;
case 0x085: usage->code = KEY_SPORT; break;
case 0x086: usage->code = KEY_SHOP; break;
default: usage->code = KEY_UNKNOWN; break;
}
......@@ -353,7 +386,7 @@ static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsign
}
hid_set_field(field, offset, value);
hid_write_report(hid, field->report);
hid_submit_report(hid, field->report, USB_DIR_OUT);
return 0;
}
......@@ -397,6 +430,8 @@ int hidinput_connect(struct hid_device *hid)
hid->input.close = hidinput_close;
hid->input.name = hid->name;
hid->input.phys = hid->phys;
hid->input.uniq = hid->uniq;
hid->input.idbus = BUS_USB;
hid->input.idvendor = dev->descriptor.idVendor;
hid->input.idproduct = dev->descriptor.idProduct;
......
......@@ -2,12 +2,10 @@
#define __HID_H
/*
* $Id: hid.h,v 1.10 2001/05/10 15:56:07 vojtech Exp $
* $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Sponsored by SuSE
*/
/*
......@@ -26,13 +24,24 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/list.h>
/*
* USB HID (Human Interface Device) interface class code
*/
#define USB_INTERFACE_CLASS_HID 3
/*
* HID class requests
*/
#define HID_REQ_GET_REPORT 0x01
#define HID_REQ_GET_IDLE 0x02
#define HID_REQ_GET_PROTOCOL 0x03
......@@ -43,85 +52,11 @@
/*
* HID class descriptor types
*/
#define HID_DT_HID (USB_TYPE_CLASS | 0x01)
#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02)
#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
/*
* Utilities for class control messaging
*/
static inline int
hid_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(duration << 8) | report_id, ifnum, NULL, 0,
HZ * USB_CTRL_SET_TIMEOUT);
}
static inline int
hid_get_protocol(struct usb_device *dev, int ifnum)
{
unsigned char type;
int ret;
if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
HID_REQ_GET_PROTOCOL,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, ifnum, &type, 1,
HZ * USB_CTRL_GET_TIMEOUT)) < 0)
return ret;
return type;
}
static inline int
hid_set_protocol(struct usb_device *dev, int ifnum, int protocol)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
protocol, ifnum, NULL, 0,
HZ * USB_CTRL_SET_TIMEOUT);
}
static inline int
hid_get_report(struct usb_device *dev, int ifnum, unsigned char type,
unsigned char id, void *buf, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
HID_REQ_GET_REPORT,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id, ifnum, buf, size,
HZ * USB_CTRL_GET_TIMEOUT);
}
static inline int
hid_set_report(struct usb_device *dev, int ifnum, unsigned char type,
unsigned char id, void *buf, int size)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id, ifnum, buf, size, HZ);
// FIXME USB_CTRL_SET_TIMEOUT
}
/*
* "Boot Protocol" keyboard/mouse drivers use don't use all of HID;
* they're a lot smaller but can't support all the device features.
*/
#ifndef _HID_BOOT_PROTOCOL
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/list.h>
/*
* USB HID (Human Interface Device) interface class code
*/
#define USB_INTERFACE_CLASS_HID 3
/*
* We parse each description item into this structure. Short items data
* values are expanded to 32-bit signed int, long items contain a pointer
......@@ -240,9 +175,11 @@ struct hid_item {
#define HID_UP_KEYBOARD 0x00070000
#define HID_UP_LED 0x00080000
#define HID_UP_BUTTON 0x00090000
#define HID_UP_ORDINAL 0x000a0000
#define HID_UP_CONSUMER 0x000c0000
#define HID_UP_DIGITIZER 0x000d0000
#define HID_UP_PID 0x000f0000
#define HID_UP_HPVENDOR 0xff7f0000
#define HID_USAGE 0x0000ffff
......@@ -279,7 +216,7 @@ struct hid_global {
__s32 logical_maximum;
__s32 physical_minimum;
__s32 physical_maximum;
unsigned unit_exponent;
__s32 unit_exponent;
unsigned unit;
unsigned report_id;
unsigned report_size;
......@@ -336,7 +273,7 @@ struct hid_field {
__s32 logical_maximum;
__s32 physical_minimum;
__s32 physical_maximum;
unsigned unit_exponent;
__s32 unit_exponent;
unsigned unit;
struct hid_report *report; /* associated report */
};
......@@ -350,8 +287,6 @@ struct hid_report {
struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */
unsigned maxfield; /* maximum valid field index */
unsigned size; /* size of the report (bits) */
unsigned idx; /* where we're in data */
unsigned char *data; /* data for multi-packet reports */
struct hid_device *device; /* associated device */
};
......@@ -364,16 +299,20 @@ struct hid_report_enum {
#define HID_REPORT_TYPES 3
#define HID_BUFFER_SIZE 32
#define HID_CONTROL_FIFO_SIZE 8
#define HID_CONTROL_FIFO_SIZE 64
#define HID_OUTPUT_FIFO_SIZE 64
struct hid_control_fifo {
struct usb_ctrlrequest dr;
char buffer[HID_BUFFER_SIZE];
unsigned char dir;
struct hid_report *report;
};
#define HID_CLAIMED_INPUT 1
#define HID_CLAIMED_HIDDEV 2
#define HID_CTRL_RUNNING 1
#define HID_OUT_RUNNING 2
struct hid_device { /* device report descriptor */
__u8 *rdesc;
unsigned rsize;
......@@ -386,12 +325,23 @@ struct hid_device { /* device report descriptor */
struct usb_device *dev; /* USB device */
int ifnum; /* USB interface number */
struct urb urb; /* USB URB structure */
char buffer[HID_BUFFER_SIZE]; /* Rx buffer */
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
struct urb *urbin; /* Input URB */
char inbuf[HID_BUFFER_SIZE]; /* Input buffer */
struct urb urbout; /* Output URB */
struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE]; /* Transmit buffer */
unsigned char outhead, outtail; /* Tx buffer head & tail */
struct urb *urbctrl; /* Control URB */
struct usb_ctrlrequest cr; /* Control request struct */
struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */
unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
char ctrlbuf[HID_BUFFER_SIZE]; /* Control buffer */
spinlock_t ctrllock; /* Control fifo spinlock */
struct urb *urbout; /* Output URB */
struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
unsigned char outhead, outtail; /* Output pipe fifo head & tail */
char outbuf[HID_BUFFER_SIZE]; /* Output buffer */
spinlock_t outlock; /* Output fifo spinlock */
unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
......@@ -400,8 +350,12 @@ struct hid_device { /* device report descriptor */
void *hiddev; /* The hiddev structure */
int minor; /* Hiddev minor number */
wait_queue_head_t wait; /* For sleeping */
int open; /* is the device open by anyone? */
char name[128]; /* Device name */
char phys[64]; /* Device physical location */
char uniq[64]; /* Device unique identifier (serial #) */
};
#define HID_GLOBAL_STACK_SIZE 4
......@@ -441,19 +395,18 @@ void hidinput_disconnect(struct hid_device *);
#else
#define hid_dump_input(a,b) do { } while (0)
#define hid_dump_device(c) do { } while (0)
#endif /* DEBUG */
#define hid_dump_field(a,b) do { } while (0)
#endif
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || ( a == 0x000c0001))
#endif
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
/* We ignore a few input applications that are not widely used */
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001))
int hid_open(struct hid_device *);
void hid_close(struct hid_device *);
int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **);
int hid_set_field(struct hid_field *, unsigned, __s32);
void hid_write_report(struct hid_device *, struct hid_report *);
void hid_read_report(struct hid_device *, struct hid_report *);
void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
void hid_init_reports(struct hid_device *hid);
#endif /* !_HID_BOOT_PROTOCOL */
#endif /* !__HID_H */
......@@ -400,7 +400,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL;
hid_read_report(hid, report);
hid_submit_report(hid, report, USB_DIR_IN);
return 0;
......@@ -414,7 +414,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL;
hid_write_report(hid, report);
hid_submit_report(hid, report, USB_DIR_OUT);
return 0;
......
/*
* $Id: usbkbd.c,v 1.20 2001/04/26 08:34:49 vojtech Exp $
* $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* USB HIDBP Keyboard support
*
* Sponsored by SuSE
*/
/*
......@@ -24,8 +22,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
......@@ -35,19 +33,17 @@
#include <linux/init.h>
#include <linux/usb.h>
#define _HID_BOOT_PROTOCOL
#include "hid.h"
/*
* Version Information
*/
#define DRIVER_VERSION ""
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
static unsigned char usb_kbd_keycode[256] = {
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
......@@ -74,9 +70,10 @@ struct usb_kbd {
unsigned char new[8];
unsigned char old[8];
struct urb *irq, *led;
struct usb_ctrlrequest dr;
struct usb_ctrlrequest cr;
unsigned char leds, newleds;
char name[128];
char phys[64];
int open;
};
......@@ -129,7 +126,7 @@ int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, i
kbd->leds = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_KERNEL))
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
err("usb_submit_urb(leds) failed");
return 0;
......@@ -147,7 +144,7 @@ static void usb_kbd_led(struct urb *urb)
kbd->leds = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_KERNEL))
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
err("usb_submit_urb(leds) failed");
}
......@@ -181,6 +178,7 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
struct usb_endpoint_descriptor *endpoint;
struct usb_kbd *kbd;
int i, pipe, maxp;
char path[64];
char *buf;
iface = &dev->actconfig->interface[ifnum];
......@@ -195,9 +193,6 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
hid_set_protocol(dev, interface->bInterfaceNumber, 0);
hid_set_idle(dev, interface->bInterfaceNumber, 0, 0);
if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
memset(kbd, 0, sizeof(struct usb_kbd));
......@@ -230,13 +225,17 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
usb_kbd_irq, kbd, endpoint->bInterval);
kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
kbd->dr.bRequest = HID_REQ_SET_REPORT;
kbd->dr.wValue = 0x200;
kbd->dr.wIndex = interface->bInterfaceNumber;
kbd->dr.wLength = 1;
kbd->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
kbd->cr.bRequest = 0x09;
kbd->cr.wValue = 0x200;
kbd->cr.wIndex = interface->bInterfaceNumber;
kbd->cr.wLength = 1;
usb_make_path(dev, path, 64);
sprintf(kbd->phys, "%s/input0", path);
kbd->dev.name = kbd->name;
kbd->dev.phys = kbd->phys;
kbd->dev.idbus = BUS_USB;
kbd->dev.idvendor = dev->descriptor.idVendor;
kbd->dev.idproduct = dev->descriptor.idProduct;
......@@ -261,12 +260,11 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
kfree(buf);
FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0),
(void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd);
(void*) &kbd->cr, &kbd->leds, 1, usb_kbd_led, kbd);
input_register_device(&kbd->dev);
printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum);
printk(KERN_INFO "input: %s on %s\n", kbd->name, path);
return kbd;
}
......
/*
* $Id: usbmouse.c,v 1.6 2000/08/14 21:05:26 vojtech Exp $
* $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* USB HIDBP Mouse support
*
* Sponsored by SuSE
*/
/*
......@@ -24,8 +22,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
......@@ -35,23 +33,22 @@
#include <linux/init.h>
#include <linux/usb.h>
#define _HID_BOOT_PROTOCOL
#include "hid.h"
/*
* Version Information
*/
#define DRIVER_VERSION "v1.6"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB HID Boot Protocol mouse driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
struct usb_mouse {
signed char data[8];
char name[128];
char phys[64];
struct usb_device *usbdev;
struct input_dev dev;
struct urb *irq;
......@@ -107,6 +104,7 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
struct usb_endpoint_descriptor *endpoint;
struct usb_mouse *mouse;
int pipe, maxp;
char path[64];
char *buf;
iface = &dev->actconfig->interface[ifnum];
......@@ -121,8 +119,6 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
hid_set_idle(dev, interface->bInterfaceNumber, 0, 0);
if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
memset(mouse, 0, sizeof(struct usb_mouse));
......@@ -144,7 +140,11 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
mouse->dev.open = usb_mouse_open;
mouse->dev.close = usb_mouse_close;
usb_make_path(dev, path, 64);
sprintf(mouse->phys, "%s/input0", path);
mouse->dev.name = mouse->name;
mouse->dev.phys = mouse->phys;
mouse->dev.idbus = BUS_USB;
mouse->dev.idvendor = dev->descriptor.idVendor;
mouse->dev.idproduct = dev->descriptor.idProduct;
......@@ -173,8 +173,7 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
input_register_device(&mouse->dev);
printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
mouse->dev.number, mouse->name, dev->bus->busnum, dev->devnum, ifnum);
printk(KERN_INFO "input: %s on %s\n", mouse->name, path);
return mouse;
}
......
/*
* $Id: wacom.c,v 1.22 2001/04/26 11:26:09 vojtech Exp $
* $Id: wacom.c,v 1.28 2001/09/25 10:12:07 vojtech Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
* Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
* Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
......@@ -11,8 +11,6 @@
*
* USB Wacom Graphire and Wacom Intuos tablet support
*
* Sponsored by SuSE
*
* ChangeLog:
* v0.1 (vp) - Initial release
* v0.2 (aba) - Support for all buttons / combinations
......@@ -57,8 +55,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
......@@ -72,12 +70,13 @@
* Version Information
*/
#define DRIVER_VERSION "v1.21"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_WACOM 0x056a
......@@ -106,6 +105,7 @@ struct wacom {
int open;
int x, y;
__u32 serial[2];
char phys[32];
};
static void wacom_pl_irq(struct urb *urb)
......@@ -354,6 +354,7 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struc
{
struct usb_endpoint_descriptor *endpoint;
struct wacom *wacom;
char path[64];
if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
memset(wacom, 0, sizeof(struct wacom));
......@@ -394,7 +395,11 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struc
wacom->dev.open = wacom_open;
wacom->dev.close = wacom_close;
usb_make_path(dev, path, 64);
sprintf(wacom->phys, "%s/input0", path);
wacom->dev.name = wacom->features->name;
wacom->dev.phys = wacom->phys;
wacom->dev.idbus = BUS_USB;
wacom->dev.idvendor = dev->descriptor.idVendor;
wacom->dev.idproduct = dev->descriptor.idProduct;
......@@ -408,8 +413,7 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struc
input_register_device(&wacom->dev);
printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum);
printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path);
return wacom;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment