[PATCH] Generic HID layer - input and event reporting
hid_input_report() was needlessly USB-specific in USB HID. This patch makes the function independent of HID implementation and fixes all the current users. Bluetooth patches comply with this prototype. Signed-off-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
aa938f7974
commit
aa8de2f038
@@ -940,5 +940,64 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hid_set_field);
|
EXPORT_SYMBOL_GPL(hid_set_field);
|
||||||
|
|
||||||
|
int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
|
||||||
|
{
|
||||||
|
struct hid_report_enum *report_enum = hid->report_enum + type;
|
||||||
|
struct hid_report *report;
|
||||||
|
int n, rsize;
|
||||||
|
|
||||||
|
if (!hid)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (!size) {
|
||||||
|
dbg("empty report");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_DATA
|
||||||
|
printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
n = 0; /* Normally report number is 0 */
|
||||||
|
if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */
|
||||||
|
n = *data++;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_DATA
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
|
||||||
|
for (i = 0; i < size; 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
rsize = ((report->size - 1) >> 3) + 1;
|
||||||
|
|
||||||
|
if (size < rsize) {
|
||||||
|
dbg("report %d is too short, (%d < %d)", report->id, size, rsize);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
|
||||||
|
hid->hiddev_report_event(hid, report);
|
||||||
|
|
||||||
|
for (n = 0; n < report->maxfield; n++)
|
||||||
|
hid_input_field(hid, report->field[n], data, interrupt);
|
||||||
|
|
||||||
|
if (hid->claimed & HID_CLAIMED_INPUT)
|
||||||
|
hidinput_report_event(hid, report);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(hid_input_report);
|
||||||
|
|
||||||
MODULE_LICENSE(DRIVER_LICENSE);
|
MODULE_LICENSE(DRIVER_LICENSE);
|
||||||
|
|
||||||
|
@@ -169,65 +169,6 @@ done:
|
|||||||
spin_unlock_irqrestore(&usbhid->inlock, flags);
|
spin_unlock_irqrestore(&usbhid->inlock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hid_input_report(int type, struct urb *urb, int interrupt)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (!len) {
|
|
||||||
dbg("empty report");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_DATA
|
|
||||||
printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
n = 0; /* Normally report number is 0 */
|
|
||||||
if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */
|
|
||||||
n = *data++;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_DATA
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);
|
|
||||||
for (i = 0; i < len; 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) {
|
|
||||||
dbg("report %d is too short, (%d < %d)", report->id, len, size);
|
|
||||||
memset(data + len, 0, size - len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hid->claimed & HID_CLAIMED_HIDDEV)
|
|
||||||
hiddev_report_event(hid, report);
|
|
||||||
|
|
||||||
for (n = 0; n < report->maxfield; n++)
|
|
||||||
hid_input_field(hid, report->field[n], data, interrupt);
|
|
||||||
|
|
||||||
if (hid->claimed & HID_CLAIMED_INPUT)
|
|
||||||
hidinput_report_event(hid, report);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Input interrupt completion handler.
|
* Input interrupt completion handler.
|
||||||
*/
|
*/
|
||||||
@@ -241,7 +182,9 @@ static void hid_irq_in(struct urb *urb)
|
|||||||
switch (urb->status) {
|
switch (urb->status) {
|
||||||
case 0: /* success */
|
case 0: /* success */
|
||||||
usbhid->retry_delay = 0;
|
usbhid->retry_delay = 0;
|
||||||
hid_input_report(HID_INPUT_REPORT, urb, 1);
|
hid_input_report(urb->context, HID_INPUT_REPORT,
|
||||||
|
urb->transfer_buffer,
|
||||||
|
urb->actual_length, 1);
|
||||||
break;
|
break;
|
||||||
case -EPIPE: /* stall */
|
case -EPIPE: /* stall */
|
||||||
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
|
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
|
||||||
@@ -426,7 +369,8 @@ static void hid_ctrl(struct urb *urb)
|
|||||||
switch (urb->status) {
|
switch (urb->status) {
|
||||||
case 0: /* success */
|
case 0: /* success */
|
||||||
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
|
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
|
||||||
hid_input_report(usbhid->ctrl[usbhid->ctrltail].report->type, urb, 0);
|
hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
|
||||||
|
urb->transfer_buffer, urb->actual_length, 0);
|
||||||
break;
|
break;
|
||||||
case -ESHUTDOWN: /* unplug */
|
case -ESHUTDOWN: /* unplug */
|
||||||
unplug = 1;
|
unplug = 1;
|
||||||
@@ -1286,6 +1230,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|||||||
hid->hidinput_close = hidinput_close;
|
hid->hidinput_close = hidinput_close;
|
||||||
#ifdef CONFIG_USB_HIDDEV
|
#ifdef CONFIG_USB_HIDDEV
|
||||||
hid->hiddev_hid_event = hiddev_hid_event;
|
hid->hiddev_hid_event = hiddev_hid_event;
|
||||||
|
hid->hiddev_report_event = hiddev_report_event;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return hid;
|
return hid;
|
||||||
|
@@ -214,6 +214,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
|
|||||||
|
|
||||||
hiddev_send_event(hid, &uref);
|
hiddev_send_event(hid, &uref);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fasync file op
|
* fasync file op
|
||||||
*/
|
*/
|
||||||
|
@@ -436,7 +436,7 @@ struct hid_device { /* device report descriptor */
|
|||||||
/* hiddev event handler */
|
/* hiddev event handler */
|
||||||
void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
|
void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
|
||||||
struct hid_usage *, __s32);
|
struct hid_usage *, __s32);
|
||||||
|
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
|
||||||
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
|
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
|
||||||
unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
|
unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
|
||||||
unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
|
unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
|
||||||
@@ -492,6 +492,7 @@ extern int hidinput_connect(struct hid_device *);
|
|||||||
extern void hidinput_disconnect(struct hid_device *);
|
extern void hidinput_disconnect(struct hid_device *);
|
||||||
|
|
||||||
int hid_set_field(struct hid_field *, unsigned, __s32);
|
int hid_set_field(struct hid_field *, unsigned, __s32);
|
||||||
|
int hid_input_report(struct hid_device *, int type, u8 *, int, int);
|
||||||
int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
|
int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
|
||||||
void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt);
|
void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt);
|
||||||
void hid_output_report(struct hid_report *report, __u8 *data);
|
void hid_output_report(struct hid_report *report, __u8 *data);
|
||||||
|
Reference in New Issue
Block a user