Commit 57d52f67 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linuxusb.bkbits.net/linus-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 0f739278 d96835d3
/*
* $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;
......
......@@ -134,9 +134,11 @@ struct usb_eth_dev {
#define VENDOR_ALLIEDTEL 0x07c9
#define VENDOR_BELKIN 0x050d
#define VENDOR_BILLIONTON 0x08dd
#define VENDOR_COMPAQ 0x049f
#define VENDOR_COREGA 0x07aa
#define VENDOR_DLINK 0x2001
#define VENDOR_ELSA 0x05cc
#define VENDOR_HAWKING 0x0e66
#define VENDOR_IODATA 0x04bb
#define VENDOR_KINGSTON 0x0951
#define VENDOR_LANEED 0x056e
......@@ -190,6 +192,8 @@ PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
......@@ -212,8 +216,12 @@ PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
DEFAULT_GPIO_RESET)
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
......
/*
* $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