162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  USB HID support for Linux
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 1999 Andreas Gal
662306a36Sopenharmony_ci *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
762306a36Sopenharmony_ci *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
862306a36Sopenharmony_ci *  Copyright (c) 2007-2008 Oliver Neukum
962306a36Sopenharmony_ci *  Copyright (c) 2006-2010 Jiri Kosina
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/list.h>
2062306a36Sopenharmony_ci#include <linux/mm.h>
2162306a36Sopenharmony_ci#include <linux/mutex.h>
2262306a36Sopenharmony_ci#include <linux/spinlock.h>
2362306a36Sopenharmony_ci#include <asm/unaligned.h>
2462306a36Sopenharmony_ci#include <asm/byteorder.h>
2562306a36Sopenharmony_ci#include <linux/input.h>
2662306a36Sopenharmony_ci#include <linux/wait.h>
2762306a36Sopenharmony_ci#include <linux/workqueue.h>
2862306a36Sopenharmony_ci#include <linux/string.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <linux/usb.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <linux/hid.h>
3362306a36Sopenharmony_ci#include <linux/hiddev.h>
3462306a36Sopenharmony_ci#include <linux/hid-debug.h>
3562306a36Sopenharmony_ci#include <linux/hidraw.h>
3662306a36Sopenharmony_ci#include "usbhid.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/*
3962306a36Sopenharmony_ci * Version Information
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define DRIVER_DESC "USB HID core driver"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*
4562306a36Sopenharmony_ci * Module parameters.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic unsigned int hid_mousepoll_interval;
4962306a36Sopenharmony_cimodule_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
5062306a36Sopenharmony_ciMODULE_PARM_DESC(mousepoll, "Polling interval of mice");
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic unsigned int hid_jspoll_interval;
5362306a36Sopenharmony_cimodule_param_named(jspoll, hid_jspoll_interval, uint, 0644);
5462306a36Sopenharmony_ciMODULE_PARM_DESC(jspoll, "Polling interval of joysticks");
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic unsigned int hid_kbpoll_interval;
5762306a36Sopenharmony_cimodule_param_named(kbpoll, hid_kbpoll_interval, uint, 0644);
5862306a36Sopenharmony_ciMODULE_PARM_DESC(kbpoll, "Polling interval of keyboards");
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic unsigned int ignoreled;
6162306a36Sopenharmony_cimodule_param_named(ignoreled, ignoreled, uint, 0644);
6262306a36Sopenharmony_ciMODULE_PARM_DESC(ignoreled, "Autosuspend with active leds");
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Quirks specified at module load time */
6562306a36Sopenharmony_cistatic char *quirks_param[MAX_USBHID_BOOT_QUIRKS];
6662306a36Sopenharmony_cimodule_param_array_named(quirks, quirks_param, charp, NULL, 0444);
6762306a36Sopenharmony_ciMODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
6862306a36Sopenharmony_ci		" quirks=vendorID:productID:quirks"
6962306a36Sopenharmony_ci		" where vendorID, productID, and quirks are all in"
7062306a36Sopenharmony_ci		" 0x-prefixed hex");
7162306a36Sopenharmony_ci/*
7262306a36Sopenharmony_ci * Input submission and I/O error handler.
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_cistatic void hid_io_error(struct hid_device *hid);
7562306a36Sopenharmony_cistatic int hid_submit_out(struct hid_device *hid);
7662306a36Sopenharmony_cistatic int hid_submit_ctrl(struct hid_device *hid);
7762306a36Sopenharmony_cistatic void hid_cancel_delayed_stuff(struct usbhid_device *usbhid);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Start up the input URB */
8062306a36Sopenharmony_cistatic int hid_start_in(struct hid_device *hid)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	unsigned long flags;
8362306a36Sopenharmony_ci	int rc = 0;
8462306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
8762306a36Sopenharmony_ci	if (test_bit(HID_IN_POLLING, &usbhid->iofl) &&
8862306a36Sopenharmony_ci	    !test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
8962306a36Sopenharmony_ci	    !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
9062306a36Sopenharmony_ci	    !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
9162306a36Sopenharmony_ci		rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
9262306a36Sopenharmony_ci		if (rc != 0) {
9362306a36Sopenharmony_ci			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
9462306a36Sopenharmony_ci			if (rc == -ENOSPC)
9562306a36Sopenharmony_ci				set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
9662306a36Sopenharmony_ci		} else {
9762306a36Sopenharmony_ci			clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
10162306a36Sopenharmony_ci	return rc;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* I/O retry timer routine */
10562306a36Sopenharmony_cistatic void hid_retry_timeout(struct timer_list *t)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct usbhid_device *usbhid = from_timer(usbhid, t, io_retry);
10862306a36Sopenharmony_ci	struct hid_device *hid = usbhid->hid;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
11162306a36Sopenharmony_ci	if (hid_start_in(hid))
11262306a36Sopenharmony_ci		hid_io_error(hid);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Workqueue routine to reset the device or clear a halt */
11662306a36Sopenharmony_cistatic void hid_reset(struct work_struct *work)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct usbhid_device *usbhid =
11962306a36Sopenharmony_ci		container_of(work, struct usbhid_device, reset_work);
12062306a36Sopenharmony_ci	struct hid_device *hid = usbhid->hid;
12162306a36Sopenharmony_ci	int rc;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
12462306a36Sopenharmony_ci		dev_dbg(&usbhid->intf->dev, "clear halt\n");
12562306a36Sopenharmony_ci		rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe);
12662306a36Sopenharmony_ci		clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
12762306a36Sopenharmony_ci		if (rc == 0) {
12862306a36Sopenharmony_ci			hid_start_in(hid);
12962306a36Sopenharmony_ci		} else {
13062306a36Sopenharmony_ci			dev_dbg(&usbhid->intf->dev,
13162306a36Sopenharmony_ci					"clear-halt failed: %d\n", rc);
13262306a36Sopenharmony_ci			set_bit(HID_RESET_PENDING, &usbhid->iofl);
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
13762306a36Sopenharmony_ci		dev_dbg(&usbhid->intf->dev, "resetting device\n");
13862306a36Sopenharmony_ci		usb_queue_reset_device(usbhid->intf);
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* Main I/O error handler */
14362306a36Sopenharmony_cistatic void hid_io_error(struct hid_device *hid)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	unsigned long flags;
14662306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* Stop when disconnected */
15162306a36Sopenharmony_ci	if (test_bit(HID_DISCONNECTED, &usbhid->iofl))
15262306a36Sopenharmony_ci		goto done;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* If it has been a while since the last error, we'll assume
15562306a36Sopenharmony_ci	 * this a brand new error and reset the retry timeout. */
15662306a36Sopenharmony_ci	if (time_after(jiffies, usbhid->stop_retry + HZ/2))
15762306a36Sopenharmony_ci		usbhid->retry_delay = 0;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* When an error occurs, retry at increasing intervals */
16062306a36Sopenharmony_ci	if (usbhid->retry_delay == 0) {
16162306a36Sopenharmony_ci		usbhid->retry_delay = 13;	/* Then 26, 52, 104, 104, ... */
16262306a36Sopenharmony_ci		usbhid->stop_retry = jiffies + msecs_to_jiffies(1000);
16362306a36Sopenharmony_ci	} else if (usbhid->retry_delay < 100)
16462306a36Sopenharmony_ci		usbhid->retry_delay *= 2;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (time_after(jiffies, usbhid->stop_retry)) {
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		/* Retries failed, so do a port reset unless we lack bandwidth*/
16962306a36Sopenharmony_ci		if (!test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
17062306a36Sopenharmony_ci		     && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci			schedule_work(&usbhid->reset_work);
17362306a36Sopenharmony_ci			goto done;
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	mod_timer(&usbhid->io_retry,
17862306a36Sopenharmony_ci			jiffies + msecs_to_jiffies(usbhid->retry_delay));
17962306a36Sopenharmony_cidone:
18062306a36Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void usbhid_mark_busy(struct usbhid_device *usbhid)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct usb_interface *intf = usbhid->intf;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	usb_mark_last_busy(interface_to_usbdev(intf));
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int usbhid_restart_out_queue(struct usbhid_device *usbhid)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(usbhid->intf);
19362306a36Sopenharmony_ci	int kicked;
19462306a36Sopenharmony_ci	int r;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (!hid || test_bit(HID_RESET_PENDING, &usbhid->iofl) ||
19762306a36Sopenharmony_ci			test_bit(HID_SUSPENDED, &usbhid->iofl))
19862306a36Sopenharmony_ci		return 0;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if ((kicked = (usbhid->outhead != usbhid->outtail))) {
20162306a36Sopenharmony_ci		hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		/* Try to wake up from autosuspend... */
20462306a36Sopenharmony_ci		r = usb_autopm_get_interface_async(usbhid->intf);
20562306a36Sopenharmony_ci		if (r < 0)
20662306a36Sopenharmony_ci			return r;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci		/*
20962306a36Sopenharmony_ci		 * If still suspended, don't submit.  Submission will
21062306a36Sopenharmony_ci		 * occur if/when resume drains the queue.
21162306a36Sopenharmony_ci		 */
21262306a36Sopenharmony_ci		if (test_bit(HID_SUSPENDED, &usbhid->iofl)) {
21362306a36Sopenharmony_ci			usb_autopm_put_interface_no_suspend(usbhid->intf);
21462306a36Sopenharmony_ci			return r;
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		/* Asynchronously flush queue. */
21862306a36Sopenharmony_ci		set_bit(HID_OUT_RUNNING, &usbhid->iofl);
21962306a36Sopenharmony_ci		if (hid_submit_out(hid)) {
22062306a36Sopenharmony_ci			clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
22162306a36Sopenharmony_ci			usb_autopm_put_interface_async(usbhid->intf);
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci		wake_up(&usbhid->wait);
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci	return kicked;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(usbhid->intf);
23162306a36Sopenharmony_ci	int kicked;
23262306a36Sopenharmony_ci	int r;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	WARN_ON(hid == NULL);
23562306a36Sopenharmony_ci	if (!hid || test_bit(HID_RESET_PENDING, &usbhid->iofl) ||
23662306a36Sopenharmony_ci			test_bit(HID_SUSPENDED, &usbhid->iofl))
23762306a36Sopenharmony_ci		return 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) {
24062306a36Sopenharmony_ci		hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		/* Try to wake up from autosuspend... */
24362306a36Sopenharmony_ci		r = usb_autopm_get_interface_async(usbhid->intf);
24462306a36Sopenharmony_ci		if (r < 0)
24562306a36Sopenharmony_ci			return r;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		/*
24862306a36Sopenharmony_ci		 * If still suspended, don't submit.  Submission will
24962306a36Sopenharmony_ci		 * occur if/when resume drains the queue.
25062306a36Sopenharmony_ci		 */
25162306a36Sopenharmony_ci		if (test_bit(HID_SUSPENDED, &usbhid->iofl)) {
25262306a36Sopenharmony_ci			usb_autopm_put_interface_no_suspend(usbhid->intf);
25362306a36Sopenharmony_ci			return r;
25462306a36Sopenharmony_ci		}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		/* Asynchronously flush queue. */
25762306a36Sopenharmony_ci		set_bit(HID_CTRL_RUNNING, &usbhid->iofl);
25862306a36Sopenharmony_ci		if (hid_submit_ctrl(hid)) {
25962306a36Sopenharmony_ci			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
26062306a36Sopenharmony_ci			usb_autopm_put_interface_async(usbhid->intf);
26162306a36Sopenharmony_ci		}
26262306a36Sopenharmony_ci		wake_up(&usbhid->wait);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci	return kicked;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * Input interrupt completion handler.
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void hid_irq_in(struct urb *urb)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct hid_device	*hid = urb->context;
27462306a36Sopenharmony_ci	struct usbhid_device	*usbhid = hid->driver_data;
27562306a36Sopenharmony_ci	int			status;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	switch (urb->status) {
27862306a36Sopenharmony_ci	case 0:			/* success */
27962306a36Sopenharmony_ci		usbhid->retry_delay = 0;
28062306a36Sopenharmony_ci		if (!test_bit(HID_OPENED, &usbhid->iofl))
28162306a36Sopenharmony_ci			break;
28262306a36Sopenharmony_ci		usbhid_mark_busy(usbhid);
28362306a36Sopenharmony_ci		if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
28462306a36Sopenharmony_ci			hid_input_report(urb->context, HID_INPUT_REPORT,
28562306a36Sopenharmony_ci					 urb->transfer_buffer,
28662306a36Sopenharmony_ci					 urb->actual_length, 1);
28762306a36Sopenharmony_ci			/*
28862306a36Sopenharmony_ci			 * autosuspend refused while keys are pressed
28962306a36Sopenharmony_ci			 * because most keyboards don't wake up when
29062306a36Sopenharmony_ci			 * a key is released
29162306a36Sopenharmony_ci			 */
29262306a36Sopenharmony_ci			if (hid_check_keys_pressed(hid))
29362306a36Sopenharmony_ci				set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
29462306a36Sopenharmony_ci			else
29562306a36Sopenharmony_ci				clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
29662306a36Sopenharmony_ci		}
29762306a36Sopenharmony_ci		break;
29862306a36Sopenharmony_ci	case -EPIPE:		/* stall */
29962306a36Sopenharmony_ci		usbhid_mark_busy(usbhid);
30062306a36Sopenharmony_ci		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
30162306a36Sopenharmony_ci		set_bit(HID_CLEAR_HALT, &usbhid->iofl);
30262306a36Sopenharmony_ci		schedule_work(&usbhid->reset_work);
30362306a36Sopenharmony_ci		return;
30462306a36Sopenharmony_ci	case -ECONNRESET:	/* unlink */
30562306a36Sopenharmony_ci	case -ENOENT:
30662306a36Sopenharmony_ci	case -ESHUTDOWN:	/* unplug */
30762306a36Sopenharmony_ci		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
30862306a36Sopenharmony_ci		return;
30962306a36Sopenharmony_ci	case -EILSEQ:		/* protocol error or unplug */
31062306a36Sopenharmony_ci	case -EPROTO:		/* protocol error or unplug */
31162306a36Sopenharmony_ci	case -ETIME:		/* protocol error or unplug */
31262306a36Sopenharmony_ci	case -ETIMEDOUT:	/* Should never happen, but... */
31362306a36Sopenharmony_ci		usbhid_mark_busy(usbhid);
31462306a36Sopenharmony_ci		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
31562306a36Sopenharmony_ci		hid_io_error(hid);
31662306a36Sopenharmony_ci		return;
31762306a36Sopenharmony_ci	default:		/* error */
31862306a36Sopenharmony_ci		hid_warn(urb->dev, "input irq status %d received\n",
31962306a36Sopenharmony_ci			 urb->status);
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	status = usb_submit_urb(urb, GFP_ATOMIC);
32362306a36Sopenharmony_ci	if (status) {
32462306a36Sopenharmony_ci		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
32562306a36Sopenharmony_ci		if (status != -EPERM) {
32662306a36Sopenharmony_ci			hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n",
32762306a36Sopenharmony_ci				hid_to_usb_dev(hid)->bus->bus_name,
32862306a36Sopenharmony_ci				hid_to_usb_dev(hid)->devpath,
32962306a36Sopenharmony_ci				usbhid->ifnum, status);
33062306a36Sopenharmony_ci			hid_io_error(hid);
33162306a36Sopenharmony_ci		}
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int hid_submit_out(struct hid_device *hid)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct hid_report *report;
33862306a36Sopenharmony_ci	char *raw_report;
33962306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
34062306a36Sopenharmony_ci	int r;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	report = usbhid->out[usbhid->outtail].report;
34362306a36Sopenharmony_ci	raw_report = usbhid->out[usbhid->outtail].raw_report;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	usbhid->urbout->transfer_buffer_length = hid_report_len(report);
34662306a36Sopenharmony_ci	usbhid->urbout->dev = hid_to_usb_dev(hid);
34762306a36Sopenharmony_ci	if (raw_report) {
34862306a36Sopenharmony_ci		memcpy(usbhid->outbuf, raw_report,
34962306a36Sopenharmony_ci				usbhid->urbout->transfer_buffer_length);
35062306a36Sopenharmony_ci		kfree(raw_report);
35162306a36Sopenharmony_ci		usbhid->out[usbhid->outtail].raw_report = NULL;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	dbg_hid("submitting out urb\n");
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	r = usb_submit_urb(usbhid->urbout, GFP_ATOMIC);
35762306a36Sopenharmony_ci	if (r < 0) {
35862306a36Sopenharmony_ci		hid_err(hid, "usb_submit_urb(out) failed: %d\n", r);
35962306a36Sopenharmony_ci		return r;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci	usbhid->last_out = jiffies;
36262306a36Sopenharmony_ci	return 0;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int hid_submit_ctrl(struct hid_device *hid)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	struct hid_report *report;
36862306a36Sopenharmony_ci	unsigned char dir;
36962306a36Sopenharmony_ci	char *raw_report;
37062306a36Sopenharmony_ci	int len, r;
37162306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	report = usbhid->ctrl[usbhid->ctrltail].report;
37462306a36Sopenharmony_ci	raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
37562306a36Sopenharmony_ci	dir = usbhid->ctrl[usbhid->ctrltail].dir;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	len = hid_report_len(report);
37862306a36Sopenharmony_ci	if (dir == USB_DIR_OUT) {
37962306a36Sopenharmony_ci		usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
38062306a36Sopenharmony_ci		if (raw_report) {
38162306a36Sopenharmony_ci			memcpy(usbhid->ctrlbuf, raw_report, len);
38262306a36Sopenharmony_ci			kfree(raw_report);
38362306a36Sopenharmony_ci			usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
38462306a36Sopenharmony_ci		}
38562306a36Sopenharmony_ci	} else {
38662306a36Sopenharmony_ci		int maxpacket;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
38962306a36Sopenharmony_ci		maxpacket = usb_maxpacket(hid_to_usb_dev(hid),
39062306a36Sopenharmony_ci					  usbhid->urbctrl->pipe);
39162306a36Sopenharmony_ci		len += (len == 0);	/* Don't allow 0-length reports */
39262306a36Sopenharmony_ci		len = round_up(len, maxpacket);
39362306a36Sopenharmony_ci		if (len > usbhid->bufsize)
39462306a36Sopenharmony_ci			len = usbhid->bufsize;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci	usbhid->urbctrl->transfer_buffer_length = len;
39762306a36Sopenharmony_ci	usbhid->urbctrl->dev = hid_to_usb_dev(hid);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
40062306a36Sopenharmony_ci	usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT :
40162306a36Sopenharmony_ci						      HID_REQ_GET_REPORT;
40262306a36Sopenharmony_ci	usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) |
40362306a36Sopenharmony_ci					 report->id);
40462306a36Sopenharmony_ci	usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
40562306a36Sopenharmony_ci	usbhid->cr->wLength = cpu_to_le16(len);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n",
40862306a36Sopenharmony_ci		usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" :
40962306a36Sopenharmony_ci							     "Get_Report",
41062306a36Sopenharmony_ci		usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	r = usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC);
41362306a36Sopenharmony_ci	if (r < 0) {
41462306a36Sopenharmony_ci		hid_err(hid, "usb_submit_urb(ctrl) failed: %d\n", r);
41562306a36Sopenharmony_ci		return r;
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci	usbhid->last_ctrl = jiffies;
41862306a36Sopenharmony_ci	return 0;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/*
42262306a36Sopenharmony_ci * Output interrupt completion handler.
42362306a36Sopenharmony_ci */
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic void hid_irq_out(struct urb *urb)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct hid_device *hid = urb->context;
42862306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
42962306a36Sopenharmony_ci	unsigned long flags;
43062306a36Sopenharmony_ci	int unplug = 0;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	switch (urb->status) {
43362306a36Sopenharmony_ci	case 0:			/* success */
43462306a36Sopenharmony_ci		break;
43562306a36Sopenharmony_ci	case -ESHUTDOWN:	/* unplug */
43662306a36Sopenharmony_ci		unplug = 1;
43762306a36Sopenharmony_ci		break;
43862306a36Sopenharmony_ci	case -EILSEQ:		/* protocol error or unplug */
43962306a36Sopenharmony_ci	case -EPROTO:		/* protocol error or unplug */
44062306a36Sopenharmony_ci	case -ECONNRESET:	/* unlink */
44162306a36Sopenharmony_ci	case -ENOENT:
44262306a36Sopenharmony_ci		break;
44362306a36Sopenharmony_ci	default:		/* error */
44462306a36Sopenharmony_ci		hid_warn(urb->dev, "output irq status %d received\n",
44562306a36Sopenharmony_ci			 urb->status);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (unplug) {
45162306a36Sopenharmony_ci		usbhid->outtail = usbhid->outhead;
45262306a36Sopenharmony_ci	} else {
45362306a36Sopenharmony_ci		usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		if (usbhid->outhead != usbhid->outtail &&
45662306a36Sopenharmony_ci				hid_submit_out(hid) == 0) {
45762306a36Sopenharmony_ci			/* Successfully submitted next urb in queue */
45862306a36Sopenharmony_ci			spin_unlock_irqrestore(&usbhid->lock, flags);
45962306a36Sopenharmony_ci			return;
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
46462306a36Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
46562306a36Sopenharmony_ci	usb_autopm_put_interface_async(usbhid->intf);
46662306a36Sopenharmony_ci	wake_up(&usbhid->wait);
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci/*
47062306a36Sopenharmony_ci * Control pipe completion handler.
47162306a36Sopenharmony_ci */
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic void hid_ctrl(struct urb *urb)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	struct hid_device *hid = urb->context;
47662306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
47762306a36Sopenharmony_ci	unsigned long flags;
47862306a36Sopenharmony_ci	int unplug = 0, status = urb->status;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	switch (status) {
48162306a36Sopenharmony_ci	case 0:			/* success */
48262306a36Sopenharmony_ci		if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
48362306a36Sopenharmony_ci			hid_input_report(urb->context,
48462306a36Sopenharmony_ci				usbhid->ctrl[usbhid->ctrltail].report->type,
48562306a36Sopenharmony_ci				urb->transfer_buffer, urb->actual_length, 0);
48662306a36Sopenharmony_ci		break;
48762306a36Sopenharmony_ci	case -ESHUTDOWN:	/* unplug */
48862306a36Sopenharmony_ci		unplug = 1;
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci	case -EILSEQ:		/* protocol error or unplug */
49162306a36Sopenharmony_ci	case -EPROTO:		/* protocol error or unplug */
49262306a36Sopenharmony_ci	case -ECONNRESET:	/* unlink */
49362306a36Sopenharmony_ci	case -ENOENT:
49462306a36Sopenharmony_ci	case -EPIPE:		/* report not available */
49562306a36Sopenharmony_ci		break;
49662306a36Sopenharmony_ci	default:		/* error */
49762306a36Sopenharmony_ci		hid_warn(urb->dev, "ctrl urb status %d received\n", status);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (unplug) {
50362306a36Sopenharmony_ci		usbhid->ctrltail = usbhid->ctrlhead;
50462306a36Sopenharmony_ci	} else if (usbhid->ctrlhead != usbhid->ctrltail) {
50562306a36Sopenharmony_ci		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		if (usbhid->ctrlhead != usbhid->ctrltail &&
50862306a36Sopenharmony_ci				hid_submit_ctrl(hid) == 0) {
50962306a36Sopenharmony_ci			/* Successfully submitted next urb in queue */
51062306a36Sopenharmony_ci			spin_unlock_irqrestore(&usbhid->lock, flags);
51162306a36Sopenharmony_ci			return;
51262306a36Sopenharmony_ci		}
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
51662306a36Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
51762306a36Sopenharmony_ci	usb_autopm_put_interface_async(usbhid->intf);
51862306a36Sopenharmony_ci	wake_up(&usbhid->wait);
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report,
52262306a36Sopenharmony_ci				   unsigned char dir)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	int head;
52562306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) ||
52862306a36Sopenharmony_ci		test_bit(HID_DISCONNECTED, &usbhid->iofl))
52962306a36Sopenharmony_ci		return;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
53262306a36Sopenharmony_ci		if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
53362306a36Sopenharmony_ci			hid_warn(hid, "output queue full\n");
53462306a36Sopenharmony_ci			return;
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
53862306a36Sopenharmony_ci		if (!usbhid->out[usbhid->outhead].raw_report) {
53962306a36Sopenharmony_ci			hid_warn(hid, "output queueing failed\n");
54062306a36Sopenharmony_ci			return;
54162306a36Sopenharmony_ci		}
54262306a36Sopenharmony_ci		hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
54362306a36Sopenharmony_ci		usbhid->out[usbhid->outhead].report = report;
54462306a36Sopenharmony_ci		usbhid->outhead = head;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		/* If the queue isn't running, restart it */
54762306a36Sopenharmony_ci		if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) {
54862306a36Sopenharmony_ci			usbhid_restart_out_queue(usbhid);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		/* Otherwise see if an earlier request has timed out */
55162306a36Sopenharmony_ci		} else if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci			/* Prevent autosuspend following the unlink */
55462306a36Sopenharmony_ci			usb_autopm_get_interface_no_resume(usbhid->intf);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci			/*
55762306a36Sopenharmony_ci			 * Prevent resubmission in case the URB completes
55862306a36Sopenharmony_ci			 * before we can unlink it.  We don't want to cancel
55962306a36Sopenharmony_ci			 * the wrong transfer!
56062306a36Sopenharmony_ci			 */
56162306a36Sopenharmony_ci			usb_block_urb(usbhid->urbout);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci			/* Drop lock to avoid deadlock if the callback runs */
56462306a36Sopenharmony_ci			spin_unlock(&usbhid->lock);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci			usb_unlink_urb(usbhid->urbout);
56762306a36Sopenharmony_ci			spin_lock(&usbhid->lock);
56862306a36Sopenharmony_ci			usb_unblock_urb(usbhid->urbout);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci			/* Unlink might have stopped the queue */
57162306a36Sopenharmony_ci			if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl))
57262306a36Sopenharmony_ci				usbhid_restart_out_queue(usbhid);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci			/* Now we can allow autosuspend again */
57562306a36Sopenharmony_ci			usb_autopm_put_interface_async(usbhid->intf);
57662306a36Sopenharmony_ci		}
57762306a36Sopenharmony_ci		return;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
58162306a36Sopenharmony_ci		hid_warn(hid, "control queue full\n");
58262306a36Sopenharmony_ci		return;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if (dir == USB_DIR_OUT) {
58662306a36Sopenharmony_ci		usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
58762306a36Sopenharmony_ci		if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
58862306a36Sopenharmony_ci			hid_warn(hid, "control queueing failed\n");
58962306a36Sopenharmony_ci			return;
59062306a36Sopenharmony_ci		}
59162306a36Sopenharmony_ci		hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	usbhid->ctrl[usbhid->ctrlhead].report = report;
59462306a36Sopenharmony_ci	usbhid->ctrl[usbhid->ctrlhead].dir = dir;
59562306a36Sopenharmony_ci	usbhid->ctrlhead = head;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* If the queue isn't running, restart it */
59862306a36Sopenharmony_ci	if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) {
59962306a36Sopenharmony_ci		usbhid_restart_ctrl_queue(usbhid);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* Otherwise see if an earlier request has timed out */
60262306a36Sopenharmony_ci	} else if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci		/* Prevent autosuspend following the unlink */
60562306a36Sopenharmony_ci		usb_autopm_get_interface_no_resume(usbhid->intf);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci		/*
60862306a36Sopenharmony_ci		 * Prevent resubmission in case the URB completes
60962306a36Sopenharmony_ci		 * before we can unlink it.  We don't want to cancel
61062306a36Sopenharmony_ci		 * the wrong transfer!
61162306a36Sopenharmony_ci		 */
61262306a36Sopenharmony_ci		usb_block_urb(usbhid->urbctrl);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		/* Drop lock to avoid deadlock if the callback runs */
61562306a36Sopenharmony_ci		spin_unlock(&usbhid->lock);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		usb_unlink_urb(usbhid->urbctrl);
61862306a36Sopenharmony_ci		spin_lock(&usbhid->lock);
61962306a36Sopenharmony_ci		usb_unblock_urb(usbhid->urbctrl);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		/* Unlink might have stopped the queue */
62262306a36Sopenharmony_ci		if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
62362306a36Sopenharmony_ci			usbhid_restart_ctrl_queue(usbhid);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		/* Now we can allow autosuspend again */
62662306a36Sopenharmony_ci		usb_autopm_put_interface_async(usbhid->intf);
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
63362306a36Sopenharmony_ci	unsigned long flags;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	spin_lock_irqsave(&usbhid->lock, flags);
63662306a36Sopenharmony_ci	__usbhid_submit_report(hid, report, dir);
63762306a36Sopenharmony_ci	spin_unlock_irqrestore(&usbhid->lock, flags);
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic int usbhid_wait_io(struct hid_device *hid)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	if (!wait_event_timeout(usbhid->wait,
64562306a36Sopenharmony_ci				(!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
64662306a36Sopenharmony_ci				!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
64762306a36Sopenharmony_ci					10*HZ)) {
64862306a36Sopenharmony_ci		dbg_hid("timeout waiting for ctrl or out queue to clear\n");
64962306a36Sopenharmony_ci		return -1;
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	return 0;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
65862306a36Sopenharmony_ci		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
65962306a36Sopenharmony_ci		ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
66362306a36Sopenharmony_ci		unsigned char type, void *buf, int size)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	int result, retries = 4;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	memset(buf, 0, size);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	do {
67062306a36Sopenharmony_ci		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
67162306a36Sopenharmony_ci				USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
67262306a36Sopenharmony_ci				(type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);
67362306a36Sopenharmony_ci		retries--;
67462306a36Sopenharmony_ci	} while (result < size && retries);
67562306a36Sopenharmony_ci	return result;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic int usbhid_open(struct hid_device *hid)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
68162306a36Sopenharmony_ci	int res;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	mutex_lock(&usbhid->mutex);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	set_bit(HID_OPENED, &usbhid->iofl);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
68862306a36Sopenharmony_ci		res = 0;
68962306a36Sopenharmony_ci		goto Done;
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	res = usb_autopm_get_interface(usbhid->intf);
69362306a36Sopenharmony_ci	/* the device must be awake to reliably request remote wakeup */
69462306a36Sopenharmony_ci	if (res < 0) {
69562306a36Sopenharmony_ci		clear_bit(HID_OPENED, &usbhid->iofl);
69662306a36Sopenharmony_ci		res = -EIO;
69762306a36Sopenharmony_ci		goto Done;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	usbhid->intf->needs_remote_wakeup = 1;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	set_bit(HID_RESUME_RUNNING, &usbhid->iofl);
70362306a36Sopenharmony_ci	set_bit(HID_IN_POLLING, &usbhid->iofl);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	res = hid_start_in(hid);
70662306a36Sopenharmony_ci	if (res) {
70762306a36Sopenharmony_ci		if (res != -ENOSPC) {
70862306a36Sopenharmony_ci			hid_io_error(hid);
70962306a36Sopenharmony_ci			res = 0;
71062306a36Sopenharmony_ci		} else {
71162306a36Sopenharmony_ci			/* no use opening if resources are insufficient */
71262306a36Sopenharmony_ci			res = -EBUSY;
71362306a36Sopenharmony_ci			clear_bit(HID_OPENED, &usbhid->iofl);
71462306a36Sopenharmony_ci			clear_bit(HID_IN_POLLING, &usbhid->iofl);
71562306a36Sopenharmony_ci			usbhid->intf->needs_remote_wakeup = 0;
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	usb_autopm_put_interface(usbhid->intf);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/*
72262306a36Sopenharmony_ci	 * In case events are generated while nobody was listening,
72362306a36Sopenharmony_ci	 * some are released when the device is re-opened.
72462306a36Sopenharmony_ci	 * Wait 50 msec for the queue to empty before allowing events
72562306a36Sopenharmony_ci	 * to go through hid.
72662306a36Sopenharmony_ci	 */
72762306a36Sopenharmony_ci	if (res == 0)
72862306a36Sopenharmony_ci		msleep(50);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci Done:
73362306a36Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
73462306a36Sopenharmony_ci	return res;
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic void usbhid_close(struct hid_device *hid)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	mutex_lock(&usbhid->mutex);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/*
74462306a36Sopenharmony_ci	 * Make sure we don't restart data acquisition due to
74562306a36Sopenharmony_ci	 * a resumption we no longer care about by avoiding racing
74662306a36Sopenharmony_ci	 * with hid_start_in().
74762306a36Sopenharmony_ci	 */
74862306a36Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
74962306a36Sopenharmony_ci	clear_bit(HID_OPENED, &usbhid->iofl);
75062306a36Sopenharmony_ci	if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL))
75162306a36Sopenharmony_ci		clear_bit(HID_IN_POLLING, &usbhid->iofl);
75262306a36Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) {
75562306a36Sopenharmony_ci		hid_cancel_delayed_stuff(usbhid);
75662306a36Sopenharmony_ci		usb_kill_urb(usbhid->urbin);
75762306a36Sopenharmony_ci		usbhid->intf->needs_remote_wakeup = 0;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci/*
76462306a36Sopenharmony_ci * Initialize all reports
76562306a36Sopenharmony_ci */
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_civoid usbhid_init_reports(struct hid_device *hid)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	struct hid_report *report;
77062306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
77162306a36Sopenharmony_ci	struct hid_report_enum *report_enum;
77262306a36Sopenharmony_ci	int err, ret;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	report_enum = &hid->report_enum[HID_INPUT_REPORT];
77562306a36Sopenharmony_ci	list_for_each_entry(report, &report_enum->report_list, list)
77662306a36Sopenharmony_ci		usbhid_submit_report(hid, report, USB_DIR_IN);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	report_enum = &hid->report_enum[HID_FEATURE_REPORT];
77962306a36Sopenharmony_ci	list_for_each_entry(report, &report_enum->report_list, list)
78062306a36Sopenharmony_ci		usbhid_submit_report(hid, report, USB_DIR_IN);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	err = 0;
78362306a36Sopenharmony_ci	ret = usbhid_wait_io(hid);
78462306a36Sopenharmony_ci	while (ret) {
78562306a36Sopenharmony_ci		err |= ret;
78662306a36Sopenharmony_ci		if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
78762306a36Sopenharmony_ci			usb_kill_urb(usbhid->urbctrl);
78862306a36Sopenharmony_ci		if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
78962306a36Sopenharmony_ci			usb_kill_urb(usbhid->urbout);
79062306a36Sopenharmony_ci		ret = usbhid_wait_io(hid);
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	if (err)
79462306a36Sopenharmony_ci		hid_warn(hid, "timeout initializing reports\n");
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci/*
79862306a36Sopenharmony_ci * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01).
79962306a36Sopenharmony_ci */
80062306a36Sopenharmony_cistatic int hid_find_field_early(struct hid_device *hid, unsigned int page,
80162306a36Sopenharmony_ci    unsigned int hid_code, struct hid_field **pfield)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct hid_report *report;
80462306a36Sopenharmony_ci	struct hid_field *field;
80562306a36Sopenharmony_ci	struct hid_usage *usage;
80662306a36Sopenharmony_ci	int i, j;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
80962306a36Sopenharmony_ci		for (i = 0; i < report->maxfield; i++) {
81062306a36Sopenharmony_ci			field = report->field[i];
81162306a36Sopenharmony_ci			for (j = 0; j < field->maxusage; j++) {
81262306a36Sopenharmony_ci				usage = &field->usage[j];
81362306a36Sopenharmony_ci				if ((usage->hid & HID_USAGE_PAGE) == page &&
81462306a36Sopenharmony_ci				    (usage->hid & 0xFFFF) == hid_code) {
81562306a36Sopenharmony_ci					*pfield = field;
81662306a36Sopenharmony_ci					return j;
81762306a36Sopenharmony_ci				}
81862306a36Sopenharmony_ci			}
81962306a36Sopenharmony_ci		}
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci	return -1;
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_cistatic void usbhid_set_leds(struct hid_device *hid)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	struct hid_field *field;
82762306a36Sopenharmony_ci	int offset;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) {
83062306a36Sopenharmony_ci		hid_set_field(field, offset, 0);
83162306a36Sopenharmony_ci		usbhid_submit_report(hid, field->report, USB_DIR_OUT);
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci/*
83662306a36Sopenharmony_ci * Traverse the supplied list of reports and find the longest
83762306a36Sopenharmony_ci */
83862306a36Sopenharmony_cistatic void hid_find_max_report(struct hid_device *hid, unsigned int type,
83962306a36Sopenharmony_ci		unsigned int *max)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	struct hid_report *report;
84262306a36Sopenharmony_ci	unsigned int size;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
84562306a36Sopenharmony_ci		size = ((report->size - 1) >> 3) + 1 + hid->report_enum[type].numbered;
84662306a36Sopenharmony_ci		if (*max < size)
84762306a36Sopenharmony_ci			*max = size;
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	usbhid->inbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
85662306a36Sopenharmony_ci			&usbhid->inbuf_dma);
85762306a36Sopenharmony_ci	usbhid->outbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
85862306a36Sopenharmony_ci			&usbhid->outbuf_dma);
85962306a36Sopenharmony_ci	usbhid->cr = kmalloc(sizeof(*usbhid->cr), GFP_KERNEL);
86062306a36Sopenharmony_ci	usbhid->ctrlbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
86162306a36Sopenharmony_ci			&usbhid->ctrlbuf_dma);
86262306a36Sopenharmony_ci	if (!usbhid->inbuf || !usbhid->outbuf || !usbhid->cr ||
86362306a36Sopenharmony_ci			!usbhid->ctrlbuf)
86462306a36Sopenharmony_ci		return -1;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	return 0;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic int usbhid_get_raw_report(struct hid_device *hid,
87062306a36Sopenharmony_ci		unsigned char report_number, __u8 *buf, size_t count,
87162306a36Sopenharmony_ci		unsigned char report_type)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
87462306a36Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
87562306a36Sopenharmony_ci	struct usb_interface *intf = usbhid->intf;
87662306a36Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
87762306a36Sopenharmony_ci	int skipped_report_id = 0;
87862306a36Sopenharmony_ci	int ret;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* Byte 0 is the report number. Report data starts at byte 1.*/
88162306a36Sopenharmony_ci	buf[0] = report_number;
88262306a36Sopenharmony_ci	if (report_number == 0x0) {
88362306a36Sopenharmony_ci		/* Offset the return buffer by 1, so that the report ID
88462306a36Sopenharmony_ci		   will remain in byte 0. */
88562306a36Sopenharmony_ci		buf++;
88662306a36Sopenharmony_ci		count--;
88762306a36Sopenharmony_ci		skipped_report_id = 1;
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
89062306a36Sopenharmony_ci		HID_REQ_GET_REPORT,
89162306a36Sopenharmony_ci		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
89262306a36Sopenharmony_ci		((report_type + 1) << 8) | report_number,
89362306a36Sopenharmony_ci		interface->desc.bInterfaceNumber, buf, count,
89462306a36Sopenharmony_ci		USB_CTRL_SET_TIMEOUT);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	/* count also the report id */
89762306a36Sopenharmony_ci	if (ret > 0 && skipped_report_id)
89862306a36Sopenharmony_ci		ret++;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	return ret;
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cistatic int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
90462306a36Sopenharmony_ci				 __u8 *buf, size_t count, unsigned char rtype)
90562306a36Sopenharmony_ci{
90662306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
90762306a36Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
90862306a36Sopenharmony_ci	struct usb_interface *intf = usbhid->intf;
90962306a36Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
91062306a36Sopenharmony_ci	int ret, skipped_report_id = 0;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	/* Byte 0 is the report number. Report data starts at byte 1.*/
91362306a36Sopenharmony_ci	if ((rtype == HID_OUTPUT_REPORT) &&
91462306a36Sopenharmony_ci	    (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORT_ID))
91562306a36Sopenharmony_ci		buf[0] = 0;
91662306a36Sopenharmony_ci	else
91762306a36Sopenharmony_ci		buf[0] = reportnum;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	if (buf[0] == 0x0) {
92062306a36Sopenharmony_ci		/* Don't send the Report ID */
92162306a36Sopenharmony_ci		buf++;
92262306a36Sopenharmony_ci		count--;
92362306a36Sopenharmony_ci		skipped_report_id = 1;
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
92762306a36Sopenharmony_ci			HID_REQ_SET_REPORT,
92862306a36Sopenharmony_ci			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
92962306a36Sopenharmony_ci			((rtype + 1) << 8) | reportnum,
93062306a36Sopenharmony_ci			interface->desc.bInterfaceNumber, buf, count,
93162306a36Sopenharmony_ci			USB_CTRL_SET_TIMEOUT);
93262306a36Sopenharmony_ci	/* count also the report id, if this was a numbered report. */
93362306a36Sopenharmony_ci	if (ret > 0 && skipped_report_id)
93462306a36Sopenharmony_ci		ret++;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	return ret;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
94262306a36Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
94362306a36Sopenharmony_ci	int actual_length, skipped_report_id = 0, ret;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	if (!usbhid->urbout)
94662306a36Sopenharmony_ci		return -ENOSYS;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	if (buf[0] == 0x0) {
94962306a36Sopenharmony_ci		/* Don't send the Report ID */
95062306a36Sopenharmony_ci		buf++;
95162306a36Sopenharmony_ci		count--;
95262306a36Sopenharmony_ci		skipped_report_id = 1;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
95662306a36Sopenharmony_ci				buf, count, &actual_length,
95762306a36Sopenharmony_ci				USB_CTRL_SET_TIMEOUT);
95862306a36Sopenharmony_ci	/* return the number of bytes transferred */
95962306a36Sopenharmony_ci	if (ret == 0) {
96062306a36Sopenharmony_ci		ret = actual_length;
96162306a36Sopenharmony_ci		/* count also the report id */
96262306a36Sopenharmony_ci		if (skipped_report_id)
96362306a36Sopenharmony_ci			ret++;
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	return ret;
96762306a36Sopenharmony_ci}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_cistatic void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	usb_free_coherent(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
97462306a36Sopenharmony_ci	usb_free_coherent(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
97562306a36Sopenharmony_ci	kfree(usbhid->cr);
97662306a36Sopenharmony_ci	usb_free_coherent(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic int usbhid_parse(struct hid_device *hid)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
98262306a36Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
98362306a36Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev (intf);
98462306a36Sopenharmony_ci	struct hid_descriptor *hdesc;
98562306a36Sopenharmony_ci	u32 quirks = 0;
98662306a36Sopenharmony_ci	unsigned int rsize = 0;
98762306a36Sopenharmony_ci	char *rdesc;
98862306a36Sopenharmony_ci	int ret, n;
98962306a36Sopenharmony_ci	int num_descriptors;
99062306a36Sopenharmony_ci	size_t offset = offsetof(struct hid_descriptor, desc);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	quirks = hid_lookup_quirk(hid);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (quirks & HID_QUIRK_IGNORE)
99562306a36Sopenharmony_ci		return -ENODEV;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/* Many keyboards and mice don't like to be polled for reports,
99862306a36Sopenharmony_ci	 * so we will always set the HID_QUIRK_NOGET flag for them. */
99962306a36Sopenharmony_ci	if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
100062306a36Sopenharmony_ci		if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||
100162306a36Sopenharmony_ci			interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
100262306a36Sopenharmony_ci				quirks |= HID_QUIRK_NOGET;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
100662306a36Sopenharmony_ci	    (!interface->desc.bNumEndpoints ||
100762306a36Sopenharmony_ci	     usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
100862306a36Sopenharmony_ci		dbg_hid("class descriptor not present\n");
100962306a36Sopenharmony_ci		return -ENODEV;
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	if (hdesc->bLength < sizeof(struct hid_descriptor)) {
101362306a36Sopenharmony_ci		dbg_hid("hid descriptor is too short\n");
101462306a36Sopenharmony_ci		return -EINVAL;
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	hid->version = le16_to_cpu(hdesc->bcdHID);
101862306a36Sopenharmony_ci	hid->country = hdesc->bCountryCode;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	num_descriptors = min_t(int, hdesc->bNumDescriptors,
102162306a36Sopenharmony_ci	       (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor));
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	for (n = 0; n < num_descriptors; n++)
102462306a36Sopenharmony_ci		if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
102562306a36Sopenharmony_ci			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
102862306a36Sopenharmony_ci		dbg_hid("weird size of report descriptor (%u)\n", rsize);
102962306a36Sopenharmony_ci		return -EINVAL;
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	rdesc = kmalloc(rsize, GFP_KERNEL);
103362306a36Sopenharmony_ci	if (!rdesc)
103462306a36Sopenharmony_ci		return -ENOMEM;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	ret = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber,
103962306a36Sopenharmony_ci			HID_DT_REPORT, rdesc, rsize);
104062306a36Sopenharmony_ci	if (ret < 0) {
104162306a36Sopenharmony_ci		dbg_hid("reading report descriptor failed\n");
104262306a36Sopenharmony_ci		kfree(rdesc);
104362306a36Sopenharmony_ci		goto err;
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	ret = hid_parse_report(hid, rdesc, rsize);
104762306a36Sopenharmony_ci	kfree(rdesc);
104862306a36Sopenharmony_ci	if (ret) {
104962306a36Sopenharmony_ci		dbg_hid("parsing report descriptor failed\n");
105062306a36Sopenharmony_ci		goto err;
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	hid->quirks |= quirks;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	return 0;
105662306a36Sopenharmony_cierr:
105762306a36Sopenharmony_ci	return ret;
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic int usbhid_start(struct hid_device *hid)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
106362306a36Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
106462306a36Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev(intf);
106562306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
106662306a36Sopenharmony_ci	unsigned int n, insize = 0;
106762306a36Sopenharmony_ci	int ret;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	mutex_lock(&usbhid->mutex);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	clear_bit(HID_DISCONNECTED, &usbhid->iofl);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	usbhid->bufsize = HID_MIN_BUFFER_SIZE;
107462306a36Sopenharmony_ci	hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
107562306a36Sopenharmony_ci	hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
107662306a36Sopenharmony_ci	hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
107962306a36Sopenharmony_ci		usbhid->bufsize = HID_MAX_BUFFER_SIZE;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (insize > HID_MAX_BUFFER_SIZE)
108462306a36Sopenharmony_ci		insize = HID_MAX_BUFFER_SIZE;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (hid_alloc_buffers(dev, hid)) {
108762306a36Sopenharmony_ci		ret = -ENOMEM;
108862306a36Sopenharmony_ci		goto fail;
108962306a36Sopenharmony_ci	}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	for (n = 0; n < interface->desc.bNumEndpoints; n++) {
109262306a36Sopenharmony_ci		struct usb_endpoint_descriptor *endpoint;
109362306a36Sopenharmony_ci		int pipe;
109462306a36Sopenharmony_ci		int interval;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci		endpoint = &interface->endpoint[n].desc;
109762306a36Sopenharmony_ci		if (!usb_endpoint_xfer_int(endpoint))
109862306a36Sopenharmony_ci			continue;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci		interval = endpoint->bInterval;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci		/* Some vendors give fullspeed interval on highspeed devides */
110362306a36Sopenharmony_ci		if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
110462306a36Sopenharmony_ci		    dev->speed == USB_SPEED_HIGH) {
110562306a36Sopenharmony_ci			interval = fls(endpoint->bInterval*8);
110662306a36Sopenharmony_ci			pr_info("%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
110762306a36Sopenharmony_ci				hid->name, endpoint->bInterval, interval);
110862306a36Sopenharmony_ci		}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		/* Change the polling interval of mice, joysticks
111162306a36Sopenharmony_ci		 * and keyboards.
111262306a36Sopenharmony_ci		 */
111362306a36Sopenharmony_ci		switch (hid->collection->usage) {
111462306a36Sopenharmony_ci		case HID_GD_MOUSE:
111562306a36Sopenharmony_ci			if (hid_mousepoll_interval > 0)
111662306a36Sopenharmony_ci				interval = hid_mousepoll_interval;
111762306a36Sopenharmony_ci			break;
111862306a36Sopenharmony_ci		case HID_GD_JOYSTICK:
111962306a36Sopenharmony_ci			if (hid_jspoll_interval > 0)
112062306a36Sopenharmony_ci				interval = hid_jspoll_interval;
112162306a36Sopenharmony_ci			break;
112262306a36Sopenharmony_ci		case HID_GD_KEYBOARD:
112362306a36Sopenharmony_ci			if (hid_kbpoll_interval > 0)
112462306a36Sopenharmony_ci				interval = hid_kbpoll_interval;
112562306a36Sopenharmony_ci			break;
112662306a36Sopenharmony_ci		}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci		ret = -ENOMEM;
112962306a36Sopenharmony_ci		if (usb_endpoint_dir_in(endpoint)) {
113062306a36Sopenharmony_ci			if (usbhid->urbin)
113162306a36Sopenharmony_ci				continue;
113262306a36Sopenharmony_ci			if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
113362306a36Sopenharmony_ci				goto fail;
113462306a36Sopenharmony_ci			pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
113562306a36Sopenharmony_ci			usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
113662306a36Sopenharmony_ci					 hid_irq_in, hid, interval);
113762306a36Sopenharmony_ci			usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
113862306a36Sopenharmony_ci			usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
113962306a36Sopenharmony_ci		} else {
114062306a36Sopenharmony_ci			if (usbhid->urbout)
114162306a36Sopenharmony_ci				continue;
114262306a36Sopenharmony_ci			if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
114362306a36Sopenharmony_ci				goto fail;
114462306a36Sopenharmony_ci			pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
114562306a36Sopenharmony_ci			usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
114662306a36Sopenharmony_ci					 hid_irq_out, hid, interval);
114762306a36Sopenharmony_ci			usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
114862306a36Sopenharmony_ci			usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
114962306a36Sopenharmony_ci		}
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
115362306a36Sopenharmony_ci	if (!usbhid->urbctrl) {
115462306a36Sopenharmony_ci		ret = -ENOMEM;
115562306a36Sopenharmony_ci		goto fail;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
115962306a36Sopenharmony_ci			     usbhid->ctrlbuf, 1, hid_ctrl, hid);
116062306a36Sopenharmony_ci	usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
116162306a36Sopenharmony_ci	usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	set_bit(HID_STARTED, &usbhid->iofl);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
116662306a36Sopenharmony_ci		ret = usb_autopm_get_interface(usbhid->intf);
116762306a36Sopenharmony_ci		if (ret)
116862306a36Sopenharmony_ci			goto fail;
116962306a36Sopenharmony_ci		set_bit(HID_IN_POLLING, &usbhid->iofl);
117062306a36Sopenharmony_ci		usbhid->intf->needs_remote_wakeup = 1;
117162306a36Sopenharmony_ci		ret = hid_start_in(hid);
117262306a36Sopenharmony_ci		if (ret) {
117362306a36Sopenharmony_ci			dev_err(&hid->dev,
117462306a36Sopenharmony_ci				"failed to start in urb: %d\n", ret);
117562306a36Sopenharmony_ci		}
117662306a36Sopenharmony_ci		usb_autopm_put_interface(usbhid->intf);
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	/* Some keyboards don't work until their LEDs have been set.
118062306a36Sopenharmony_ci	 * Since BIOSes do set the LEDs, it must be safe for any device
118162306a36Sopenharmony_ci	 * that supports the keyboard boot protocol.
118262306a36Sopenharmony_ci	 * In addition, enable remote wakeup by default for all keyboard
118362306a36Sopenharmony_ci	 * devices supporting the boot protocol.
118462306a36Sopenharmony_ci	 */
118562306a36Sopenharmony_ci	if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT &&
118662306a36Sopenharmony_ci			interface->desc.bInterfaceProtocol ==
118762306a36Sopenharmony_ci				USB_INTERFACE_PROTOCOL_KEYBOARD) {
118862306a36Sopenharmony_ci		usbhid_set_leds(hid);
118962306a36Sopenharmony_ci		device_set_wakeup_enable(&dev->dev, 1);
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
119362306a36Sopenharmony_ci	return 0;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cifail:
119662306a36Sopenharmony_ci	usb_free_urb(usbhid->urbin);
119762306a36Sopenharmony_ci	usb_free_urb(usbhid->urbout);
119862306a36Sopenharmony_ci	usb_free_urb(usbhid->urbctrl);
119962306a36Sopenharmony_ci	usbhid->urbin = NULL;
120062306a36Sopenharmony_ci	usbhid->urbout = NULL;
120162306a36Sopenharmony_ci	usbhid->urbctrl = NULL;
120262306a36Sopenharmony_ci	hid_free_buffers(dev, hid);
120362306a36Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
120462306a36Sopenharmony_ci	return ret;
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_cistatic void usbhid_stop(struct hid_device *hid)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	if (WARN_ON(!usbhid))
121262306a36Sopenharmony_ci		return;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
121562306a36Sopenharmony_ci		clear_bit(HID_IN_POLLING, &usbhid->iofl);
121662306a36Sopenharmony_ci		usbhid->intf->needs_remote_wakeup = 0;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	mutex_lock(&usbhid->mutex);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	clear_bit(HID_STARTED, &usbhid->iofl);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	spin_lock_irq(&usbhid->lock);	/* Sync with error and led handlers */
122462306a36Sopenharmony_ci	set_bit(HID_DISCONNECTED, &usbhid->iofl);
122562306a36Sopenharmony_ci	while (usbhid->ctrltail != usbhid->ctrlhead) {
122662306a36Sopenharmony_ci		if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_OUT) {
122762306a36Sopenharmony_ci			kfree(usbhid->ctrl[usbhid->ctrltail].raw_report);
122862306a36Sopenharmony_ci			usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
122962306a36Sopenharmony_ci		}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci		usbhid->ctrltail = (usbhid->ctrltail + 1) &
123262306a36Sopenharmony_ci			(HID_CONTROL_FIFO_SIZE - 1);
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	usb_kill_urb(usbhid->urbin);
123762306a36Sopenharmony_ci	usb_kill_urb(usbhid->urbout);
123862306a36Sopenharmony_ci	usb_kill_urb(usbhid->urbctrl);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	hid_cancel_delayed_stuff(usbhid);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	hid->claimed = 0;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	usb_free_urb(usbhid->urbin);
124562306a36Sopenharmony_ci	usb_free_urb(usbhid->urbctrl);
124662306a36Sopenharmony_ci	usb_free_urb(usbhid->urbout);
124762306a36Sopenharmony_ci	usbhid->urbin = NULL; /* don't mess up next start */
124862306a36Sopenharmony_ci	usbhid->urbctrl = NULL;
124962306a36Sopenharmony_ci	usbhid->urbout = NULL;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	hid_free_buffers(hid_to_usb_dev(hid), hid);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	mutex_unlock(&usbhid->mutex);
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic int usbhid_power(struct hid_device *hid, int lvl)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
125962306a36Sopenharmony_ci	int r = 0;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	switch (lvl) {
126262306a36Sopenharmony_ci	case PM_HINT_FULLON:
126362306a36Sopenharmony_ci		r = usb_autopm_get_interface(usbhid->intf);
126462306a36Sopenharmony_ci		break;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	case PM_HINT_NORMAL:
126762306a36Sopenharmony_ci		usb_autopm_put_interface(usbhid->intf);
126862306a36Sopenharmony_ci		break;
126962306a36Sopenharmony_ci	}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	return r;
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic void usbhid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	switch (reqtype) {
127762306a36Sopenharmony_ci	case HID_REQ_GET_REPORT:
127862306a36Sopenharmony_ci		usbhid_submit_report(hid, rep, USB_DIR_IN);
127962306a36Sopenharmony_ci		break;
128062306a36Sopenharmony_ci	case HID_REQ_SET_REPORT:
128162306a36Sopenharmony_ci		usbhid_submit_report(hid, rep, USB_DIR_OUT);
128262306a36Sopenharmony_ci		break;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cistatic int usbhid_raw_request(struct hid_device *hid, unsigned char reportnum,
128762306a36Sopenharmony_ci			      __u8 *buf, size_t len, unsigned char rtype,
128862306a36Sopenharmony_ci			      int reqtype)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	switch (reqtype) {
129162306a36Sopenharmony_ci	case HID_REQ_GET_REPORT:
129262306a36Sopenharmony_ci		return usbhid_get_raw_report(hid, reportnum, buf, len, rtype);
129362306a36Sopenharmony_ci	case HID_REQ_SET_REPORT:
129462306a36Sopenharmony_ci		return usbhid_set_raw_report(hid, reportnum, buf, len, rtype);
129562306a36Sopenharmony_ci	default:
129662306a36Sopenharmony_ci		return -EIO;
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic int usbhid_idle(struct hid_device *hid, int report, int idle,
130162306a36Sopenharmony_ci		int reqtype)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
130462306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
130562306a36Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
130662306a36Sopenharmony_ci	int ifnum = interface->desc.bInterfaceNumber;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (reqtype != HID_REQ_SET_IDLE)
130962306a36Sopenharmony_ci		return -EINVAL;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	return hid_set_idle(dev, ifnum, report, idle);
131262306a36Sopenharmony_ci}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic bool usbhid_may_wakeup(struct hid_device *hid)
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	struct usb_device *dev = hid_to_usb_dev(hid);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	return device_may_wakeup(&dev->dev);
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic const struct hid_ll_driver usb_hid_driver = {
132262306a36Sopenharmony_ci	.parse = usbhid_parse,
132362306a36Sopenharmony_ci	.start = usbhid_start,
132462306a36Sopenharmony_ci	.stop = usbhid_stop,
132562306a36Sopenharmony_ci	.open = usbhid_open,
132662306a36Sopenharmony_ci	.close = usbhid_close,
132762306a36Sopenharmony_ci	.power = usbhid_power,
132862306a36Sopenharmony_ci	.request = usbhid_request,
132962306a36Sopenharmony_ci	.wait = usbhid_wait_io,
133062306a36Sopenharmony_ci	.raw_request = usbhid_raw_request,
133162306a36Sopenharmony_ci	.output_report = usbhid_output_report,
133262306a36Sopenharmony_ci	.idle = usbhid_idle,
133362306a36Sopenharmony_ci	.may_wakeup = usbhid_may_wakeup,
133462306a36Sopenharmony_ci};
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cibool hid_is_usb(const struct hid_device *hdev)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	return hdev->ll_driver == &usb_hid_driver;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hid_is_usb);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
134562306a36Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev(intf);
134662306a36Sopenharmony_ci	struct usbhid_device *usbhid;
134762306a36Sopenharmony_ci	struct hid_device *hid;
134862306a36Sopenharmony_ci	unsigned int n, has_in = 0;
134962306a36Sopenharmony_ci	size_t len;
135062306a36Sopenharmony_ci	int ret;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	dbg_hid("HID probe called for ifnum %d\n",
135362306a36Sopenharmony_ci			intf->altsetting->desc.bInterfaceNumber);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	for (n = 0; n < interface->desc.bNumEndpoints; n++)
135662306a36Sopenharmony_ci		if (usb_endpoint_is_int_in(&interface->endpoint[n].desc))
135762306a36Sopenharmony_ci			has_in++;
135862306a36Sopenharmony_ci	if (!has_in) {
135962306a36Sopenharmony_ci		hid_err(intf, "couldn't find an input interrupt endpoint\n");
136062306a36Sopenharmony_ci		return -ENODEV;
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	hid = hid_allocate_device();
136462306a36Sopenharmony_ci	if (IS_ERR(hid))
136562306a36Sopenharmony_ci		return PTR_ERR(hid);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	usb_set_intfdata(intf, hid);
136862306a36Sopenharmony_ci	hid->ll_driver = &usb_hid_driver;
136962306a36Sopenharmony_ci	hid->ff_init = hid_pidff_init;
137062306a36Sopenharmony_ci#ifdef CONFIG_USB_HIDDEV
137162306a36Sopenharmony_ci	hid->hiddev_connect = hiddev_connect;
137262306a36Sopenharmony_ci	hid->hiddev_disconnect = hiddev_disconnect;
137362306a36Sopenharmony_ci	hid->hiddev_hid_event = hiddev_hid_event;
137462306a36Sopenharmony_ci	hid->hiddev_report_event = hiddev_report_event;
137562306a36Sopenharmony_ci#endif
137662306a36Sopenharmony_ci	hid->dev.parent = &intf->dev;
137762306a36Sopenharmony_ci	hid->bus = BUS_USB;
137862306a36Sopenharmony_ci	hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
137962306a36Sopenharmony_ci	hid->product = le16_to_cpu(dev->descriptor.idProduct);
138062306a36Sopenharmony_ci	hid->version = le16_to_cpu(dev->descriptor.bcdDevice);
138162306a36Sopenharmony_ci	hid->name[0] = 0;
138262306a36Sopenharmony_ci	if (intf->cur_altsetting->desc.bInterfaceProtocol ==
138362306a36Sopenharmony_ci			USB_INTERFACE_PROTOCOL_MOUSE)
138462306a36Sopenharmony_ci		hid->type = HID_TYPE_USBMOUSE;
138562306a36Sopenharmony_ci	else if (intf->cur_altsetting->desc.bInterfaceProtocol == 0)
138662306a36Sopenharmony_ci		hid->type = HID_TYPE_USBNONE;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	if (dev->manufacturer)
138962306a36Sopenharmony_ci		strscpy(hid->name, dev->manufacturer, sizeof(hid->name));
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	if (dev->product) {
139262306a36Sopenharmony_ci		if (dev->manufacturer)
139362306a36Sopenharmony_ci			strlcat(hid->name, " ", sizeof(hid->name));
139462306a36Sopenharmony_ci		strlcat(hid->name, dev->product, sizeof(hid->name));
139562306a36Sopenharmony_ci	}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (!strlen(hid->name))
139862306a36Sopenharmony_ci		snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
139962306a36Sopenharmony_ci			 le16_to_cpu(dev->descriptor.idVendor),
140062306a36Sopenharmony_ci			 le16_to_cpu(dev->descriptor.idProduct));
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	usb_make_path(dev, hid->phys, sizeof(hid->phys));
140362306a36Sopenharmony_ci	strlcat(hid->phys, "/input", sizeof(hid->phys));
140462306a36Sopenharmony_ci	len = strlen(hid->phys);
140562306a36Sopenharmony_ci	if (len < sizeof(hid->phys) - 1)
140662306a36Sopenharmony_ci		snprintf(hid->phys + len, sizeof(hid->phys) - len,
140762306a36Sopenharmony_ci			 "%d", intf->altsetting[0].desc.bInterfaceNumber);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
141062306a36Sopenharmony_ci		hid->uniq[0] = 0;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	usbhid = kzalloc(sizeof(*usbhid), GFP_KERNEL);
141362306a36Sopenharmony_ci	if (usbhid == NULL) {
141462306a36Sopenharmony_ci		ret = -ENOMEM;
141562306a36Sopenharmony_ci		goto err;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	hid->driver_data = usbhid;
141962306a36Sopenharmony_ci	usbhid->hid = hid;
142062306a36Sopenharmony_ci	usbhid->intf = intf;
142162306a36Sopenharmony_ci	usbhid->ifnum = interface->desc.bInterfaceNumber;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	init_waitqueue_head(&usbhid->wait);
142462306a36Sopenharmony_ci	INIT_WORK(&usbhid->reset_work, hid_reset);
142562306a36Sopenharmony_ci	timer_setup(&usbhid->io_retry, hid_retry_timeout, 0);
142662306a36Sopenharmony_ci	spin_lock_init(&usbhid->lock);
142762306a36Sopenharmony_ci	mutex_init(&usbhid->mutex);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	ret = hid_add_device(hid);
143062306a36Sopenharmony_ci	if (ret) {
143162306a36Sopenharmony_ci		if (ret != -ENODEV)
143262306a36Sopenharmony_ci			hid_err(intf, "can't add hid device: %d\n", ret);
143362306a36Sopenharmony_ci		goto err_free;
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	return 0;
143762306a36Sopenharmony_cierr_free:
143862306a36Sopenharmony_ci	kfree(usbhid);
143962306a36Sopenharmony_cierr:
144062306a36Sopenharmony_ci	hid_destroy_device(hid);
144162306a36Sopenharmony_ci	return ret;
144262306a36Sopenharmony_ci}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic void usbhid_disconnect(struct usb_interface *intf)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
144762306a36Sopenharmony_ci	struct usbhid_device *usbhid;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	if (WARN_ON(!hid))
145062306a36Sopenharmony_ci		return;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	usbhid = hid->driver_data;
145362306a36Sopenharmony_ci	spin_lock_irq(&usbhid->lock);	/* Sync with error and led handlers */
145462306a36Sopenharmony_ci	set_bit(HID_DISCONNECTED, &usbhid->iofl);
145562306a36Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
145662306a36Sopenharmony_ci	hid_destroy_device(hid);
145762306a36Sopenharmony_ci	kfree(usbhid);
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cistatic void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	del_timer_sync(&usbhid->io_retry);
146362306a36Sopenharmony_ci	cancel_work_sync(&usbhid->reset_work);
146462306a36Sopenharmony_ci}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_cistatic void hid_cease_io(struct usbhid_device *usbhid)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	del_timer_sync(&usbhid->io_retry);
146962306a36Sopenharmony_ci	usb_kill_urb(usbhid->urbin);
147062306a36Sopenharmony_ci	usb_kill_urb(usbhid->urbctrl);
147162306a36Sopenharmony_ci	usb_kill_urb(usbhid->urbout);
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic void hid_restart_io(struct hid_device *hid)
147562306a36Sopenharmony_ci{
147662306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
147762306a36Sopenharmony_ci	int clear_halt = test_bit(HID_CLEAR_HALT, &usbhid->iofl);
147862306a36Sopenharmony_ci	int reset_pending = test_bit(HID_RESET_PENDING, &usbhid->iofl);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
148162306a36Sopenharmony_ci	clear_bit(HID_SUSPENDED, &usbhid->iofl);
148262306a36Sopenharmony_ci	usbhid_mark_busy(usbhid);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	if (clear_halt || reset_pending)
148562306a36Sopenharmony_ci		schedule_work(&usbhid->reset_work);
148662306a36Sopenharmony_ci	usbhid->retry_delay = 0;
148762306a36Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	if (reset_pending || !test_bit(HID_STARTED, &usbhid->iofl))
149062306a36Sopenharmony_ci		return;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	if (!clear_halt) {
149362306a36Sopenharmony_ci		if (hid_start_in(hid) < 0)
149462306a36Sopenharmony_ci			hid_io_error(hid);
149562306a36Sopenharmony_ci	}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
149862306a36Sopenharmony_ci	if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
149962306a36Sopenharmony_ci		usbhid_restart_out_queue(usbhid);
150062306a36Sopenharmony_ci	if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
150162306a36Sopenharmony_ci		usbhid_restart_ctrl_queue(usbhid);
150262306a36Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci/* Treat USB reset pretty much the same as suspend/resume */
150662306a36Sopenharmony_cistatic int hid_pre_reset(struct usb_interface *intf)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
150962306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
151262306a36Sopenharmony_ci	set_bit(HID_RESET_PENDING, &usbhid->iofl);
151362306a36Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
151462306a36Sopenharmony_ci	hid_cease_io(usbhid);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	return 0;
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci/* Same routine used for post_reset and reset_resume */
152062306a36Sopenharmony_cistatic int hid_post_reset(struct usb_interface *intf)
152162306a36Sopenharmony_ci{
152262306a36Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev (intf);
152362306a36Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
152462306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
152562306a36Sopenharmony_ci	struct usb_host_interface *interface = intf->cur_altsetting;
152662306a36Sopenharmony_ci	int status;
152762306a36Sopenharmony_ci	char *rdesc;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	/* Fetch and examine the HID report descriptor. If this
153062306a36Sopenharmony_ci	 * has changed, then rebind. Since usbcore's check of the
153162306a36Sopenharmony_ci	 * configuration descriptors passed, we already know that
153262306a36Sopenharmony_ci	 * the size of the HID report descriptor has not changed.
153362306a36Sopenharmony_ci	 */
153462306a36Sopenharmony_ci	rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
153562306a36Sopenharmony_ci	if (!rdesc)
153662306a36Sopenharmony_ci		return -ENOMEM;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	status = hid_get_class_descriptor(dev,
153962306a36Sopenharmony_ci				interface->desc.bInterfaceNumber,
154062306a36Sopenharmony_ci				HID_DT_REPORT, rdesc, hid->dev_rsize);
154162306a36Sopenharmony_ci	if (status < 0) {
154262306a36Sopenharmony_ci		dbg_hid("reading report descriptor failed (post_reset)\n");
154362306a36Sopenharmony_ci		kfree(rdesc);
154462306a36Sopenharmony_ci		return status;
154562306a36Sopenharmony_ci	}
154662306a36Sopenharmony_ci	status = memcmp(rdesc, hid->dev_rdesc, hid->dev_rsize);
154762306a36Sopenharmony_ci	kfree(rdesc);
154862306a36Sopenharmony_ci	if (status != 0) {
154962306a36Sopenharmony_ci		dbg_hid("report descriptor changed\n");
155062306a36Sopenharmony_ci		return -EPERM;
155162306a36Sopenharmony_ci	}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	/* No need to do another reset or clear a halted endpoint */
155462306a36Sopenharmony_ci	spin_lock_irq(&usbhid->lock);
155562306a36Sopenharmony_ci	clear_bit(HID_RESET_PENDING, &usbhid->iofl);
155662306a36Sopenharmony_ci	clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
155762306a36Sopenharmony_ci	spin_unlock_irq(&usbhid->lock);
155862306a36Sopenharmony_ci	hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	hid_restart_io(hid);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	return 0;
156362306a36Sopenharmony_ci}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci#ifdef CONFIG_PM
156662306a36Sopenharmony_cistatic int hid_resume_common(struct hid_device *hid, bool driver_suspended)
156762306a36Sopenharmony_ci{
156862306a36Sopenharmony_ci	int status = 0;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	hid_restart_io(hid);
157162306a36Sopenharmony_ci	if (driver_suspended)
157262306a36Sopenharmony_ci		status = hid_driver_resume(hid);
157362306a36Sopenharmony_ci	return status;
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic int hid_suspend(struct usb_interface *intf, pm_message_t message)
157762306a36Sopenharmony_ci{
157862306a36Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
157962306a36Sopenharmony_ci	struct usbhid_device *usbhid = hid->driver_data;
158062306a36Sopenharmony_ci	int status = 0;
158162306a36Sopenharmony_ci	bool driver_suspended = false;
158262306a36Sopenharmony_ci	unsigned int ledcount;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	if (PMSG_IS_AUTO(message)) {
158562306a36Sopenharmony_ci		ledcount = hidinput_count_leds(hid);
158662306a36Sopenharmony_ci		spin_lock_irq(&usbhid->lock);	/* Sync with error handler */
158762306a36Sopenharmony_ci		if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
158862306a36Sopenharmony_ci		    && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
158962306a36Sopenharmony_ci		    && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
159062306a36Sopenharmony_ci		    && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
159162306a36Sopenharmony_ci		    && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
159262306a36Sopenharmony_ci		    && (!ledcount || ignoreled))
159362306a36Sopenharmony_ci		{
159462306a36Sopenharmony_ci			set_bit(HID_SUSPENDED, &usbhid->iofl);
159562306a36Sopenharmony_ci			spin_unlock_irq(&usbhid->lock);
159662306a36Sopenharmony_ci			status = hid_driver_suspend(hid, message);
159762306a36Sopenharmony_ci			if (status < 0)
159862306a36Sopenharmony_ci				goto failed;
159962306a36Sopenharmony_ci			driver_suspended = true;
160062306a36Sopenharmony_ci		} else {
160162306a36Sopenharmony_ci			usbhid_mark_busy(usbhid);
160262306a36Sopenharmony_ci			spin_unlock_irq(&usbhid->lock);
160362306a36Sopenharmony_ci			return -EBUSY;
160462306a36Sopenharmony_ci		}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	} else {
160762306a36Sopenharmony_ci		/* TODO: resume() might need to handle suspend failure */
160862306a36Sopenharmony_ci		status = hid_driver_suspend(hid, message);
160962306a36Sopenharmony_ci		driver_suspended = true;
161062306a36Sopenharmony_ci		spin_lock_irq(&usbhid->lock);
161162306a36Sopenharmony_ci		set_bit(HID_SUSPENDED, &usbhid->iofl);
161262306a36Sopenharmony_ci		spin_unlock_irq(&usbhid->lock);
161362306a36Sopenharmony_ci		if (usbhid_wait_io(hid) < 0)
161462306a36Sopenharmony_ci			status = -EIO;
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	hid_cancel_delayed_stuff(usbhid);
161862306a36Sopenharmony_ci	hid_cease_io(usbhid);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
162162306a36Sopenharmony_ci		/* lost race against keypresses */
162262306a36Sopenharmony_ci		status = -EBUSY;
162362306a36Sopenharmony_ci		goto failed;
162462306a36Sopenharmony_ci	}
162562306a36Sopenharmony_ci	dev_dbg(&intf->dev, "suspend\n");
162662306a36Sopenharmony_ci	return status;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci failed:
162962306a36Sopenharmony_ci	hid_resume_common(hid, driver_suspended);
163062306a36Sopenharmony_ci	return status;
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_cistatic int hid_resume(struct usb_interface *intf)
163462306a36Sopenharmony_ci{
163562306a36Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata (intf);
163662306a36Sopenharmony_ci	int status;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	status = hid_resume_common(hid, true);
163962306a36Sopenharmony_ci	dev_dbg(&intf->dev, "resume status %d\n", status);
164062306a36Sopenharmony_ci	return 0;
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_cistatic int hid_reset_resume(struct usb_interface *intf)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	struct hid_device *hid = usb_get_intfdata(intf);
164662306a36Sopenharmony_ci	int status;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	status = hid_post_reset(intf);
164962306a36Sopenharmony_ci	if (status >= 0) {
165062306a36Sopenharmony_ci		int ret = hid_driver_reset_resume(hid);
165162306a36Sopenharmony_ci		if (ret < 0)
165262306a36Sopenharmony_ci			status = ret;
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci	return status;
165562306a36Sopenharmony_ci}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci#endif /* CONFIG_PM */
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_cistatic const struct usb_device_id hid_usb_ids[] = {
166062306a36Sopenharmony_ci	{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
166162306a36Sopenharmony_ci		.bInterfaceClass = USB_INTERFACE_CLASS_HID },
166262306a36Sopenharmony_ci	{ }						/* Terminating entry */
166362306a36Sopenharmony_ci};
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ciMODULE_DEVICE_TABLE (usb, hid_usb_ids);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_cistatic struct usb_driver hid_driver = {
166862306a36Sopenharmony_ci	.name =		"usbhid",
166962306a36Sopenharmony_ci	.probe =	usbhid_probe,
167062306a36Sopenharmony_ci	.disconnect =	usbhid_disconnect,
167162306a36Sopenharmony_ci#ifdef CONFIG_PM
167262306a36Sopenharmony_ci	.suspend =	hid_suspend,
167362306a36Sopenharmony_ci	.resume =	hid_resume,
167462306a36Sopenharmony_ci	.reset_resume =	hid_reset_resume,
167562306a36Sopenharmony_ci#endif
167662306a36Sopenharmony_ci	.pre_reset =	hid_pre_reset,
167762306a36Sopenharmony_ci	.post_reset =	hid_post_reset,
167862306a36Sopenharmony_ci	.id_table =	hid_usb_ids,
167962306a36Sopenharmony_ci	.supports_autosuspend = 1,
168062306a36Sopenharmony_ci};
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_cistruct usb_interface *usbhid_find_interface(int minor)
168362306a36Sopenharmony_ci{
168462306a36Sopenharmony_ci	return usb_find_interface(&hid_driver, minor);
168562306a36Sopenharmony_ci}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_cistatic int __init hid_init(void)
168862306a36Sopenharmony_ci{
168962306a36Sopenharmony_ci	int retval;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	retval = hid_quirks_init(quirks_param, BUS_USB, MAX_USBHID_BOOT_QUIRKS);
169262306a36Sopenharmony_ci	if (retval)
169362306a36Sopenharmony_ci		goto usbhid_quirks_init_fail;
169462306a36Sopenharmony_ci	retval = usb_register(&hid_driver);
169562306a36Sopenharmony_ci	if (retval)
169662306a36Sopenharmony_ci		goto usb_register_fail;
169762306a36Sopenharmony_ci	pr_info(KBUILD_MODNAME ": " DRIVER_DESC "\n");
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	return 0;
170062306a36Sopenharmony_ciusb_register_fail:
170162306a36Sopenharmony_ci	hid_quirks_exit(BUS_USB);
170262306a36Sopenharmony_ciusbhid_quirks_init_fail:
170362306a36Sopenharmony_ci	return retval;
170462306a36Sopenharmony_ci}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_cistatic void __exit hid_exit(void)
170762306a36Sopenharmony_ci{
170862306a36Sopenharmony_ci	usb_deregister(&hid_driver);
170962306a36Sopenharmony_ci	hid_quirks_exit(BUS_USB);
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_cimodule_init(hid_init);
171362306a36Sopenharmony_cimodule_exit(hid_exit);
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ciMODULE_AUTHOR("Andreas Gal");
171662306a36Sopenharmony_ciMODULE_AUTHOR("Vojtech Pavlik");
171762306a36Sopenharmony_ciMODULE_AUTHOR("Jiri Kosina");
171862306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
171962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1720