Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa8de2f0 authored by Jiri Kosina's avatar Jiri Kosina Committed by Greg Kroah-Hartman
Browse files

[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: default avatarJiri Kosina <jkosina@suse.cz>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent aa938f79
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -940,5 +940,64 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
}
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);
+6 −61
Original line number Diff line number Diff line
@@ -169,65 +169,6 @@ static void hid_io_error(struct hid_device *hid)
	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.
 */
@@ -241,7 +182,9 @@ static void hid_irq_in(struct urb *urb)
	switch (urb->status) {
		case 0:			/* success */
			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;
		case -EPIPE:		/* stall */
			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
@@ -426,7 +369,8 @@ static void hid_ctrl(struct urb *urb)
	switch (urb->status) {
		case 0:			/* success */
			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;
		case -ESHUTDOWN:	/* unplug */
			unplug = 1;
@@ -1286,6 +1230,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
	hid->hidinput_close = hidinput_close;
#ifdef CONFIG_USB_HIDDEV
	hid->hiddev_hid_event = hiddev_hid_event;
	hid->hiddev_report_event = hiddev_report_event;
#endif

	return hid;
+1 −0
Original line number Diff line number Diff line
@@ -214,6 +214,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)

	hiddev_send_event(hid, &uref);
}

/*
 * fasync file op
 */
+2 −1
Original line number Diff line number Diff line
@@ -436,7 +436,7 @@ struct hid_device { /* device report descriptor */
	/* hiddev event handler */
	void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
				  struct hid_usage *, __s32);

	void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
	unsigned long pb_pressed_fn[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 *);

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);
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);