18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  USB HID support for Linux
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (c) 1999 Andreas Gal
68c2ecf20Sopenharmony_ci *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
78c2ecf20Sopenharmony_ci *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
88c2ecf20Sopenharmony_ci *  Copyright (c) 2007-2008 Oliver Neukum
98c2ecf20Sopenharmony_ci *  Copyright (c) 2006-2010 Jiri Kosina
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/*
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/list.h>
208c2ecf20Sopenharmony_ci#include <linux/mm.h>
218c2ecf20Sopenharmony_ci#include <linux/mutex.h>
228c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
238c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
248c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
258c2ecf20Sopenharmony_ci#include <linux/input.h>
268c2ecf20Sopenharmony_ci#include <linux/wait.h>
278c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
288c2ecf20Sopenharmony_ci#include <linux/string.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <linux/usb.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <linux/hid.h>
338c2ecf20Sopenharmony_ci#include <linux/hiddev.h>
348c2ecf20Sopenharmony_ci#include <linux/hid-debug.h>
358c2ecf20Sopenharmony_ci#include <linux/hidraw.h>
368c2ecf20Sopenharmony_ci#include "usbhid.h"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * Version Information
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define DRIVER_DESC "USB HID core driver"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*
458c2ecf20Sopenharmony_ci * Module parameters.
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic unsigned int hid_mousepoll_interval;
498c2ecf20Sopenharmony_cimodule_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mousepoll, "Polling interval of mice");
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic unsigned int hid_jspoll_interval;
538c2ecf20Sopenharmony_cimodule_param_named(jspoll, hid_jspoll_interval, uint, 0644);
548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(jspoll, "Polling interval of joysticks");
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic unsigned int hid_kbpoll_interval;
578c2ecf20Sopenharmony_cimodule_param_named(kbpoll, hid_kbpoll_interval, uint, 0644);
588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(kbpoll, "Polling interval of keyboards");
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic unsigned int ignoreled;
618c2ecf20Sopenharmony_cimodule_param_named(ignoreled, ignoreled, uint, 0644);
628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ignoreled, "Autosuspend with active leds");
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/* Quirks specified at module load time */
658c2ecf20Sopenharmony_cistatic char *quirks_param[MAX_USBHID_BOOT_QUIRKS];
668c2ecf20Sopenharmony_cimodule_param_array_named(quirks, quirks_param, charp, NULL, 0444);
678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
688c2ecf20Sopenharmony_ci		" quirks=vendorID:productID:quirks"
698c2ecf20Sopenharmony_ci		" where vendorID, productID, and quirks are all in"
708c2ecf20Sopenharmony_ci		" 0x-prefixed hex");
718c2ecf20Sopenharmony_ci/*
728c2ecf20Sopenharmony_ci * Input submission and I/O error handler.
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cistatic void hid_io_error(struct hid_device *hid);
758c2ecf20Sopenharmony_cistatic int hid_submit_out(struct hid_device *hid);
768c2ecf20Sopenharmony_cistatic int hid_submit_ctrl(struct hid_device *hid);
778c2ecf20Sopenharmony_cistatic void hid_cancel_delayed_stuff(struct usbhid_device *usbhid);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/* Start up the input URB */
808c2ecf20Sopenharmony_cistatic int hid_start_in(struct hid_device *hid)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	unsigned long flags;
838c2ecf20Sopenharmony_ci	int rc = 0;
848c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
878c2ecf20Sopenharmony_ci	if (test_bit(HID_IN_POLLING, &usbhid->iofl) &&
888c2ecf20Sopenharmony_ci	    !test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
898c2ecf20Sopenharmony_ci	    !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
908c2ecf20Sopenharmony_ci	    !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
918c2ecf20Sopenharmony_ci		rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
928c2ecf20Sopenharmony_ci		if (rc != 0) {
938c2ecf20Sopenharmony_ci			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
948c2ecf20Sopenharmony_ci			if (rc == -ENOSPC)
958c2ecf20Sopenharmony_ci				set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
968c2ecf20Sopenharmony_ci		} else {
978c2ecf20Sopenharmony_ci			clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
988c2ecf20Sopenharmony_ci		}
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
1018c2ecf20Sopenharmony_ci	return rc;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/* I/O retry timer routine */
1058c2ecf20Sopenharmony_cistatic void hid_retry_timeout(struct timer_list *t)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = from_timer(usbhid, t, io_retry);
1088c2ecf20Sopenharmony_ci	struct hid_device *hid = usbhid->hid;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
1118c2ecf20Sopenharmony_ci	if (hid_start_in(hid))
1128c2ecf20Sopenharmony_ci		hid_io_error(hid);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/* Workqueue routine to reset the device or clear a halt */
1168c2ecf20Sopenharmony_cistatic void hid_reset(struct work_struct *work)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid =
1198c2ecf20Sopenharmony_ci		container_of(work, struct usbhid_device, reset_work);
1208c2ecf20Sopenharmony_ci	struct hid_device *hid = usbhid->hid;
1218c2ecf20Sopenharmony_ci	int rc;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
1248c2ecf20Sopenharmony_ci		dev_dbg(&usbhid->intf->dev, "clear halt\n");
1258c2ecf20Sopenharmony_ci		rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe);
1268c2ecf20Sopenharmony_ci		clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
1278c2ecf20Sopenharmony_ci		if (rc == 0) {
1288c2ecf20Sopenharmony_ci			hid_start_in(hid);
1298c2ecf20Sopenharmony_ci		} else {
1308c2ecf20Sopenharmony_ci			dev_dbg(&usbhid->intf->dev,
1318c2ecf20Sopenharmony_ci					"clear-halt failed: %d\n", rc);
1328c2ecf20Sopenharmony_ci			set_bit(HID_RESET_PENDING, &usbhid->iofl);
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
1378c2ecf20Sopenharmony_ci		dev_dbg(&usbhid->intf->dev, "resetting device\n");
1388c2ecf20Sopenharmony_ci		usb_queue_reset_device(usbhid->intf);
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/* Main I/O error handler */
1438c2ecf20Sopenharmony_cistatic void hid_io_error(struct hid_device *hid)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	unsigned long flags;
1468c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* Stop when disconnected */
1518c2ecf20Sopenharmony_ci	if (test_bit(HID_DISCONNECTED, &usbhid->iofl))
1528c2ecf20Sopenharmony_ci		goto done;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* If it has been a while since the last error, we'll assume
1558c2ecf20Sopenharmony_ci	 * this a brand new error and reset the retry timeout. */
1568c2ecf20Sopenharmony_ci	if (time_after(jiffies, usbhid->stop_retry + HZ/2))
1578c2ecf20Sopenharmony_ci		usbhid->retry_delay = 0;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* When an error occurs, retry at increasing intervals */
1608c2ecf20Sopenharmony_ci	if (usbhid->retry_delay == 0) {
1618c2ecf20Sopenharmony_ci		usbhid->retry_delay = 13;	/* Then 26, 52, 104, 104, ... */
1628c2ecf20Sopenharmony_ci		usbhid->stop_retry = jiffies + msecs_to_jiffies(1000);
1638c2ecf20Sopenharmony_ci	} else if (usbhid->retry_delay < 100)
1648c2ecf20Sopenharmony_ci		usbhid->retry_delay *= 2;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (time_after(jiffies, usbhid->stop_retry)) {
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		/* Retries failed, so do a port reset unless we lack bandwidth*/
1698c2ecf20Sopenharmony_ci		if (!test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
1708c2ecf20Sopenharmony_ci		     && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci			schedule_work(&usbhid->reset_work);
1738c2ecf20Sopenharmony_ci			goto done;
1748c2ecf20Sopenharmony_ci		}
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	mod_timer(&usbhid->io_retry,
1788c2ecf20Sopenharmony_ci			jiffies + msecs_to_jiffies(usbhid->retry_delay));
1798c2ecf20Sopenharmony_cidone:
1808c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic void usbhid_mark_busy(struct usbhid_device *usbhid)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct usb_interface *intf = usbhid->intf;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	usb_mark_last_busy(interface_to_usbdev(intf));
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int usbhid_restart_out_queue(struct usbhid_device *usbhid)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(usbhid->intf);
1938c2ecf20Sopenharmony_ci	int kicked;
1948c2ecf20Sopenharmony_ci	int r;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (!hid || test_bit(HID_RESET_PENDING, &usbhid->iofl) ||
1978c2ecf20Sopenharmony_ci			test_bit(HID_SUSPENDED, &usbhid->iofl))
1988c2ecf20Sopenharmony_ci		return 0;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if ((kicked = (usbhid->outhead != usbhid->outtail))) {
2018c2ecf20Sopenharmony_ci		hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		/* Try to wake up from autosuspend... */
2048c2ecf20Sopenharmony_ci		r = usb_autopm_get_interface_async(usbhid->intf);
2058c2ecf20Sopenharmony_ci		if (r < 0)
2068c2ecf20Sopenharmony_ci			return r;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		/*
2098c2ecf20Sopenharmony_ci		 * If still suspended, don't submit.  Submission will
2108c2ecf20Sopenharmony_ci		 * occur if/when resume drains the queue.
2118c2ecf20Sopenharmony_ci		 */
2128c2ecf20Sopenharmony_ci		if (test_bit(HID_SUSPENDED, &usbhid->iofl)) {
2138c2ecf20Sopenharmony_ci			usb_autopm_put_interface_no_suspend(usbhid->intf);
2148c2ecf20Sopenharmony_ci			return r;
2158c2ecf20Sopenharmony_ci		}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		/* Asynchronously flush queue. */
2188c2ecf20Sopenharmony_ci		set_bit(HID_OUT_RUNNING, &usbhid->iofl);
2198c2ecf20Sopenharmony_ci		if (hid_submit_out(hid)) {
2208c2ecf20Sopenharmony_ci			clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
2218c2ecf20Sopenharmony_ci			usb_autopm_put_interface_async(usbhid->intf);
2228c2ecf20Sopenharmony_ci		}
2238c2ecf20Sopenharmony_ci		wake_up(&usbhid->wait);
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci	return kicked;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(usbhid->intf);
2318c2ecf20Sopenharmony_ci	int kicked;
2328c2ecf20Sopenharmony_ci	int r;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	WARN_ON(hid == NULL);
2358c2ecf20Sopenharmony_ci	if (!hid || test_bit(HID_RESET_PENDING, &usbhid->iofl) ||
2368c2ecf20Sopenharmony_ci			test_bit(HID_SUSPENDED, &usbhid->iofl))
2378c2ecf20Sopenharmony_ci		return 0;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) {
2408c2ecf20Sopenharmony_ci		hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		/* Try to wake up from autosuspend... */
2438c2ecf20Sopenharmony_ci		r = usb_autopm_get_interface_async(usbhid->intf);
2448c2ecf20Sopenharmony_ci		if (r < 0)
2458c2ecf20Sopenharmony_ci			return r;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		/*
2488c2ecf20Sopenharmony_ci		 * If still suspended, don't submit.  Submission will
2498c2ecf20Sopenharmony_ci		 * occur if/when resume drains the queue.
2508c2ecf20Sopenharmony_ci		 */
2518c2ecf20Sopenharmony_ci		if (test_bit(HID_SUSPENDED, &usbhid->iofl)) {
2528c2ecf20Sopenharmony_ci			usb_autopm_put_interface_no_suspend(usbhid->intf);
2538c2ecf20Sopenharmony_ci			return r;
2548c2ecf20Sopenharmony_ci		}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci		/* Asynchronously flush queue. */
2578c2ecf20Sopenharmony_ci		set_bit(HID_CTRL_RUNNING, &usbhid->iofl);
2588c2ecf20Sopenharmony_ci		if (hid_submit_ctrl(hid)) {
2598c2ecf20Sopenharmony_ci			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
2608c2ecf20Sopenharmony_ci			usb_autopm_put_interface_async(usbhid->intf);
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci		wake_up(&usbhid->wait);
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci	return kicked;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci/*
2688c2ecf20Sopenharmony_ci * Input interrupt completion handler.
2698c2ecf20Sopenharmony_ci */
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic void hid_irq_in(struct urb *urb)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct hid_device	*hid = urb->context;
2748c2ecf20Sopenharmony_ci	struct usbhid_device	*usbhid = hid->driver_data;
2758c2ecf20Sopenharmony_ci	int			status;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	switch (urb->status) {
2788c2ecf20Sopenharmony_ci	case 0:			/* success */
2798c2ecf20Sopenharmony_ci		usbhid->retry_delay = 0;
2808c2ecf20Sopenharmony_ci		if (!test_bit(HID_OPENED, &usbhid->iofl))
2818c2ecf20Sopenharmony_ci			break;
2828c2ecf20Sopenharmony_ci		usbhid_mark_busy(usbhid);
2838c2ecf20Sopenharmony_ci		if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
2848c2ecf20Sopenharmony_ci			hid_input_report(urb->context, HID_INPUT_REPORT,
2858c2ecf20Sopenharmony_ci					 urb->transfer_buffer,
2868c2ecf20Sopenharmony_ci					 urb->actual_length, 1);
2878c2ecf20Sopenharmony_ci			/*
2888c2ecf20Sopenharmony_ci			 * autosuspend refused while keys are pressed
2898c2ecf20Sopenharmony_ci			 * because most keyboards don't wake up when
2908c2ecf20Sopenharmony_ci			 * a key is released
2918c2ecf20Sopenharmony_ci			 */
2928c2ecf20Sopenharmony_ci			if (hid_check_keys_pressed(hid))
2938c2ecf20Sopenharmony_ci				set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
2948c2ecf20Sopenharmony_ci			else
2958c2ecf20Sopenharmony_ci				clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
2968c2ecf20Sopenharmony_ci		}
2978c2ecf20Sopenharmony_ci		break;
2988c2ecf20Sopenharmony_ci	case -EPIPE:		/* stall */
2998c2ecf20Sopenharmony_ci		usbhid_mark_busy(usbhid);
3008c2ecf20Sopenharmony_ci		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
3018c2ecf20Sopenharmony_ci		set_bit(HID_CLEAR_HALT, &usbhid->iofl);
3028c2ecf20Sopenharmony_ci		schedule_work(&usbhid->reset_work);
3038c2ecf20Sopenharmony_ci		return;
3048c2ecf20Sopenharmony_ci	case -ECONNRESET:	/* unlink */
3058c2ecf20Sopenharmony_ci	case -ENOENT:
3068c2ecf20Sopenharmony_ci	case -ESHUTDOWN:	/* unplug */
3078c2ecf20Sopenharmony_ci		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
3088c2ecf20Sopenharmony_ci		return;
3098c2ecf20Sopenharmony_ci	case -EILSEQ:		/* protocol error or unplug */
3108c2ecf20Sopenharmony_ci	case -EPROTO:		/* protocol error or unplug */
3118c2ecf20Sopenharmony_ci	case -ETIME:		/* protocol error or unplug */
3128c2ecf20Sopenharmony_ci	case -ETIMEDOUT:	/* Should never happen, but... */
3138c2ecf20Sopenharmony_ci		usbhid_mark_busy(usbhid);
3148c2ecf20Sopenharmony_ci		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
3158c2ecf20Sopenharmony_ci		hid_io_error(hid);
3168c2ecf20Sopenharmony_ci		return;
3178c2ecf20Sopenharmony_ci	default:		/* error */
3188c2ecf20Sopenharmony_ci		hid_warn(urb->dev, "input irq status %d received\n",
3198c2ecf20Sopenharmony_ci			 urb->status);
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	status = usb_submit_urb(urb, GFP_ATOMIC);
3238c2ecf20Sopenharmony_ci	if (status) {
3248c2ecf20Sopenharmony_ci		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
3258c2ecf20Sopenharmony_ci		if (status != -EPERM) {
3268c2ecf20Sopenharmony_ci			hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n",
3278c2ecf20Sopenharmony_ci				hid_to_usb_dev(hid)->bus->bus_name,
3288c2ecf20Sopenharmony_ci				hid_to_usb_dev(hid)->devpath,
3298c2ecf20Sopenharmony_ci				usbhid->ifnum, status);
3308c2ecf20Sopenharmony_ci			hid_io_error(hid);
3318c2ecf20Sopenharmony_ci		}
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int hid_submit_out(struct hid_device *hid)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct hid_report *report;
3388c2ecf20Sopenharmony_ci	char *raw_report;
3398c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
3408c2ecf20Sopenharmony_ci	int r;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	report = usbhid->out[usbhid->outtail].report;
3438c2ecf20Sopenharmony_ci	raw_report = usbhid->out[usbhid->outtail].raw_report;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	usbhid->urbout->transfer_buffer_length = hid_report_len(report);
3468c2ecf20Sopenharmony_ci	usbhid->urbout->dev = hid_to_usb_dev(hid);
3478c2ecf20Sopenharmony_ci	if (raw_report) {
3488c2ecf20Sopenharmony_ci		memcpy(usbhid->outbuf, raw_report,
3498c2ecf20Sopenharmony_ci				usbhid->urbout->transfer_buffer_length);
3508c2ecf20Sopenharmony_ci		kfree(raw_report);
3518c2ecf20Sopenharmony_ci		usbhid->out[usbhid->outtail].raw_report = NULL;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	dbg_hid("submitting out urb\n");
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	r = usb_submit_urb(usbhid->urbout, GFP_ATOMIC);
3578c2ecf20Sopenharmony_ci	if (r < 0) {
3588c2ecf20Sopenharmony_ci		hid_err(hid, "usb_submit_urb(out) failed: %d\n", r);
3598c2ecf20Sopenharmony_ci		return r;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	usbhid->last_out = jiffies;
3628c2ecf20Sopenharmony_ci	return 0;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int hid_submit_ctrl(struct hid_device *hid)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct hid_report *report;
3688c2ecf20Sopenharmony_ci	unsigned char dir;
3698c2ecf20Sopenharmony_ci	char *raw_report;
3708c2ecf20Sopenharmony_ci	int len, r;
3718c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	report = usbhid->ctrl[usbhid->ctrltail].report;
3748c2ecf20Sopenharmony_ci	raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
3758c2ecf20Sopenharmony_ci	dir = usbhid->ctrl[usbhid->ctrltail].dir;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	len = hid_report_len(report);
3788c2ecf20Sopenharmony_ci	if (dir == USB_DIR_OUT) {
3798c2ecf20Sopenharmony_ci		usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
3808c2ecf20Sopenharmony_ci		usbhid->urbctrl->transfer_buffer_length = len;
3818c2ecf20Sopenharmony_ci		if (raw_report) {
3828c2ecf20Sopenharmony_ci			memcpy(usbhid->ctrlbuf, raw_report, len);
3838c2ecf20Sopenharmony_ci			kfree(raw_report);
3848c2ecf20Sopenharmony_ci			usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
3858c2ecf20Sopenharmony_ci		}
3868c2ecf20Sopenharmony_ci	} else {
3878c2ecf20Sopenharmony_ci		int maxpacket, padlen;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci		usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
3908c2ecf20Sopenharmony_ci		maxpacket = usb_maxpacket(hid_to_usb_dev(hid),
3918c2ecf20Sopenharmony_ci					  usbhid->urbctrl->pipe, 0);
3928c2ecf20Sopenharmony_ci		if (maxpacket > 0) {
3938c2ecf20Sopenharmony_ci			padlen = DIV_ROUND_UP(len, maxpacket);
3948c2ecf20Sopenharmony_ci			padlen *= maxpacket;
3958c2ecf20Sopenharmony_ci			if (padlen > usbhid->bufsize)
3968c2ecf20Sopenharmony_ci				padlen = usbhid->bufsize;
3978c2ecf20Sopenharmony_ci		} else
3988c2ecf20Sopenharmony_ci			padlen = 0;
3998c2ecf20Sopenharmony_ci		usbhid->urbctrl->transfer_buffer_length = padlen;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci	usbhid->urbctrl->dev = hid_to_usb_dev(hid);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
4048c2ecf20Sopenharmony_ci	usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT :
4058c2ecf20Sopenharmony_ci						      HID_REQ_GET_REPORT;
4068c2ecf20Sopenharmony_ci	usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) |
4078c2ecf20Sopenharmony_ci					 report->id);
4088c2ecf20Sopenharmony_ci	usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
4098c2ecf20Sopenharmony_ci	usbhid->cr->wLength = cpu_to_le16(len);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n",
4128c2ecf20Sopenharmony_ci		usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" :
4138c2ecf20Sopenharmony_ci							     "Get_Report",
4148c2ecf20Sopenharmony_ci		usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	r = usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC);
4178c2ecf20Sopenharmony_ci	if (r < 0) {
4188c2ecf20Sopenharmony_ci		hid_err(hid, "usb_submit_urb(ctrl) failed: %d\n", r);
4198c2ecf20Sopenharmony_ci		return r;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci	usbhid->last_ctrl = jiffies;
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci/*
4268c2ecf20Sopenharmony_ci * Output interrupt completion handler.
4278c2ecf20Sopenharmony_ci */
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic void hid_irq_out(struct urb *urb)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct hid_device *hid = urb->context;
4328c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
4338c2ecf20Sopenharmony_ci	unsigned long flags;
4348c2ecf20Sopenharmony_ci	int unplug = 0;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	switch (urb->status) {
4378c2ecf20Sopenharmony_ci	case 0:			/* success */
4388c2ecf20Sopenharmony_ci		break;
4398c2ecf20Sopenharmony_ci	case -ESHUTDOWN:	/* unplug */
4408c2ecf20Sopenharmony_ci		unplug = 1;
4418c2ecf20Sopenharmony_ci	case -EILSEQ:		/* protocol error or unplug */
4428c2ecf20Sopenharmony_ci	case -EPROTO:		/* protocol error or unplug */
4438c2ecf20Sopenharmony_ci	case -ECONNRESET:	/* unlink */
4448c2ecf20Sopenharmony_ci	case -ENOENT:
4458c2ecf20Sopenharmony_ci		break;
4468c2ecf20Sopenharmony_ci	default:		/* error */
4478c2ecf20Sopenharmony_ci		hid_warn(urb->dev, "output irq status %d received\n",
4488c2ecf20Sopenharmony_ci			 urb->status);
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (unplug) {
4548c2ecf20Sopenharmony_ci		usbhid->outtail = usbhid->outhead;
4558c2ecf20Sopenharmony_ci	} else {
4568c2ecf20Sopenharmony_ci		usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		if (usbhid->outhead != usbhid->outtail &&
4598c2ecf20Sopenharmony_ci				hid_submit_out(hid) == 0) {
4608c2ecf20Sopenharmony_ci			/* Successfully submitted next urb in queue */
4618c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&usbhid->lock, flags);
4628c2ecf20Sopenharmony_ci			return;
4638c2ecf20Sopenharmony_ci		}
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
4678c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
4688c2ecf20Sopenharmony_ci	usb_autopm_put_interface_async(usbhid->intf);
4698c2ecf20Sopenharmony_ci	wake_up(&usbhid->wait);
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci/*
4738c2ecf20Sopenharmony_ci * Control pipe completion handler.
4748c2ecf20Sopenharmony_ci */
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic void hid_ctrl(struct urb *urb)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct hid_device *hid = urb->context;
4798c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
4808c2ecf20Sopenharmony_ci	unsigned long flags;
4818c2ecf20Sopenharmony_ci	int unplug = 0, status = urb->status;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	switch (status) {
4848c2ecf20Sopenharmony_ci	case 0:			/* success */
4858c2ecf20Sopenharmony_ci		if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
4868c2ecf20Sopenharmony_ci			hid_input_report(urb->context,
4878c2ecf20Sopenharmony_ci				usbhid->ctrl[usbhid->ctrltail].report->type,
4888c2ecf20Sopenharmony_ci				urb->transfer_buffer, urb->actual_length, 0);
4898c2ecf20Sopenharmony_ci		break;
4908c2ecf20Sopenharmony_ci	case -ESHUTDOWN:	/* unplug */
4918c2ecf20Sopenharmony_ci		unplug = 1;
4928c2ecf20Sopenharmony_ci	case -EILSEQ:		/* protocol error or unplug */
4938c2ecf20Sopenharmony_ci	case -EPROTO:		/* protocol error or unplug */
4948c2ecf20Sopenharmony_ci	case -ECONNRESET:	/* unlink */
4958c2ecf20Sopenharmony_ci	case -ENOENT:
4968c2ecf20Sopenharmony_ci	case -EPIPE:		/* report not available */
4978c2ecf20Sopenharmony_ci		break;
4988c2ecf20Sopenharmony_ci	default:		/* error */
4998c2ecf20Sopenharmony_ci		hid_warn(urb->dev, "ctrl urb status %d received\n", status);
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (unplug) {
5058c2ecf20Sopenharmony_ci		usbhid->ctrltail = usbhid->ctrlhead;
5068c2ecf20Sopenharmony_ci	} else if (usbhid->ctrlhead != usbhid->ctrltail) {
5078c2ecf20Sopenharmony_ci		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci		if (usbhid->ctrlhead != usbhid->ctrltail &&
5108c2ecf20Sopenharmony_ci				hid_submit_ctrl(hid) == 0) {
5118c2ecf20Sopenharmony_ci			/* Successfully submitted next urb in queue */
5128c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&usbhid->lock, flags);
5138c2ecf20Sopenharmony_ci			return;
5148c2ecf20Sopenharmony_ci		}
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
5188c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
5198c2ecf20Sopenharmony_ci	usb_autopm_put_interface_async(usbhid->intf);
5208c2ecf20Sopenharmony_ci	wake_up(&usbhid->wait);
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report,
5248c2ecf20Sopenharmony_ci				   unsigned char dir)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	int head;
5278c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) ||
5308c2ecf20Sopenharmony_ci		test_bit(HID_DISCONNECTED, &usbhid->iofl))
5318c2ecf20Sopenharmony_ci		return;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
5348c2ecf20Sopenharmony_ci		if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
5358c2ecf20Sopenharmony_ci			hid_warn(hid, "output queue full\n");
5368c2ecf20Sopenharmony_ci			return;
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
5408c2ecf20Sopenharmony_ci		if (!usbhid->out[usbhid->outhead].raw_report) {
5418c2ecf20Sopenharmony_ci			hid_warn(hid, "output queueing failed\n");
5428c2ecf20Sopenharmony_ci			return;
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci		hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
5458c2ecf20Sopenharmony_ci		usbhid->out[usbhid->outhead].report = report;
5468c2ecf20Sopenharmony_ci		usbhid->outhead = head;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci		/* If the queue isn't running, restart it */
5498c2ecf20Sopenharmony_ci		if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) {
5508c2ecf20Sopenharmony_ci			usbhid_restart_out_queue(usbhid);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		/* Otherwise see if an earlier request has timed out */
5538c2ecf20Sopenharmony_ci		} else if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci			/* Prevent autosuspend following the unlink */
5568c2ecf20Sopenharmony_ci			usb_autopm_get_interface_no_resume(usbhid->intf);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci			/*
5598c2ecf20Sopenharmony_ci			 * Prevent resubmission in case the URB completes
5608c2ecf20Sopenharmony_ci			 * before we can unlink it.  We don't want to cancel
5618c2ecf20Sopenharmony_ci			 * the wrong transfer!
5628c2ecf20Sopenharmony_ci			 */
5638c2ecf20Sopenharmony_ci			usb_block_urb(usbhid->urbout);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci			/* Drop lock to avoid deadlock if the callback runs */
5668c2ecf20Sopenharmony_ci			spin_unlock(&usbhid->lock);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci			usb_unlink_urb(usbhid->urbout);
5698c2ecf20Sopenharmony_ci			spin_lock(&usbhid->lock);
5708c2ecf20Sopenharmony_ci			usb_unblock_urb(usbhid->urbout);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci			/* Unlink might have stopped the queue */
5738c2ecf20Sopenharmony_ci			if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl))
5748c2ecf20Sopenharmony_ci				usbhid_restart_out_queue(usbhid);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci			/* Now we can allow autosuspend again */
5778c2ecf20Sopenharmony_ci			usb_autopm_put_interface_async(usbhid->intf);
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci		return;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
5838c2ecf20Sopenharmony_ci		hid_warn(hid, "control queue full\n");
5848c2ecf20Sopenharmony_ci		return;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	if (dir == USB_DIR_OUT) {
5888c2ecf20Sopenharmony_ci		usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
5898c2ecf20Sopenharmony_ci		if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
5908c2ecf20Sopenharmony_ci			hid_warn(hid, "control queueing failed\n");
5918c2ecf20Sopenharmony_ci			return;
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci		hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
5948c2ecf20Sopenharmony_ci	}
5958c2ecf20Sopenharmony_ci	usbhid->ctrl[usbhid->ctrlhead].report = report;
5968c2ecf20Sopenharmony_ci	usbhid->ctrl[usbhid->ctrlhead].dir = dir;
5978c2ecf20Sopenharmony_ci	usbhid->ctrlhead = head;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	/* If the queue isn't running, restart it */
6008c2ecf20Sopenharmony_ci	if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) {
6018c2ecf20Sopenharmony_ci		usbhid_restart_ctrl_queue(usbhid);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	/* Otherwise see if an earlier request has timed out */
6048c2ecf20Sopenharmony_ci	} else if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci		/* Prevent autosuspend following the unlink */
6078c2ecf20Sopenharmony_ci		usb_autopm_get_interface_no_resume(usbhid->intf);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		/*
6108c2ecf20Sopenharmony_ci		 * Prevent resubmission in case the URB completes
6118c2ecf20Sopenharmony_ci		 * before we can unlink it.  We don't want to cancel
6128c2ecf20Sopenharmony_ci		 * the wrong transfer!
6138c2ecf20Sopenharmony_ci		 */
6148c2ecf20Sopenharmony_ci		usb_block_urb(usbhid->urbctrl);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci		/* Drop lock to avoid deadlock if the callback runs */
6178c2ecf20Sopenharmony_ci		spin_unlock(&usbhid->lock);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		usb_unlink_urb(usbhid->urbctrl);
6208c2ecf20Sopenharmony_ci		spin_lock(&usbhid->lock);
6218c2ecf20Sopenharmony_ci		usb_unblock_urb(usbhid->urbctrl);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci		/* Unlink might have stopped the queue */
6248c2ecf20Sopenharmony_ci		if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
6258c2ecf20Sopenharmony_ci			usbhid_restart_ctrl_queue(usbhid);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		/* Now we can allow autosuspend again */
6288c2ecf20Sopenharmony_ci		usb_autopm_put_interface_async(usbhid->intf);
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cistatic void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
6358c2ecf20Sopenharmony_ci	unsigned long flags;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
6388c2ecf20Sopenharmony_ci	__usbhid_submit_report(hid, report, dir);
6398c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int usbhid_wait_io(struct hid_device *hid)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (!wait_event_timeout(usbhid->wait,
6478c2ecf20Sopenharmony_ci				(!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
6488c2ecf20Sopenharmony_ci				!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
6498c2ecf20Sopenharmony_ci					10*HZ)) {
6508c2ecf20Sopenharmony_ci		dbg_hid("timeout waiting for ctrl or out queue to clear\n");
6518c2ecf20Sopenharmony_ci		return -1;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	return 0;
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
6588c2ecf20Sopenharmony_ci{
6598c2ecf20Sopenharmony_ci	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
6608c2ecf20Sopenharmony_ci		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
6618c2ecf20Sopenharmony_ci		ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
6628c2ecf20Sopenharmony_ci}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_cistatic int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
6658c2ecf20Sopenharmony_ci		unsigned char type, void *buf, int size)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	int result, retries = 4;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	memset(buf, 0, size);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	do {
6728c2ecf20Sopenharmony_ci		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
6738c2ecf20Sopenharmony_ci				USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
6748c2ecf20Sopenharmony_ci				(type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);
6758c2ecf20Sopenharmony_ci		retries--;
6768c2ecf20Sopenharmony_ci	} while (result < size && retries);
6778c2ecf20Sopenharmony_ci	return result;
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cistatic int usbhid_open(struct hid_device *hid)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
6838c2ecf20Sopenharmony_ci	int res;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	mutex_lock(&usbhid->mutex);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	set_bit(HID_OPENED, &usbhid->iofl);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
6908c2ecf20Sopenharmony_ci		res = 0;
6918c2ecf20Sopenharmony_ci		goto Done;
6928c2ecf20Sopenharmony_ci	}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	res = usb_autopm_get_interface(usbhid->intf);
6958c2ecf20Sopenharmony_ci	/* the device must be awake to reliably request remote wakeup */
6968c2ecf20Sopenharmony_ci	if (res < 0) {
6978c2ecf20Sopenharmony_ci		clear_bit(HID_OPENED, &usbhid->iofl);
6988c2ecf20Sopenharmony_ci		res = -EIO;
6998c2ecf20Sopenharmony_ci		goto Done;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	usbhid->intf->needs_remote_wakeup = 1;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	set_bit(HID_RESUME_RUNNING, &usbhid->iofl);
7058c2ecf20Sopenharmony_ci	set_bit(HID_IN_POLLING, &usbhid->iofl);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	res = hid_start_in(hid);
7088c2ecf20Sopenharmony_ci	if (res) {
7098c2ecf20Sopenharmony_ci		if (res != -ENOSPC) {
7108c2ecf20Sopenharmony_ci			hid_io_error(hid);
7118c2ecf20Sopenharmony_ci			res = 0;
7128c2ecf20Sopenharmony_ci		} else {
7138c2ecf20Sopenharmony_ci			/* no use opening if resources are insufficient */
7148c2ecf20Sopenharmony_ci			res = -EBUSY;
7158c2ecf20Sopenharmony_ci			clear_bit(HID_OPENED, &usbhid->iofl);
7168c2ecf20Sopenharmony_ci			clear_bit(HID_IN_POLLING, &usbhid->iofl);
7178c2ecf20Sopenharmony_ci			usbhid->intf->needs_remote_wakeup = 0;
7188c2ecf20Sopenharmony_ci		}
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	usb_autopm_put_interface(usbhid->intf);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/*
7248c2ecf20Sopenharmony_ci	 * In case events are generated while nobody was listening,
7258c2ecf20Sopenharmony_ci	 * some are released when the device is re-opened.
7268c2ecf20Sopenharmony_ci	 * Wait 50 msec for the queue to empty before allowing events
7278c2ecf20Sopenharmony_ci	 * to go through hid.
7288c2ecf20Sopenharmony_ci	 */
7298c2ecf20Sopenharmony_ci	if (res == 0)
7308c2ecf20Sopenharmony_ci		msleep(50);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci Done:
7358c2ecf20Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
7368c2ecf20Sopenharmony_ci	return res;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic void usbhid_close(struct hid_device *hid)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	mutex_lock(&usbhid->mutex);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	/*
7468c2ecf20Sopenharmony_ci	 * Make sure we don't restart data acquisition due to
7478c2ecf20Sopenharmony_ci	 * a resumption we no longer care about by avoiding racing
7488c2ecf20Sopenharmony_ci	 * with hid_start_in().
7498c2ecf20Sopenharmony_ci	 */
7508c2ecf20Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
7518c2ecf20Sopenharmony_ci	clear_bit(HID_OPENED, &usbhid->iofl);
7528c2ecf20Sopenharmony_ci	if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL))
7538c2ecf20Sopenharmony_ci		clear_bit(HID_IN_POLLING, &usbhid->iofl);
7548c2ecf20Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) {
7578c2ecf20Sopenharmony_ci		hid_cancel_delayed_stuff(usbhid);
7588c2ecf20Sopenharmony_ci		usb_kill_urb(usbhid->urbin);
7598c2ecf20Sopenharmony_ci		usbhid->intf->needs_remote_wakeup = 0;
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci/*
7668c2ecf20Sopenharmony_ci * Initialize all reports
7678c2ecf20Sopenharmony_ci */
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_civoid usbhid_init_reports(struct hid_device *hid)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	struct hid_report *report;
7728c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
7738c2ecf20Sopenharmony_ci	struct hid_report_enum *report_enum;
7748c2ecf20Sopenharmony_ci	int err, ret;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	report_enum = &hid->report_enum[HID_INPUT_REPORT];
7778c2ecf20Sopenharmony_ci	list_for_each_entry(report, &report_enum->report_list, list)
7788c2ecf20Sopenharmony_ci		usbhid_submit_report(hid, report, USB_DIR_IN);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	report_enum = &hid->report_enum[HID_FEATURE_REPORT];
7818c2ecf20Sopenharmony_ci	list_for_each_entry(report, &report_enum->report_list, list)
7828c2ecf20Sopenharmony_ci		usbhid_submit_report(hid, report, USB_DIR_IN);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	err = 0;
7858c2ecf20Sopenharmony_ci	ret = usbhid_wait_io(hid);
7868c2ecf20Sopenharmony_ci	while (ret) {
7878c2ecf20Sopenharmony_ci		err |= ret;
7888c2ecf20Sopenharmony_ci		if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
7898c2ecf20Sopenharmony_ci			usb_kill_urb(usbhid->urbctrl);
7908c2ecf20Sopenharmony_ci		if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
7918c2ecf20Sopenharmony_ci			usb_kill_urb(usbhid->urbout);
7928c2ecf20Sopenharmony_ci		ret = usbhid_wait_io(hid);
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if (err)
7968c2ecf20Sopenharmony_ci		hid_warn(hid, "timeout initializing reports\n");
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci/*
8008c2ecf20Sopenharmony_ci * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01).
8018c2ecf20Sopenharmony_ci */
8028c2ecf20Sopenharmony_cistatic int hid_find_field_early(struct hid_device *hid, unsigned int page,
8038c2ecf20Sopenharmony_ci    unsigned int hid_code, struct hid_field **pfield)
8048c2ecf20Sopenharmony_ci{
8058c2ecf20Sopenharmony_ci	struct hid_report *report;
8068c2ecf20Sopenharmony_ci	struct hid_field *field;
8078c2ecf20Sopenharmony_ci	struct hid_usage *usage;
8088c2ecf20Sopenharmony_ci	int i, j;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
8118c2ecf20Sopenharmony_ci		for (i = 0; i < report->maxfield; i++) {
8128c2ecf20Sopenharmony_ci			field = report->field[i];
8138c2ecf20Sopenharmony_ci			for (j = 0; j < field->maxusage; j++) {
8148c2ecf20Sopenharmony_ci				usage = &field->usage[j];
8158c2ecf20Sopenharmony_ci				if ((usage->hid & HID_USAGE_PAGE) == page &&
8168c2ecf20Sopenharmony_ci				    (usage->hid & 0xFFFF) == hid_code) {
8178c2ecf20Sopenharmony_ci					*pfield = field;
8188c2ecf20Sopenharmony_ci					return j;
8198c2ecf20Sopenharmony_ci				}
8208c2ecf20Sopenharmony_ci			}
8218c2ecf20Sopenharmony_ci		}
8228c2ecf20Sopenharmony_ci	}
8238c2ecf20Sopenharmony_ci	return -1;
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_cistatic void usbhid_set_leds(struct hid_device *hid)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	struct hid_field *field;
8298c2ecf20Sopenharmony_ci	int offset;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) {
8328c2ecf20Sopenharmony_ci		hid_set_field(field, offset, 0);
8338c2ecf20Sopenharmony_ci		usbhid_submit_report(hid, field->report, USB_DIR_OUT);
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci/*
8388c2ecf20Sopenharmony_ci * Traverse the supplied list of reports and find the longest
8398c2ecf20Sopenharmony_ci */
8408c2ecf20Sopenharmony_cistatic void hid_find_max_report(struct hid_device *hid, unsigned int type,
8418c2ecf20Sopenharmony_ci		unsigned int *max)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	struct hid_report *report;
8448c2ecf20Sopenharmony_ci	unsigned int size;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
8478c2ecf20Sopenharmony_ci		size = ((report->size - 1) >> 3) + 1 + hid->report_enum[type].numbered;
8488c2ecf20Sopenharmony_ci		if (*max < size)
8498c2ecf20Sopenharmony_ci			*max = size;
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	usbhid->inbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
8588c2ecf20Sopenharmony_ci			&usbhid->inbuf_dma);
8598c2ecf20Sopenharmony_ci	usbhid->outbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
8608c2ecf20Sopenharmony_ci			&usbhid->outbuf_dma);
8618c2ecf20Sopenharmony_ci	usbhid->cr = kmalloc(sizeof(*usbhid->cr), GFP_KERNEL);
8628c2ecf20Sopenharmony_ci	usbhid->ctrlbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
8638c2ecf20Sopenharmony_ci			&usbhid->ctrlbuf_dma);
8648c2ecf20Sopenharmony_ci	if (!usbhid->inbuf || !usbhid->outbuf || !usbhid->cr ||
8658c2ecf20Sopenharmony_ci			!usbhid->ctrlbuf)
8668c2ecf20Sopenharmony_ci		return -1;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	return 0;
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_cistatic int usbhid_get_raw_report(struct hid_device *hid,
8728c2ecf20Sopenharmony_ci		unsigned char report_number, __u8 *buf, size_t count,
8738c2ecf20Sopenharmony_ci		unsigned char report_type)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
8768c2ecf20Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
8778c2ecf20Sopenharmony_ci	struct usb_interface *intf = usbhid->intf;
8788c2ecf20Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
8798c2ecf20Sopenharmony_ci	int skipped_report_id = 0;
8808c2ecf20Sopenharmony_ci	int ret;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* Byte 0 is the report number. Report data starts at byte 1.*/
8838c2ecf20Sopenharmony_ci	buf[0] = report_number;
8848c2ecf20Sopenharmony_ci	if (report_number == 0x0) {
8858c2ecf20Sopenharmony_ci		/* Offset the return buffer by 1, so that the report ID
8868c2ecf20Sopenharmony_ci		   will remain in byte 0. */
8878c2ecf20Sopenharmony_ci		buf++;
8888c2ecf20Sopenharmony_ci		count--;
8898c2ecf20Sopenharmony_ci		skipped_report_id = 1;
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
8928c2ecf20Sopenharmony_ci		HID_REQ_GET_REPORT,
8938c2ecf20Sopenharmony_ci		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
8948c2ecf20Sopenharmony_ci		((report_type + 1) << 8) | report_number,
8958c2ecf20Sopenharmony_ci		interface->desc.bInterfaceNumber, buf, count,
8968c2ecf20Sopenharmony_ci		USB_CTRL_SET_TIMEOUT);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	/* count also the report id */
8998c2ecf20Sopenharmony_ci	if (ret > 0 && skipped_report_id)
9008c2ecf20Sopenharmony_ci		ret++;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	return ret;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_cistatic int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
9068c2ecf20Sopenharmony_ci				 __u8 *buf, size_t count, unsigned char rtype)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
9098c2ecf20Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
9108c2ecf20Sopenharmony_ci	struct usb_interface *intf = usbhid->intf;
9118c2ecf20Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
9128c2ecf20Sopenharmony_ci	int ret, skipped_report_id = 0;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	/* Byte 0 is the report number. Report data starts at byte 1.*/
9158c2ecf20Sopenharmony_ci	if ((rtype == HID_OUTPUT_REPORT) &&
9168c2ecf20Sopenharmony_ci	    (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORT_ID))
9178c2ecf20Sopenharmony_ci		buf[0] = 0;
9188c2ecf20Sopenharmony_ci	else
9198c2ecf20Sopenharmony_ci		buf[0] = reportnum;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (buf[0] == 0x0) {
9228c2ecf20Sopenharmony_ci		/* Don't send the Report ID */
9238c2ecf20Sopenharmony_ci		buf++;
9248c2ecf20Sopenharmony_ci		count--;
9258c2ecf20Sopenharmony_ci		skipped_report_id = 1;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
9298c2ecf20Sopenharmony_ci			HID_REQ_SET_REPORT,
9308c2ecf20Sopenharmony_ci			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
9318c2ecf20Sopenharmony_ci			((rtype + 1) << 8) | reportnum,
9328c2ecf20Sopenharmony_ci			interface->desc.bInterfaceNumber, buf, count,
9338c2ecf20Sopenharmony_ci			USB_CTRL_SET_TIMEOUT);
9348c2ecf20Sopenharmony_ci	/* count also the report id, if this was a numbered report. */
9358c2ecf20Sopenharmony_ci	if (ret > 0 && skipped_report_id)
9368c2ecf20Sopenharmony_ci		ret++;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	return ret;
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
9448c2ecf20Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
9458c2ecf20Sopenharmony_ci	int actual_length, skipped_report_id = 0, ret;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	if (!usbhid->urbout)
9488c2ecf20Sopenharmony_ci		return -ENOSYS;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	if (buf[0] == 0x0) {
9518c2ecf20Sopenharmony_ci		/* Don't send the Report ID */
9528c2ecf20Sopenharmony_ci		buf++;
9538c2ecf20Sopenharmony_ci		count--;
9548c2ecf20Sopenharmony_ci		skipped_report_id = 1;
9558c2ecf20Sopenharmony_ci	}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
9588c2ecf20Sopenharmony_ci				buf, count, &actual_length,
9598c2ecf20Sopenharmony_ci				USB_CTRL_SET_TIMEOUT);
9608c2ecf20Sopenharmony_ci	/* return the number of bytes transferred */
9618c2ecf20Sopenharmony_ci	if (ret == 0) {
9628c2ecf20Sopenharmony_ci		ret = actual_length;
9638c2ecf20Sopenharmony_ci		/* count also the report id */
9648c2ecf20Sopenharmony_ci		if (skipped_report_id)
9658c2ecf20Sopenharmony_ci			ret++;
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	return ret;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistatic void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
9728c2ecf20Sopenharmony_ci{
9738c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	usb_free_coherent(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
9768c2ecf20Sopenharmony_ci	usb_free_coherent(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
9778c2ecf20Sopenharmony_ci	kfree(usbhid->cr);
9788c2ecf20Sopenharmony_ci	usb_free_coherent(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_cistatic int usbhid_parse(struct hid_device *hid)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
9848c2ecf20Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
9858c2ecf20Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev (intf);
9868c2ecf20Sopenharmony_ci	struct hid_descriptor *hdesc;
9878c2ecf20Sopenharmony_ci	u32 quirks = 0;
9888c2ecf20Sopenharmony_ci	unsigned int rsize = 0;
9898c2ecf20Sopenharmony_ci	char *rdesc;
9908c2ecf20Sopenharmony_ci	int ret, n;
9918c2ecf20Sopenharmony_ci	int num_descriptors;
9928c2ecf20Sopenharmony_ci	size_t offset = offsetof(struct hid_descriptor, desc);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	quirks = hid_lookup_quirk(hid);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	if (quirks & HID_QUIRK_IGNORE)
9978c2ecf20Sopenharmony_ci		return -ENODEV;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	/* Many keyboards and mice don't like to be polled for reports,
10008c2ecf20Sopenharmony_ci	 * so we will always set the HID_QUIRK_NOGET flag for them. */
10018c2ecf20Sopenharmony_ci	if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
10028c2ecf20Sopenharmony_ci		if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||
10038c2ecf20Sopenharmony_ci			interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
10048c2ecf20Sopenharmony_ci				quirks |= HID_QUIRK_NOGET;
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
10088c2ecf20Sopenharmony_ci	    (!interface->desc.bNumEndpoints ||
10098c2ecf20Sopenharmony_ci	     usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
10108c2ecf20Sopenharmony_ci		dbg_hid("class descriptor not present\n");
10118c2ecf20Sopenharmony_ci		return -ENODEV;
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if (hdesc->bLength < sizeof(struct hid_descriptor)) {
10158c2ecf20Sopenharmony_ci		dbg_hid("hid descriptor is too short\n");
10168c2ecf20Sopenharmony_ci		return -EINVAL;
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	hid->version = le16_to_cpu(hdesc->bcdHID);
10208c2ecf20Sopenharmony_ci	hid->country = hdesc->bCountryCode;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	num_descriptors = min_t(int, hdesc->bNumDescriptors,
10238c2ecf20Sopenharmony_ci	       (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor));
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	for (n = 0; n < num_descriptors; n++)
10268c2ecf20Sopenharmony_ci		if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
10278c2ecf20Sopenharmony_ci			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
10308c2ecf20Sopenharmony_ci		dbg_hid("weird size of report descriptor (%u)\n", rsize);
10318c2ecf20Sopenharmony_ci		return -EINVAL;
10328c2ecf20Sopenharmony_ci	}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	rdesc = kmalloc(rsize, GFP_KERNEL);
10358c2ecf20Sopenharmony_ci	if (!rdesc)
10368c2ecf20Sopenharmony_ci		return -ENOMEM;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	ret = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber,
10418c2ecf20Sopenharmony_ci			HID_DT_REPORT, rdesc, rsize);
10428c2ecf20Sopenharmony_ci	if (ret < 0) {
10438c2ecf20Sopenharmony_ci		dbg_hid("reading report descriptor failed\n");
10448c2ecf20Sopenharmony_ci		kfree(rdesc);
10458c2ecf20Sopenharmony_ci		goto err;
10468c2ecf20Sopenharmony_ci	}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	ret = hid_parse_report(hid, rdesc, rsize);
10498c2ecf20Sopenharmony_ci	kfree(rdesc);
10508c2ecf20Sopenharmony_ci	if (ret) {
10518c2ecf20Sopenharmony_ci		dbg_hid("parsing report descriptor failed\n");
10528c2ecf20Sopenharmony_ci		goto err;
10538c2ecf20Sopenharmony_ci	}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	hid->quirks |= quirks;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	return 0;
10588c2ecf20Sopenharmony_cierr:
10598c2ecf20Sopenharmony_ci	return ret;
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_cistatic int usbhid_start(struct hid_device *hid)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
10658c2ecf20Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
10668c2ecf20Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev(intf);
10678c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
10688c2ecf20Sopenharmony_ci	unsigned int n, insize = 0;
10698c2ecf20Sopenharmony_ci	int ret;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	mutex_lock(&usbhid->mutex);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	clear_bit(HID_DISCONNECTED, &usbhid->iofl);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	usbhid->bufsize = HID_MIN_BUFFER_SIZE;
10768c2ecf20Sopenharmony_ci	hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
10778c2ecf20Sopenharmony_ci	hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
10788c2ecf20Sopenharmony_ci	hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
10818c2ecf20Sopenharmony_ci		usbhid->bufsize = HID_MAX_BUFFER_SIZE;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	if (insize > HID_MAX_BUFFER_SIZE)
10868c2ecf20Sopenharmony_ci		insize = HID_MAX_BUFFER_SIZE;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (hid_alloc_buffers(dev, hid)) {
10898c2ecf20Sopenharmony_ci		ret = -ENOMEM;
10908c2ecf20Sopenharmony_ci		goto fail;
10918c2ecf20Sopenharmony_ci	}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	for (n = 0; n < interface->desc.bNumEndpoints; n++) {
10948c2ecf20Sopenharmony_ci		struct usb_endpoint_descriptor *endpoint;
10958c2ecf20Sopenharmony_ci		int pipe;
10968c2ecf20Sopenharmony_ci		int interval;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci		endpoint = &interface->endpoint[n].desc;
10998c2ecf20Sopenharmony_ci		if (!usb_endpoint_xfer_int(endpoint))
11008c2ecf20Sopenharmony_ci			continue;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci		interval = endpoint->bInterval;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci		/* Some vendors give fullspeed interval on highspeed devides */
11058c2ecf20Sopenharmony_ci		if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
11068c2ecf20Sopenharmony_ci		    dev->speed == USB_SPEED_HIGH) {
11078c2ecf20Sopenharmony_ci			interval = fls(endpoint->bInterval*8);
11088c2ecf20Sopenharmony_ci			pr_info("%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
11098c2ecf20Sopenharmony_ci				hid->name, endpoint->bInterval, interval);
11108c2ecf20Sopenharmony_ci		}
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci		/* Change the polling interval of mice, joysticks
11138c2ecf20Sopenharmony_ci		 * and keyboards.
11148c2ecf20Sopenharmony_ci		 */
11158c2ecf20Sopenharmony_ci		switch (hid->collection->usage) {
11168c2ecf20Sopenharmony_ci		case HID_GD_MOUSE:
11178c2ecf20Sopenharmony_ci			if (hid_mousepoll_interval > 0)
11188c2ecf20Sopenharmony_ci				interval = hid_mousepoll_interval;
11198c2ecf20Sopenharmony_ci			break;
11208c2ecf20Sopenharmony_ci		case HID_GD_JOYSTICK:
11218c2ecf20Sopenharmony_ci			if (hid_jspoll_interval > 0)
11228c2ecf20Sopenharmony_ci				interval = hid_jspoll_interval;
11238c2ecf20Sopenharmony_ci			break;
11248c2ecf20Sopenharmony_ci		case HID_GD_KEYBOARD:
11258c2ecf20Sopenharmony_ci			if (hid_kbpoll_interval > 0)
11268c2ecf20Sopenharmony_ci				interval = hid_kbpoll_interval;
11278c2ecf20Sopenharmony_ci			break;
11288c2ecf20Sopenharmony_ci		}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci		ret = -ENOMEM;
11318c2ecf20Sopenharmony_ci		if (usb_endpoint_dir_in(endpoint)) {
11328c2ecf20Sopenharmony_ci			if (usbhid->urbin)
11338c2ecf20Sopenharmony_ci				continue;
11348c2ecf20Sopenharmony_ci			if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
11358c2ecf20Sopenharmony_ci				goto fail;
11368c2ecf20Sopenharmony_ci			pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
11378c2ecf20Sopenharmony_ci			usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
11388c2ecf20Sopenharmony_ci					 hid_irq_in, hid, interval);
11398c2ecf20Sopenharmony_ci			usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
11408c2ecf20Sopenharmony_ci			usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
11418c2ecf20Sopenharmony_ci		} else {
11428c2ecf20Sopenharmony_ci			if (usbhid->urbout)
11438c2ecf20Sopenharmony_ci				continue;
11448c2ecf20Sopenharmony_ci			if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
11458c2ecf20Sopenharmony_ci				goto fail;
11468c2ecf20Sopenharmony_ci			pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
11478c2ecf20Sopenharmony_ci			usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
11488c2ecf20Sopenharmony_ci					 hid_irq_out, hid, interval);
11498c2ecf20Sopenharmony_ci			usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
11508c2ecf20Sopenharmony_ci			usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
11518c2ecf20Sopenharmony_ci		}
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
11558c2ecf20Sopenharmony_ci	if (!usbhid->urbctrl) {
11568c2ecf20Sopenharmony_ci		ret = -ENOMEM;
11578c2ecf20Sopenharmony_ci		goto fail;
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
11618c2ecf20Sopenharmony_ci			     usbhid->ctrlbuf, 1, hid_ctrl, hid);
11628c2ecf20Sopenharmony_ci	usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
11638c2ecf20Sopenharmony_ci	usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	set_bit(HID_STARTED, &usbhid->iofl);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
11688c2ecf20Sopenharmony_ci		ret = usb_autopm_get_interface(usbhid->intf);
11698c2ecf20Sopenharmony_ci		if (ret)
11708c2ecf20Sopenharmony_ci			goto fail;
11718c2ecf20Sopenharmony_ci		set_bit(HID_IN_POLLING, &usbhid->iofl);
11728c2ecf20Sopenharmony_ci		usbhid->intf->needs_remote_wakeup = 1;
11738c2ecf20Sopenharmony_ci		ret = hid_start_in(hid);
11748c2ecf20Sopenharmony_ci		if (ret) {
11758c2ecf20Sopenharmony_ci			dev_err(&hid->dev,
11768c2ecf20Sopenharmony_ci				"failed to start in urb: %d\n", ret);
11778c2ecf20Sopenharmony_ci		}
11788c2ecf20Sopenharmony_ci		usb_autopm_put_interface(usbhid->intf);
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	/* Some keyboards don't work until their LEDs have been set.
11828c2ecf20Sopenharmony_ci	 * Since BIOSes do set the LEDs, it must be safe for any device
11838c2ecf20Sopenharmony_ci	 * that supports the keyboard boot protocol.
11848c2ecf20Sopenharmony_ci	 * In addition, enable remote wakeup by default for all keyboard
11858c2ecf20Sopenharmony_ci	 * devices supporting the boot protocol.
11868c2ecf20Sopenharmony_ci	 */
11878c2ecf20Sopenharmony_ci	if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT &&
11888c2ecf20Sopenharmony_ci			interface->desc.bInterfaceProtocol ==
11898c2ecf20Sopenharmony_ci				USB_INTERFACE_PROTOCOL_KEYBOARD) {
11908c2ecf20Sopenharmony_ci		usbhid_set_leds(hid);
11918c2ecf20Sopenharmony_ci		device_set_wakeup_enable(&dev->dev, 1);
11928c2ecf20Sopenharmony_ci	}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
11958c2ecf20Sopenharmony_ci	return 0;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_cifail:
11988c2ecf20Sopenharmony_ci	usb_free_urb(usbhid->urbin);
11998c2ecf20Sopenharmony_ci	usb_free_urb(usbhid->urbout);
12008c2ecf20Sopenharmony_ci	usb_free_urb(usbhid->urbctrl);
12018c2ecf20Sopenharmony_ci	usbhid->urbin = NULL;
12028c2ecf20Sopenharmony_ci	usbhid->urbout = NULL;
12038c2ecf20Sopenharmony_ci	usbhid->urbctrl = NULL;
12048c2ecf20Sopenharmony_ci	hid_free_buffers(dev, hid);
12058c2ecf20Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
12068c2ecf20Sopenharmony_ci	return ret;
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cistatic void usbhid_stop(struct hid_device *hid)
12108c2ecf20Sopenharmony_ci{
12118c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	if (WARN_ON(!usbhid))
12148c2ecf20Sopenharmony_ci		return;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
12178c2ecf20Sopenharmony_ci		clear_bit(HID_IN_POLLING, &usbhid->iofl);
12188c2ecf20Sopenharmony_ci		usbhid->intf->needs_remote_wakeup = 0;
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	mutex_lock(&usbhid->mutex);
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	clear_bit(HID_STARTED, &usbhid->iofl);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	spin_lock_irq(&usbhid->lock);	/* Sync with error and led handlers */
12268c2ecf20Sopenharmony_ci	set_bit(HID_DISCONNECTED, &usbhid->iofl);
12278c2ecf20Sopenharmony_ci	while (usbhid->ctrltail != usbhid->ctrlhead) {
12288c2ecf20Sopenharmony_ci		if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_OUT) {
12298c2ecf20Sopenharmony_ci			kfree(usbhid->ctrl[usbhid->ctrltail].raw_report);
12308c2ecf20Sopenharmony_ci			usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
12318c2ecf20Sopenharmony_ci		}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci		usbhid->ctrltail = (usbhid->ctrltail + 1) &
12348c2ecf20Sopenharmony_ci			(HID_CONTROL_FIFO_SIZE - 1);
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	usb_kill_urb(usbhid->urbin);
12398c2ecf20Sopenharmony_ci	usb_kill_urb(usbhid->urbout);
12408c2ecf20Sopenharmony_ci	usb_kill_urb(usbhid->urbctrl);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	hid_cancel_delayed_stuff(usbhid);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	hid->claimed = 0;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	usb_free_urb(usbhid->urbin);
12478c2ecf20Sopenharmony_ci	usb_free_urb(usbhid->urbctrl);
12488c2ecf20Sopenharmony_ci	usb_free_urb(usbhid->urbout);
12498c2ecf20Sopenharmony_ci	usbhid->urbin = NULL; /* don't mess up next start */
12508c2ecf20Sopenharmony_ci	usbhid->urbctrl = NULL;
12518c2ecf20Sopenharmony_ci	usbhid->urbout = NULL;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	hid_free_buffers(hid_to_usb_dev(hid), hid);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
12568c2ecf20Sopenharmony_ci}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_cistatic int usbhid_power(struct hid_device *hid, int lvl)
12598c2ecf20Sopenharmony_ci{
12608c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
12618c2ecf20Sopenharmony_ci	int r = 0;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	switch (lvl) {
12648c2ecf20Sopenharmony_ci	case PM_HINT_FULLON:
12658c2ecf20Sopenharmony_ci		r = usb_autopm_get_interface(usbhid->intf);
12668c2ecf20Sopenharmony_ci		break;
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	case PM_HINT_NORMAL:
12698c2ecf20Sopenharmony_ci		usb_autopm_put_interface(usbhid->intf);
12708c2ecf20Sopenharmony_ci		break;
12718c2ecf20Sopenharmony_ci	}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	return r;
12748c2ecf20Sopenharmony_ci}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cistatic void usbhid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	switch (reqtype) {
12798c2ecf20Sopenharmony_ci	case HID_REQ_GET_REPORT:
12808c2ecf20Sopenharmony_ci		usbhid_submit_report(hid, rep, USB_DIR_IN);
12818c2ecf20Sopenharmony_ci		break;
12828c2ecf20Sopenharmony_ci	case HID_REQ_SET_REPORT:
12838c2ecf20Sopenharmony_ci		usbhid_submit_report(hid, rep, USB_DIR_OUT);
12848c2ecf20Sopenharmony_ci		break;
12858c2ecf20Sopenharmony_ci	}
12868c2ecf20Sopenharmony_ci}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_cistatic int usbhid_raw_request(struct hid_device *hid, unsigned char reportnum,
12898c2ecf20Sopenharmony_ci			      __u8 *buf, size_t len, unsigned char rtype,
12908c2ecf20Sopenharmony_ci			      int reqtype)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	switch (reqtype) {
12938c2ecf20Sopenharmony_ci	case HID_REQ_GET_REPORT:
12948c2ecf20Sopenharmony_ci		return usbhid_get_raw_report(hid, reportnum, buf, len, rtype);
12958c2ecf20Sopenharmony_ci	case HID_REQ_SET_REPORT:
12968c2ecf20Sopenharmony_ci		return usbhid_set_raw_report(hid, reportnum, buf, len, rtype);
12978c2ecf20Sopenharmony_ci	default:
12988c2ecf20Sopenharmony_ci		return -EIO;
12998c2ecf20Sopenharmony_ci	}
13008c2ecf20Sopenharmony_ci}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_cistatic int usbhid_idle(struct hid_device *hid, int report, int idle,
13038c2ecf20Sopenharmony_ci		int reqtype)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
13068c2ecf20Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
13078c2ecf20Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
13088c2ecf20Sopenharmony_ci	int ifnum = interface->desc.bInterfaceNumber;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	if (reqtype != HID_REQ_SET_IDLE)
13118c2ecf20Sopenharmony_ci		return -EINVAL;
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	return hid_set_idle(dev, ifnum, report, idle);
13148c2ecf20Sopenharmony_ci}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_cistruct hid_ll_driver usb_hid_driver = {
13178c2ecf20Sopenharmony_ci	.parse = usbhid_parse,
13188c2ecf20Sopenharmony_ci	.start = usbhid_start,
13198c2ecf20Sopenharmony_ci	.stop = usbhid_stop,
13208c2ecf20Sopenharmony_ci	.open = usbhid_open,
13218c2ecf20Sopenharmony_ci	.close = usbhid_close,
13228c2ecf20Sopenharmony_ci	.power = usbhid_power,
13238c2ecf20Sopenharmony_ci	.request = usbhid_request,
13248c2ecf20Sopenharmony_ci	.wait = usbhid_wait_io,
13258c2ecf20Sopenharmony_ci	.raw_request = usbhid_raw_request,
13268c2ecf20Sopenharmony_ci	.output_report = usbhid_output_report,
13278c2ecf20Sopenharmony_ci	.idle = usbhid_idle,
13288c2ecf20Sopenharmony_ci};
13298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_hid_driver);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cistatic int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
13348c2ecf20Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev(intf);
13358c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid;
13368c2ecf20Sopenharmony_ci	struct hid_device *hid;
13378c2ecf20Sopenharmony_ci	unsigned int n, has_in = 0;
13388c2ecf20Sopenharmony_ci	size_t len;
13398c2ecf20Sopenharmony_ci	int ret;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	dbg_hid("HID probe called for ifnum %d\n",
13428c2ecf20Sopenharmony_ci			intf->altsetting->desc.bInterfaceNumber);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	for (n = 0; n < interface->desc.bNumEndpoints; n++)
13458c2ecf20Sopenharmony_ci		if (usb_endpoint_is_int_in(&interface->endpoint[n].desc))
13468c2ecf20Sopenharmony_ci			has_in++;
13478c2ecf20Sopenharmony_ci	if (!has_in) {
13488c2ecf20Sopenharmony_ci		hid_err(intf, "couldn't find an input interrupt endpoint\n");
13498c2ecf20Sopenharmony_ci		return -ENODEV;
13508c2ecf20Sopenharmony_ci	}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	hid = hid_allocate_device();
13538c2ecf20Sopenharmony_ci	if (IS_ERR(hid))
13548c2ecf20Sopenharmony_ci		return PTR_ERR(hid);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	usb_set_intfdata(intf, hid);
13578c2ecf20Sopenharmony_ci	hid->ll_driver = &usb_hid_driver;
13588c2ecf20Sopenharmony_ci	hid->ff_init = hid_pidff_init;
13598c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_HIDDEV
13608c2ecf20Sopenharmony_ci	hid->hiddev_connect = hiddev_connect;
13618c2ecf20Sopenharmony_ci	hid->hiddev_disconnect = hiddev_disconnect;
13628c2ecf20Sopenharmony_ci	hid->hiddev_hid_event = hiddev_hid_event;
13638c2ecf20Sopenharmony_ci	hid->hiddev_report_event = hiddev_report_event;
13648c2ecf20Sopenharmony_ci#endif
13658c2ecf20Sopenharmony_ci	hid->dev.parent = &intf->dev;
13668c2ecf20Sopenharmony_ci	hid->bus = BUS_USB;
13678c2ecf20Sopenharmony_ci	hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
13688c2ecf20Sopenharmony_ci	hid->product = le16_to_cpu(dev->descriptor.idProduct);
13698c2ecf20Sopenharmony_ci	hid->version = le16_to_cpu(dev->descriptor.bcdDevice);
13708c2ecf20Sopenharmony_ci	hid->name[0] = 0;
13718c2ecf20Sopenharmony_ci	if (intf->cur_altsetting->desc.bInterfaceProtocol ==
13728c2ecf20Sopenharmony_ci			USB_INTERFACE_PROTOCOL_MOUSE)
13738c2ecf20Sopenharmony_ci		hid->type = HID_TYPE_USBMOUSE;
13748c2ecf20Sopenharmony_ci	else if (intf->cur_altsetting->desc.bInterfaceProtocol == 0)
13758c2ecf20Sopenharmony_ci		hid->type = HID_TYPE_USBNONE;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	if (dev->manufacturer)
13788c2ecf20Sopenharmony_ci		strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	if (dev->product) {
13818c2ecf20Sopenharmony_ci		if (dev->manufacturer)
13828c2ecf20Sopenharmony_ci			strlcat(hid->name, " ", sizeof(hid->name));
13838c2ecf20Sopenharmony_ci		strlcat(hid->name, dev->product, sizeof(hid->name));
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	if (!strlen(hid->name))
13878c2ecf20Sopenharmony_ci		snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
13888c2ecf20Sopenharmony_ci			 le16_to_cpu(dev->descriptor.idVendor),
13898c2ecf20Sopenharmony_ci			 le16_to_cpu(dev->descriptor.idProduct));
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	usb_make_path(dev, hid->phys, sizeof(hid->phys));
13928c2ecf20Sopenharmony_ci	strlcat(hid->phys, "/input", sizeof(hid->phys));
13938c2ecf20Sopenharmony_ci	len = strlen(hid->phys);
13948c2ecf20Sopenharmony_ci	if (len < sizeof(hid->phys) - 1)
13958c2ecf20Sopenharmony_ci		snprintf(hid->phys + len, sizeof(hid->phys) - len,
13968c2ecf20Sopenharmony_ci			 "%d", intf->altsetting[0].desc.bInterfaceNumber);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
13998c2ecf20Sopenharmony_ci		hid->uniq[0] = 0;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	usbhid = kzalloc(sizeof(*usbhid), GFP_KERNEL);
14028c2ecf20Sopenharmony_ci	if (usbhid == NULL) {
14038c2ecf20Sopenharmony_ci		ret = -ENOMEM;
14048c2ecf20Sopenharmony_ci		goto err;
14058c2ecf20Sopenharmony_ci	}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	hid->driver_data = usbhid;
14088c2ecf20Sopenharmony_ci	usbhid->hid = hid;
14098c2ecf20Sopenharmony_ci	usbhid->intf = intf;
14108c2ecf20Sopenharmony_ci	usbhid->ifnum = interface->desc.bInterfaceNumber;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	init_waitqueue_head(&usbhid->wait);
14138c2ecf20Sopenharmony_ci	INIT_WORK(&usbhid->reset_work, hid_reset);
14148c2ecf20Sopenharmony_ci	timer_setup(&usbhid->io_retry, hid_retry_timeout, 0);
14158c2ecf20Sopenharmony_ci	spin_lock_init(&usbhid->lock);
14168c2ecf20Sopenharmony_ci	mutex_init(&usbhid->mutex);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	ret = hid_add_device(hid);
14198c2ecf20Sopenharmony_ci	if (ret) {
14208c2ecf20Sopenharmony_ci		if (ret != -ENODEV)
14218c2ecf20Sopenharmony_ci			hid_err(intf, "can't add hid device: %d\n", ret);
14228c2ecf20Sopenharmony_ci		goto err_free;
14238c2ecf20Sopenharmony_ci	}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	return 0;
14268c2ecf20Sopenharmony_cierr_free:
14278c2ecf20Sopenharmony_ci	kfree(usbhid);
14288c2ecf20Sopenharmony_cierr:
14298c2ecf20Sopenharmony_ci	hid_destroy_device(hid);
14308c2ecf20Sopenharmony_ci	return ret;
14318c2ecf20Sopenharmony_ci}
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_cistatic void usbhid_disconnect(struct usb_interface *intf)
14348c2ecf20Sopenharmony_ci{
14358c2ecf20Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
14368c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid;
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	if (WARN_ON(!hid))
14398c2ecf20Sopenharmony_ci		return;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	usbhid = hid->driver_data;
14428c2ecf20Sopenharmony_ci	spin_lock_irq(&usbhid->lock);	/* Sync with error and led handlers */
14438c2ecf20Sopenharmony_ci	set_bit(HID_DISCONNECTED, &usbhid->iofl);
14448c2ecf20Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
14458c2ecf20Sopenharmony_ci	hid_destroy_device(hid);
14468c2ecf20Sopenharmony_ci	kfree(usbhid);
14478c2ecf20Sopenharmony_ci}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_cistatic void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
14508c2ecf20Sopenharmony_ci{
14518c2ecf20Sopenharmony_ci	del_timer_sync(&usbhid->io_retry);
14528c2ecf20Sopenharmony_ci	cancel_work_sync(&usbhid->reset_work);
14538c2ecf20Sopenharmony_ci}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_cistatic void hid_cease_io(struct usbhid_device *usbhid)
14568c2ecf20Sopenharmony_ci{
14578c2ecf20Sopenharmony_ci	del_timer_sync(&usbhid->io_retry);
14588c2ecf20Sopenharmony_ci	usb_kill_urb(usbhid->urbin);
14598c2ecf20Sopenharmony_ci	usb_kill_urb(usbhid->urbctrl);
14608c2ecf20Sopenharmony_ci	usb_kill_urb(usbhid->urbout);
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic void hid_restart_io(struct hid_device *hid)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
14668c2ecf20Sopenharmony_ci	int clear_halt = test_bit(HID_CLEAR_HALT, &usbhid->iofl);
14678c2ecf20Sopenharmony_ci	int reset_pending = test_bit(HID_RESET_PENDING, &usbhid->iofl);
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
14708c2ecf20Sopenharmony_ci	clear_bit(HID_SUSPENDED, &usbhid->iofl);
14718c2ecf20Sopenharmony_ci	usbhid_mark_busy(usbhid);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (clear_halt || reset_pending)
14748c2ecf20Sopenharmony_ci		schedule_work(&usbhid->reset_work);
14758c2ecf20Sopenharmony_ci	usbhid->retry_delay = 0;
14768c2ecf20Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	if (reset_pending || !test_bit(HID_STARTED, &usbhid->iofl))
14798c2ecf20Sopenharmony_ci		return;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	if (!clear_halt) {
14828c2ecf20Sopenharmony_ci		if (hid_start_in(hid) < 0)
14838c2ecf20Sopenharmony_ci			hid_io_error(hid);
14848c2ecf20Sopenharmony_ci	}
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
14878c2ecf20Sopenharmony_ci	if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
14888c2ecf20Sopenharmony_ci		usbhid_restart_out_queue(usbhid);
14898c2ecf20Sopenharmony_ci	if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
14908c2ecf20Sopenharmony_ci		usbhid_restart_ctrl_queue(usbhid);
14918c2ecf20Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
14928c2ecf20Sopenharmony_ci}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci/* Treat USB reset pretty much the same as suspend/resume */
14958c2ecf20Sopenharmony_cistatic int hid_pre_reset(struct usb_interface *intf)
14968c2ecf20Sopenharmony_ci{
14978c2ecf20Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
14988c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
15018c2ecf20Sopenharmony_ci	set_bit(HID_RESET_PENDING, &usbhid->iofl);
15028c2ecf20Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
15038c2ecf20Sopenharmony_ci	hid_cease_io(usbhid);
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	return 0;
15068c2ecf20Sopenharmony_ci}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci/* Same routine used for post_reset and reset_resume */
15098c2ecf20Sopenharmony_cistatic int hid_post_reset(struct usb_interface *intf)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev (intf);
15128c2ecf20Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
15138c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
15148c2ecf20Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
15158c2ecf20Sopenharmony_ci	int status;
15168c2ecf20Sopenharmony_ci	char *rdesc;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	/* Fetch and examine the HID report descriptor. If this
15198c2ecf20Sopenharmony_ci	 * has changed, then rebind. Since usbcore's check of the
15208c2ecf20Sopenharmony_ci	 * configuration descriptors passed, we already know that
15218c2ecf20Sopenharmony_ci	 * the size of the HID report descriptor has not changed.
15228c2ecf20Sopenharmony_ci	 */
15238c2ecf20Sopenharmony_ci	rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
15248c2ecf20Sopenharmony_ci	if (!rdesc)
15258c2ecf20Sopenharmony_ci		return -ENOMEM;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	status = hid_get_class_descriptor(dev,
15288c2ecf20Sopenharmony_ci				interface->desc.bInterfaceNumber,
15298c2ecf20Sopenharmony_ci				HID_DT_REPORT, rdesc, hid->dev_rsize);
15308c2ecf20Sopenharmony_ci	if (status < 0) {
15318c2ecf20Sopenharmony_ci		dbg_hid("reading report descriptor failed (post_reset)\n");
15328c2ecf20Sopenharmony_ci		kfree(rdesc);
15338c2ecf20Sopenharmony_ci		return status;
15348c2ecf20Sopenharmony_ci	}
15358c2ecf20Sopenharmony_ci	status = memcmp(rdesc, hid->dev_rdesc, hid->dev_rsize);
15368c2ecf20Sopenharmony_ci	kfree(rdesc);
15378c2ecf20Sopenharmony_ci	if (status != 0) {
15388c2ecf20Sopenharmony_ci		dbg_hid("report descriptor changed\n");
15398c2ecf20Sopenharmony_ci		return -EPERM;
15408c2ecf20Sopenharmony_ci	}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	/* No need to do another reset or clear a halted endpoint */
15438c2ecf20Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
15448c2ecf20Sopenharmony_ci	clear_bit(HID_RESET_PENDING, &usbhid->iofl);
15458c2ecf20Sopenharmony_ci	clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
15468c2ecf20Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
15478c2ecf20Sopenharmony_ci	hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	hid_restart_io(hid);
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	return 0;
15528c2ecf20Sopenharmony_ci}
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
15558c2ecf20Sopenharmony_cistatic int hid_resume_common(struct hid_device *hid, bool driver_suspended)
15568c2ecf20Sopenharmony_ci{
15578c2ecf20Sopenharmony_ci	int status = 0;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	hid_restart_io(hid);
15608c2ecf20Sopenharmony_ci	if (driver_suspended && hid->driver && hid->driver->resume)
15618c2ecf20Sopenharmony_ci		status = hid->driver->resume(hid);
15628c2ecf20Sopenharmony_ci	return status;
15638c2ecf20Sopenharmony_ci}
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_cistatic int hid_suspend(struct usb_interface *intf, pm_message_t message)
15668c2ecf20Sopenharmony_ci{
15678c2ecf20Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
15688c2ecf20Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
15698c2ecf20Sopenharmony_ci	int status = 0;
15708c2ecf20Sopenharmony_ci	bool driver_suspended = false;
15718c2ecf20Sopenharmony_ci	unsigned int ledcount;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	if (PMSG_IS_AUTO(message)) {
15748c2ecf20Sopenharmony_ci		ledcount = hidinput_count_leds(hid);
15758c2ecf20Sopenharmony_ci		spin_lock_irq(&usbhid->lock);	/* Sync with error handler */
15768c2ecf20Sopenharmony_ci		if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
15778c2ecf20Sopenharmony_ci		    && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
15788c2ecf20Sopenharmony_ci		    && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
15798c2ecf20Sopenharmony_ci		    && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
15808c2ecf20Sopenharmony_ci		    && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
15818c2ecf20Sopenharmony_ci		    && (!ledcount || ignoreled))
15828c2ecf20Sopenharmony_ci		{
15838c2ecf20Sopenharmony_ci			set_bit(HID_SUSPENDED, &usbhid->iofl);
15848c2ecf20Sopenharmony_ci			spin_unlock_irq(&usbhid->lock);
15858c2ecf20Sopenharmony_ci			if (hid->driver && hid->driver->suspend) {
15868c2ecf20Sopenharmony_ci				status = hid->driver->suspend(hid, message);
15878c2ecf20Sopenharmony_ci				if (status < 0)
15888c2ecf20Sopenharmony_ci					goto failed;
15898c2ecf20Sopenharmony_ci			}
15908c2ecf20Sopenharmony_ci			driver_suspended = true;
15918c2ecf20Sopenharmony_ci		} else {
15928c2ecf20Sopenharmony_ci			usbhid_mark_busy(usbhid);
15938c2ecf20Sopenharmony_ci			spin_unlock_irq(&usbhid->lock);
15948c2ecf20Sopenharmony_ci			return -EBUSY;
15958c2ecf20Sopenharmony_ci		}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	} else {
15988c2ecf20Sopenharmony_ci		/* TODO: resume() might need to handle suspend failure */
15998c2ecf20Sopenharmony_ci		if (hid->driver && hid->driver->suspend)
16008c2ecf20Sopenharmony_ci			status = hid->driver->suspend(hid, message);
16018c2ecf20Sopenharmony_ci		driver_suspended = true;
16028c2ecf20Sopenharmony_ci		spin_lock_irq(&usbhid->lock);
16038c2ecf20Sopenharmony_ci		set_bit(HID_SUSPENDED, &usbhid->iofl);
16048c2ecf20Sopenharmony_ci		spin_unlock_irq(&usbhid->lock);
16058c2ecf20Sopenharmony_ci		if (usbhid_wait_io(hid) < 0)
16068c2ecf20Sopenharmony_ci			status = -EIO;
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	hid_cancel_delayed_stuff(usbhid);
16108c2ecf20Sopenharmony_ci	hid_cease_io(usbhid);
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
16138c2ecf20Sopenharmony_ci		/* lost race against keypresses */
16148c2ecf20Sopenharmony_ci		status = -EBUSY;
16158c2ecf20Sopenharmony_ci		goto failed;
16168c2ecf20Sopenharmony_ci	}
16178c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "suspend\n");
16188c2ecf20Sopenharmony_ci	return status;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci failed:
16218c2ecf20Sopenharmony_ci	hid_resume_common(hid, driver_suspended);
16228c2ecf20Sopenharmony_ci	return status;
16238c2ecf20Sopenharmony_ci}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_cistatic int hid_resume(struct usb_interface *intf)
16268c2ecf20Sopenharmony_ci{
16278c2ecf20Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata (intf);
16288c2ecf20Sopenharmony_ci	int status;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	status = hid_resume_common(hid, true);
16318c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "resume status %d\n", status);
16328c2ecf20Sopenharmony_ci	return 0;
16338c2ecf20Sopenharmony_ci}
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_cistatic int hid_reset_resume(struct usb_interface *intf)
16368c2ecf20Sopenharmony_ci{
16378c2ecf20Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
16388c2ecf20Sopenharmony_ci	int status;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	status = hid_post_reset(intf);
16418c2ecf20Sopenharmony_ci	if (status >= 0 && hid->driver && hid->driver->reset_resume) {
16428c2ecf20Sopenharmony_ci		int ret = hid->driver->reset_resume(hid);
16438c2ecf20Sopenharmony_ci		if (ret < 0)
16448c2ecf20Sopenharmony_ci			status = ret;
16458c2ecf20Sopenharmony_ci	}
16468c2ecf20Sopenharmony_ci	return status;
16478c2ecf20Sopenharmony_ci}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_cistatic const struct usb_device_id hid_usb_ids[] = {
16528c2ecf20Sopenharmony_ci	{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
16538c2ecf20Sopenharmony_ci		.bInterfaceClass = USB_INTERFACE_CLASS_HID },
16548c2ecf20Sopenharmony_ci	{ }						/* Terminating entry */
16558c2ecf20Sopenharmony_ci};
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (usb, hid_usb_ids);
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_cistatic struct usb_driver hid_driver = {
16608c2ecf20Sopenharmony_ci	.name =		"usbhid",
16618c2ecf20Sopenharmony_ci	.probe =	usbhid_probe,
16628c2ecf20Sopenharmony_ci	.disconnect =	usbhid_disconnect,
16638c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
16648c2ecf20Sopenharmony_ci	.suspend =	hid_suspend,
16658c2ecf20Sopenharmony_ci	.resume =	hid_resume,
16668c2ecf20Sopenharmony_ci	.reset_resume =	hid_reset_resume,
16678c2ecf20Sopenharmony_ci#endif
16688c2ecf20Sopenharmony_ci	.pre_reset =	hid_pre_reset,
16698c2ecf20Sopenharmony_ci	.post_reset =	hid_post_reset,
16708c2ecf20Sopenharmony_ci	.id_table =	hid_usb_ids,
16718c2ecf20Sopenharmony_ci	.supports_autosuspend = 1,
16728c2ecf20Sopenharmony_ci};
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_cistruct usb_interface *usbhid_find_interface(int minor)
16758c2ecf20Sopenharmony_ci{
16768c2ecf20Sopenharmony_ci	return usb_find_interface(&hid_driver, minor);
16778c2ecf20Sopenharmony_ci}
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_cistatic int __init hid_init(void)
16808c2ecf20Sopenharmony_ci{
16818c2ecf20Sopenharmony_ci	int retval;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	retval = hid_quirks_init(quirks_param, BUS_USB, MAX_USBHID_BOOT_QUIRKS);
16848c2ecf20Sopenharmony_ci	if (retval)
16858c2ecf20Sopenharmony_ci		goto usbhid_quirks_init_fail;
16868c2ecf20Sopenharmony_ci	retval = usb_register(&hid_driver);
16878c2ecf20Sopenharmony_ci	if (retval)
16888c2ecf20Sopenharmony_ci		goto usb_register_fail;
16898c2ecf20Sopenharmony_ci	pr_info(KBUILD_MODNAME ": " DRIVER_DESC "\n");
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	return 0;
16928c2ecf20Sopenharmony_ciusb_register_fail:
16938c2ecf20Sopenharmony_ci	hid_quirks_exit(BUS_USB);
16948c2ecf20Sopenharmony_ciusbhid_quirks_init_fail:
16958c2ecf20Sopenharmony_ci	return retval;
16968c2ecf20Sopenharmony_ci}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_cistatic void __exit hid_exit(void)
16998c2ecf20Sopenharmony_ci{
17008c2ecf20Sopenharmony_ci	usb_deregister(&hid_driver);
17018c2ecf20Sopenharmony_ci	hid_quirks_exit(BUS_USB);
17028c2ecf20Sopenharmony_ci}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_cimodule_init(hid_init);
17058c2ecf20Sopenharmony_cimodule_exit(hid_exit);
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andreas Gal");
17088c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vojtech Pavlik");
17098c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jiri Kosina");
17108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
17118c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1712