18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ati_remote2 - ATI/Philips USB RF remote driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi>
68c2ecf20Sopenharmony_ci * Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/usb/input.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define DRIVER_DESC    "ATI/Philips USB RF remote driver"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * ATI Remote Wonder II Channel Configuration
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * The remote control can be assigned one of sixteen "channels" in order to facilitate
238c2ecf20Sopenharmony_ci * the use of multiple remote controls within range of each other.
248c2ecf20Sopenharmony_ci * A remote's "channel" may be altered by pressing and holding the "PC" button for
258c2ecf20Sopenharmony_ci * approximately 3 seconds, after which the button will slowly flash the count of the
268c2ecf20Sopenharmony_ci * currently configured "channel", using the numeric keypad enter a number between 1 and
278c2ecf20Sopenharmony_ci * 16 and then press the "PC" button again, the button will slowly flash the count of the
288c2ecf20Sopenharmony_ci * newly configured "channel".
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cienum {
328c2ecf20Sopenharmony_ci	ATI_REMOTE2_MAX_CHANNEL_MASK = 0xFFFF,
338c2ecf20Sopenharmony_ci	ATI_REMOTE2_MAX_MODE_MASK = 0x1F,
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int ati_remote2_set_mask(const char *val,
378c2ecf20Sopenharmony_ci				const struct kernel_param *kp,
388c2ecf20Sopenharmony_ci				unsigned int max)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	unsigned int mask;
418c2ecf20Sopenharmony_ci	int ret;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (!val)
448c2ecf20Sopenharmony_ci		return -EINVAL;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	ret = kstrtouint(val, 0, &mask);
478c2ecf20Sopenharmony_ci	if (ret)
488c2ecf20Sopenharmony_ci		return ret;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (mask & ~max)
518c2ecf20Sopenharmony_ci		return -EINVAL;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	*(unsigned int *)kp->arg = mask;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int ati_remote2_set_channel_mask(const char *val,
598c2ecf20Sopenharmony_ci					const struct kernel_param *kp)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	pr_debug("%s()\n", __func__);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_CHANNEL_MASK);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic int ati_remote2_get_channel_mask(char *buffer,
678c2ecf20Sopenharmony_ci					const struct kernel_param *kp)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	pr_debug("%s()\n", __func__);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return sprintf(buffer, "0x%04x\n", *(unsigned int *)kp->arg);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic int ati_remote2_set_mode_mask(const char *val,
758c2ecf20Sopenharmony_ci				     const struct kernel_param *kp)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	pr_debug("%s()\n", __func__);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_MODE_MASK);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int ati_remote2_get_mode_mask(char *buffer,
838c2ecf20Sopenharmony_ci				     const struct kernel_param *kp)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	pr_debug("%s()\n", __func__);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return sprintf(buffer, "0x%02x\n", *(unsigned int *)kp->arg);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
918c2ecf20Sopenharmony_ci#define param_check_channel_mask(name, p) __param_check(name, p, unsigned int)
928c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_channel_mask = {
938c2ecf20Sopenharmony_ci	.set = ati_remote2_set_channel_mask,
948c2ecf20Sopenharmony_ci	.get = ati_remote2_get_channel_mask,
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_cimodule_param(channel_mask, channel_mask, 0644);
978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK;
1008c2ecf20Sopenharmony_ci#define param_check_mode_mask(name, p) __param_check(name, p, unsigned int)
1018c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_mode_mask = {
1028c2ecf20Sopenharmony_ci	.set = ati_remote2_set_mode_mask,
1038c2ecf20Sopenharmony_ci	.get = ati_remote2_get_mode_mask,
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_cimodule_param(mode_mask, mode_mask, 0644);
1068c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic const struct usb_device_id ati_remote2_id_table[] = {
1098c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x0471, 0x0602) },	/* ATI Remote Wonder II */
1108c2ecf20Sopenharmony_ci	{ }
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ati_remote2_mutex);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cienum {
1178c2ecf20Sopenharmony_ci	ATI_REMOTE2_OPENED = 0x1,
1188c2ecf20Sopenharmony_ci	ATI_REMOTE2_SUSPENDED = 0x2,
1198c2ecf20Sopenharmony_ci};
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cienum {
1228c2ecf20Sopenharmony_ci	ATI_REMOTE2_AUX1,
1238c2ecf20Sopenharmony_ci	ATI_REMOTE2_AUX2,
1248c2ecf20Sopenharmony_ci	ATI_REMOTE2_AUX3,
1258c2ecf20Sopenharmony_ci	ATI_REMOTE2_AUX4,
1268c2ecf20Sopenharmony_ci	ATI_REMOTE2_PC,
1278c2ecf20Sopenharmony_ci	ATI_REMOTE2_MODES,
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic const struct {
1318c2ecf20Sopenharmony_ci	u8  hw_code;
1328c2ecf20Sopenharmony_ci	u16 keycode;
1338c2ecf20Sopenharmony_ci} ati_remote2_key_table[] = {
1348c2ecf20Sopenharmony_ci	{ 0x00, KEY_0 },
1358c2ecf20Sopenharmony_ci	{ 0x01, KEY_1 },
1368c2ecf20Sopenharmony_ci	{ 0x02, KEY_2 },
1378c2ecf20Sopenharmony_ci	{ 0x03, KEY_3 },
1388c2ecf20Sopenharmony_ci	{ 0x04, KEY_4 },
1398c2ecf20Sopenharmony_ci	{ 0x05, KEY_5 },
1408c2ecf20Sopenharmony_ci	{ 0x06, KEY_6 },
1418c2ecf20Sopenharmony_ci	{ 0x07, KEY_7 },
1428c2ecf20Sopenharmony_ci	{ 0x08, KEY_8 },
1438c2ecf20Sopenharmony_ci	{ 0x09, KEY_9 },
1448c2ecf20Sopenharmony_ci	{ 0x0c, KEY_POWER },
1458c2ecf20Sopenharmony_ci	{ 0x0d, KEY_MUTE },
1468c2ecf20Sopenharmony_ci	{ 0x10, KEY_VOLUMEUP },
1478c2ecf20Sopenharmony_ci	{ 0x11, KEY_VOLUMEDOWN },
1488c2ecf20Sopenharmony_ci	{ 0x20, KEY_CHANNELUP },
1498c2ecf20Sopenharmony_ci	{ 0x21, KEY_CHANNELDOWN },
1508c2ecf20Sopenharmony_ci	{ 0x28, KEY_FORWARD },
1518c2ecf20Sopenharmony_ci	{ 0x29, KEY_REWIND },
1528c2ecf20Sopenharmony_ci	{ 0x2c, KEY_PLAY },
1538c2ecf20Sopenharmony_ci	{ 0x30, KEY_PAUSE },
1548c2ecf20Sopenharmony_ci	{ 0x31, KEY_STOP },
1558c2ecf20Sopenharmony_ci	{ 0x37, KEY_RECORD },
1568c2ecf20Sopenharmony_ci	{ 0x38, KEY_DVD },
1578c2ecf20Sopenharmony_ci	{ 0x39, KEY_TV },
1588c2ecf20Sopenharmony_ci	{ 0x3f, KEY_PROG1 }, /* AUX1-AUX4 and PC */
1598c2ecf20Sopenharmony_ci	{ 0x54, KEY_MENU },
1608c2ecf20Sopenharmony_ci	{ 0x58, KEY_UP },
1618c2ecf20Sopenharmony_ci	{ 0x59, KEY_DOWN },
1628c2ecf20Sopenharmony_ci	{ 0x5a, KEY_LEFT },
1638c2ecf20Sopenharmony_ci	{ 0x5b, KEY_RIGHT },
1648c2ecf20Sopenharmony_ci	{ 0x5c, KEY_OK },
1658c2ecf20Sopenharmony_ci	{ 0x78, KEY_A },
1668c2ecf20Sopenharmony_ci	{ 0x79, KEY_B },
1678c2ecf20Sopenharmony_ci	{ 0x7a, KEY_C },
1688c2ecf20Sopenharmony_ci	{ 0x7b, KEY_D },
1698c2ecf20Sopenharmony_ci	{ 0x7c, KEY_E },
1708c2ecf20Sopenharmony_ci	{ 0x7d, KEY_F },
1718c2ecf20Sopenharmony_ci	{ 0x82, KEY_ENTER },
1728c2ecf20Sopenharmony_ci	{ 0x8e, KEY_VENDOR },
1738c2ecf20Sopenharmony_ci	{ 0x96, KEY_COFFEE },
1748c2ecf20Sopenharmony_ci	{ 0xa9, BTN_LEFT },
1758c2ecf20Sopenharmony_ci	{ 0xaa, BTN_RIGHT },
1768c2ecf20Sopenharmony_ci	{ 0xbe, KEY_QUESTION },
1778c2ecf20Sopenharmony_ci	{ 0xd0, KEY_EDIT },
1788c2ecf20Sopenharmony_ci	{ 0xd5, KEY_FRONT },
1798c2ecf20Sopenharmony_ci	{ 0xf9, KEY_INFO },
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistruct ati_remote2 {
1838c2ecf20Sopenharmony_ci	struct input_dev *idev;
1848c2ecf20Sopenharmony_ci	struct usb_device *udev;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	struct usb_interface *intf[2];
1878c2ecf20Sopenharmony_ci	struct usb_endpoint_descriptor *ep[2];
1888c2ecf20Sopenharmony_ci	struct urb *urb[2];
1898c2ecf20Sopenharmony_ci	void *buf[2];
1908c2ecf20Sopenharmony_ci	dma_addr_t buf_dma[2];
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	unsigned long jiffies;
1938c2ecf20Sopenharmony_ci	int mode;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	char name[64];
1968c2ecf20Sopenharmony_ci	char phys[64];
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/* Each mode (AUX1-AUX4 and PC) can have an independent keymap. */
1998c2ecf20Sopenharmony_ci	u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)];
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	unsigned int flags;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	unsigned int channel_mask;
2048c2ecf20Sopenharmony_ci	unsigned int mode_mask;
2058c2ecf20Sopenharmony_ci};
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
2088c2ecf20Sopenharmony_cistatic void ati_remote2_disconnect(struct usb_interface *interface);
2098c2ecf20Sopenharmony_cistatic int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message);
2108c2ecf20Sopenharmony_cistatic int ati_remote2_resume(struct usb_interface *interface);
2118c2ecf20Sopenharmony_cistatic int ati_remote2_reset_resume(struct usb_interface *interface);
2128c2ecf20Sopenharmony_cistatic int ati_remote2_pre_reset(struct usb_interface *interface);
2138c2ecf20Sopenharmony_cistatic int ati_remote2_post_reset(struct usb_interface *interface);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic struct usb_driver ati_remote2_driver = {
2168c2ecf20Sopenharmony_ci	.name       = "ati_remote2",
2178c2ecf20Sopenharmony_ci	.probe      = ati_remote2_probe,
2188c2ecf20Sopenharmony_ci	.disconnect = ati_remote2_disconnect,
2198c2ecf20Sopenharmony_ci	.id_table   = ati_remote2_id_table,
2208c2ecf20Sopenharmony_ci	.suspend    = ati_remote2_suspend,
2218c2ecf20Sopenharmony_ci	.resume     = ati_remote2_resume,
2228c2ecf20Sopenharmony_ci	.reset_resume = ati_remote2_reset_resume,
2238c2ecf20Sopenharmony_ci	.pre_reset  = ati_remote2_pre_reset,
2248c2ecf20Sopenharmony_ci	.post_reset = ati_remote2_post_reset,
2258c2ecf20Sopenharmony_ci	.supports_autosuspend = 1,
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int ati_remote2_submit_urbs(struct ati_remote2 *ar2)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	int r;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
2338c2ecf20Sopenharmony_ci	if (r) {
2348c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
2358c2ecf20Sopenharmony_ci			"%s(): usb_submit_urb() = %d\n", __func__, r);
2368c2ecf20Sopenharmony_ci		return r;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
2398c2ecf20Sopenharmony_ci	if (r) {
2408c2ecf20Sopenharmony_ci		usb_kill_urb(ar2->urb[0]);
2418c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
2428c2ecf20Sopenharmony_ci			"%s(): usb_submit_urb() = %d\n", __func__, r);
2438c2ecf20Sopenharmony_ci		return r;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return 0;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic void ati_remote2_kill_urbs(struct ati_remote2 *ar2)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	usb_kill_urb(ar2->urb[1]);
2528c2ecf20Sopenharmony_ci	usb_kill_urb(ar2->urb[0]);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int ati_remote2_open(struct input_dev *idev)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = input_get_drvdata(idev);
2588c2ecf20Sopenharmony_ci	int r;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	r = usb_autopm_get_interface(ar2->intf[0]);
2638c2ecf20Sopenharmony_ci	if (r) {
2648c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
2658c2ecf20Sopenharmony_ci			"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
2668c2ecf20Sopenharmony_ci		goto fail1;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) {
2728c2ecf20Sopenharmony_ci		r = ati_remote2_submit_urbs(ar2);
2738c2ecf20Sopenharmony_ci		if (r)
2748c2ecf20Sopenharmony_ci			goto fail2;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	ar2->flags |= ATI_REMOTE2_OPENED;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	usb_autopm_put_interface(ar2->intf[0]);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return 0;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci fail2:
2868c2ecf20Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
2878c2ecf20Sopenharmony_ci	usb_autopm_put_interface(ar2->intf[0]);
2888c2ecf20Sopenharmony_ci fail1:
2898c2ecf20Sopenharmony_ci	return r;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic void ati_remote2_close(struct input_dev *idev)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = input_get_drvdata(idev);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (!(ar2->flags & ATI_REMOTE2_SUSPENDED))
3018c2ecf20Sopenharmony_ci		ati_remote2_kill_urbs(ar2);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	ar2->flags &= ~ATI_REMOTE2_OPENED;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic void ati_remote2_input_mouse(struct ati_remote2 *ar2)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct input_dev *idev = ar2->idev;
3118c2ecf20Sopenharmony_ci	u8 *data = ar2->buf[0];
3128c2ecf20Sopenharmony_ci	int channel, mode;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	channel = data[0] >> 4;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (!((1 << channel) & ar2->channel_mask))
3178c2ecf20Sopenharmony_ci		return;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	mode = data[0] & 0x0F;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (mode > ATI_REMOTE2_PC) {
3228c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
3238c2ecf20Sopenharmony_ci			"Unknown mode byte (%02x %02x %02x %02x)\n",
3248c2ecf20Sopenharmony_ci			data[3], data[2], data[1], data[0]);
3258c2ecf20Sopenharmony_ci		return;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (!((1 << mode) & ar2->mode_mask))
3298c2ecf20Sopenharmony_ci		return;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	input_event(idev, EV_REL, REL_X, (s8) data[1]);
3328c2ecf20Sopenharmony_ci	input_event(idev, EV_REL, REL_Y, (s8) data[2]);
3338c2ecf20Sopenharmony_ci	input_sync(idev);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic int ati_remote2_lookup(unsigned int hw_code)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	int i;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ati_remote2_key_table); i++)
3418c2ecf20Sopenharmony_ci		if (ati_remote2_key_table[i].hw_code == hw_code)
3428c2ecf20Sopenharmony_ci			return i;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	return -1;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic void ati_remote2_input_key(struct ati_remote2 *ar2)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	struct input_dev *idev = ar2->idev;
3508c2ecf20Sopenharmony_ci	u8 *data = ar2->buf[1];
3518c2ecf20Sopenharmony_ci	int channel, mode, hw_code, index;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	channel = data[0] >> 4;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (!((1 << channel) & ar2->channel_mask))
3568c2ecf20Sopenharmony_ci		return;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	mode = data[0] & 0x0F;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (mode > ATI_REMOTE2_PC) {
3618c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
3628c2ecf20Sopenharmony_ci			"Unknown mode byte (%02x %02x %02x %02x)\n",
3638c2ecf20Sopenharmony_ci			data[3], data[2], data[1], data[0]);
3648c2ecf20Sopenharmony_ci		return;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	hw_code = data[2];
3688c2ecf20Sopenharmony_ci	if (hw_code == 0x3f) {
3698c2ecf20Sopenharmony_ci		/*
3708c2ecf20Sopenharmony_ci		 * For some incomprehensible reason the mouse pad generates
3718c2ecf20Sopenharmony_ci		 * events which look identical to the events from the last
3728c2ecf20Sopenharmony_ci		 * pressed mode key. Naturally we don't want to generate key
3738c2ecf20Sopenharmony_ci		 * events for the mouse pad so we filter out any subsequent
3748c2ecf20Sopenharmony_ci		 * events from the same mode key.
3758c2ecf20Sopenharmony_ci		 */
3768c2ecf20Sopenharmony_ci		if (ar2->mode == mode)
3778c2ecf20Sopenharmony_ci			return;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci		if (data[1] == 0)
3808c2ecf20Sopenharmony_ci			ar2->mode = mode;
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (!((1 << mode) & ar2->mode_mask))
3848c2ecf20Sopenharmony_ci		return;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	index = ati_remote2_lookup(hw_code);
3878c2ecf20Sopenharmony_ci	if (index < 0) {
3888c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
3898c2ecf20Sopenharmony_ci			"Unknown code byte (%02x %02x %02x %02x)\n",
3908c2ecf20Sopenharmony_ci			data[3], data[2], data[1], data[0]);
3918c2ecf20Sopenharmony_ci		return;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	switch (data[1]) {
3958c2ecf20Sopenharmony_ci	case 0:	/* release */
3968c2ecf20Sopenharmony_ci		break;
3978c2ecf20Sopenharmony_ci	case 1:	/* press */
3988c2ecf20Sopenharmony_ci		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]);
3998c2ecf20Sopenharmony_ci		break;
4008c2ecf20Sopenharmony_ci	case 2:	/* repeat */
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		/* No repeat for mouse buttons. */
4038c2ecf20Sopenharmony_ci		if (ar2->keycode[mode][index] == BTN_LEFT ||
4048c2ecf20Sopenharmony_ci		    ar2->keycode[mode][index] == BTN_RIGHT)
4058c2ecf20Sopenharmony_ci			return;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		if (!time_after_eq(jiffies, ar2->jiffies))
4088c2ecf20Sopenharmony_ci			return;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]);
4118c2ecf20Sopenharmony_ci		break;
4128c2ecf20Sopenharmony_ci	default:
4138c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
4148c2ecf20Sopenharmony_ci			"Unknown state byte (%02x %02x %02x %02x)\n",
4158c2ecf20Sopenharmony_ci			data[3], data[2], data[1], data[0]);
4168c2ecf20Sopenharmony_ci		return;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	input_event(idev, EV_KEY, ar2->keycode[mode][index], data[1]);
4208c2ecf20Sopenharmony_ci	input_sync(idev);
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic void ati_remote2_complete_mouse(struct urb *urb)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = urb->context;
4268c2ecf20Sopenharmony_ci	int r;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	switch (urb->status) {
4298c2ecf20Sopenharmony_ci	case 0:
4308c2ecf20Sopenharmony_ci		usb_mark_last_busy(ar2->udev);
4318c2ecf20Sopenharmony_ci		ati_remote2_input_mouse(ar2);
4328c2ecf20Sopenharmony_ci		break;
4338c2ecf20Sopenharmony_ci	case -ENOENT:
4348c2ecf20Sopenharmony_ci	case -EILSEQ:
4358c2ecf20Sopenharmony_ci	case -ECONNRESET:
4368c2ecf20Sopenharmony_ci	case -ESHUTDOWN:
4378c2ecf20Sopenharmony_ci		dev_dbg(&ar2->intf[0]->dev,
4388c2ecf20Sopenharmony_ci			"%s(): urb status = %d\n", __func__, urb->status);
4398c2ecf20Sopenharmony_ci		return;
4408c2ecf20Sopenharmony_ci	default:
4418c2ecf20Sopenharmony_ci		usb_mark_last_busy(ar2->udev);
4428c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
4438c2ecf20Sopenharmony_ci			"%s(): urb status = %d\n", __func__, urb->status);
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	r = usb_submit_urb(urb, GFP_ATOMIC);
4478c2ecf20Sopenharmony_ci	if (r)
4488c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
4498c2ecf20Sopenharmony_ci			"%s(): usb_submit_urb() = %d\n", __func__, r);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic void ati_remote2_complete_key(struct urb *urb)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = urb->context;
4558c2ecf20Sopenharmony_ci	int r;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	switch (urb->status) {
4588c2ecf20Sopenharmony_ci	case 0:
4598c2ecf20Sopenharmony_ci		usb_mark_last_busy(ar2->udev);
4608c2ecf20Sopenharmony_ci		ati_remote2_input_key(ar2);
4618c2ecf20Sopenharmony_ci		break;
4628c2ecf20Sopenharmony_ci	case -ENOENT:
4638c2ecf20Sopenharmony_ci	case -EILSEQ:
4648c2ecf20Sopenharmony_ci	case -ECONNRESET:
4658c2ecf20Sopenharmony_ci	case -ESHUTDOWN:
4668c2ecf20Sopenharmony_ci		dev_dbg(&ar2->intf[1]->dev,
4678c2ecf20Sopenharmony_ci			"%s(): urb status = %d\n", __func__, urb->status);
4688c2ecf20Sopenharmony_ci		return;
4698c2ecf20Sopenharmony_ci	default:
4708c2ecf20Sopenharmony_ci		usb_mark_last_busy(ar2->udev);
4718c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
4728c2ecf20Sopenharmony_ci			"%s(): urb status = %d\n", __func__, urb->status);
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	r = usb_submit_urb(urb, GFP_ATOMIC);
4768c2ecf20Sopenharmony_ci	if (r)
4778c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
4788c2ecf20Sopenharmony_ci			"%s(): usb_submit_urb() = %d\n", __func__, r);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic int ati_remote2_getkeycode(struct input_dev *idev,
4828c2ecf20Sopenharmony_ci				  struct input_keymap_entry *ke)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = input_get_drvdata(idev);
4858c2ecf20Sopenharmony_ci	unsigned int mode;
4868c2ecf20Sopenharmony_ci	int offset;
4878c2ecf20Sopenharmony_ci	unsigned int index;
4888c2ecf20Sopenharmony_ci	unsigned int scancode;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
4918c2ecf20Sopenharmony_ci		index = ke->index;
4928c2ecf20Sopenharmony_ci		if (index >= ATI_REMOTE2_MODES *
4938c2ecf20Sopenharmony_ci				ARRAY_SIZE(ati_remote2_key_table))
4948c2ecf20Sopenharmony_ci			return -EINVAL;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
4978c2ecf20Sopenharmony_ci		offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
4988c2ecf20Sopenharmony_ci		scancode = (mode << 8) + ati_remote2_key_table[offset].hw_code;
4998c2ecf20Sopenharmony_ci	} else {
5008c2ecf20Sopenharmony_ci		if (input_scancode_to_scalar(ke, &scancode))
5018c2ecf20Sopenharmony_ci			return -EINVAL;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		mode = scancode >> 8;
5048c2ecf20Sopenharmony_ci		if (mode > ATI_REMOTE2_PC)
5058c2ecf20Sopenharmony_ci			return -EINVAL;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		offset = ati_remote2_lookup(scancode & 0xff);
5088c2ecf20Sopenharmony_ci		if (offset < 0)
5098c2ecf20Sopenharmony_ci			return -EINVAL;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		index = mode * ARRAY_SIZE(ati_remote2_key_table) + offset;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	ke->keycode = ar2->keycode[mode][offset];
5158c2ecf20Sopenharmony_ci	ke->len = sizeof(scancode);
5168c2ecf20Sopenharmony_ci	memcpy(&ke->scancode, &scancode, sizeof(scancode));
5178c2ecf20Sopenharmony_ci	ke->index = index;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return 0;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic int ati_remote2_setkeycode(struct input_dev *idev,
5238c2ecf20Sopenharmony_ci				  const struct input_keymap_entry *ke,
5248c2ecf20Sopenharmony_ci				  unsigned int *old_keycode)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = input_get_drvdata(idev);
5278c2ecf20Sopenharmony_ci	unsigned int mode;
5288c2ecf20Sopenharmony_ci	int offset;
5298c2ecf20Sopenharmony_ci	unsigned int index;
5308c2ecf20Sopenharmony_ci	unsigned int scancode;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
5338c2ecf20Sopenharmony_ci		if (ke->index >= ATI_REMOTE2_MODES *
5348c2ecf20Sopenharmony_ci				ARRAY_SIZE(ati_remote2_key_table))
5358c2ecf20Sopenharmony_ci			return -EINVAL;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci		mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
5388c2ecf20Sopenharmony_ci		offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
5398c2ecf20Sopenharmony_ci	} else {
5408c2ecf20Sopenharmony_ci		if (input_scancode_to_scalar(ke, &scancode))
5418c2ecf20Sopenharmony_ci			return -EINVAL;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		mode = scancode >> 8;
5448c2ecf20Sopenharmony_ci		if (mode > ATI_REMOTE2_PC)
5458c2ecf20Sopenharmony_ci			return -EINVAL;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci		offset = ati_remote2_lookup(scancode & 0xff);
5488c2ecf20Sopenharmony_ci		if (offset < 0)
5498c2ecf20Sopenharmony_ci			return -EINVAL;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	*old_keycode = ar2->keycode[mode][offset];
5538c2ecf20Sopenharmony_ci	ar2->keycode[mode][offset] = ke->keycode;
5548c2ecf20Sopenharmony_ci	__set_bit(ke->keycode, idev->keybit);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
5578c2ecf20Sopenharmony_ci		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
5588c2ecf20Sopenharmony_ci			if (ar2->keycode[mode][index] == *old_keycode)
5598c2ecf20Sopenharmony_ci				return 0;
5608c2ecf20Sopenharmony_ci		}
5618c2ecf20Sopenharmony_ci	}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	__clear_bit(*old_keycode, idev->keybit);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	return 0;
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic int ati_remote2_input_init(struct ati_remote2 *ar2)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct input_dev *idev;
5718c2ecf20Sopenharmony_ci	int index, mode, retval;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	idev = input_allocate_device();
5748c2ecf20Sopenharmony_ci	if (!idev)
5758c2ecf20Sopenharmony_ci		return -ENOMEM;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	ar2->idev = idev;
5788c2ecf20Sopenharmony_ci	input_set_drvdata(idev, ar2);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
5818c2ecf20Sopenharmony_ci	idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
5828c2ecf20Sopenharmony_ci		BIT_MASK(BTN_RIGHT);
5838c2ecf20Sopenharmony_ci	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
5868c2ecf20Sopenharmony_ci		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
5878c2ecf20Sopenharmony_ci			ar2->keycode[mode][index] = ati_remote2_key_table[index].keycode;
5888c2ecf20Sopenharmony_ci			__set_bit(ar2->keycode[mode][index], idev->keybit);
5898c2ecf20Sopenharmony_ci		}
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/* AUX1-AUX4 and PC generate the same scancode. */
5938c2ecf20Sopenharmony_ci	index = ati_remote2_lookup(0x3f);
5948c2ecf20Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_AUX1][index] = KEY_PROG1;
5958c2ecf20Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_AUX2][index] = KEY_PROG2;
5968c2ecf20Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_AUX3][index] = KEY_PROG3;
5978c2ecf20Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_AUX4][index] = KEY_PROG4;
5988c2ecf20Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_PC][index] = KEY_PC;
5998c2ecf20Sopenharmony_ci	__set_bit(KEY_PROG1, idev->keybit);
6008c2ecf20Sopenharmony_ci	__set_bit(KEY_PROG2, idev->keybit);
6018c2ecf20Sopenharmony_ci	__set_bit(KEY_PROG3, idev->keybit);
6028c2ecf20Sopenharmony_ci	__set_bit(KEY_PROG4, idev->keybit);
6038c2ecf20Sopenharmony_ci	__set_bit(KEY_PC, idev->keybit);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	idev->rep[REP_DELAY]  = 250;
6068c2ecf20Sopenharmony_ci	idev->rep[REP_PERIOD] = 33;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	idev->open = ati_remote2_open;
6098c2ecf20Sopenharmony_ci	idev->close = ati_remote2_close;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	idev->getkeycode = ati_remote2_getkeycode;
6128c2ecf20Sopenharmony_ci	idev->setkeycode = ati_remote2_setkeycode;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	idev->name = ar2->name;
6158c2ecf20Sopenharmony_ci	idev->phys = ar2->phys;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	usb_to_input_id(ar2->udev, &idev->id);
6188c2ecf20Sopenharmony_ci	idev->dev.parent = &ar2->udev->dev;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	retval = input_register_device(idev);
6218c2ecf20Sopenharmony_ci	if (retval)
6228c2ecf20Sopenharmony_ci		input_free_device(idev);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	return retval;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_cistatic int ati_remote2_urb_init(struct ati_remote2 *ar2)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	struct usb_device *udev = ar2->udev;
6308c2ecf20Sopenharmony_ci	int i, pipe, maxp;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
6338c2ecf20Sopenharmony_ci		ar2->buf[i] = usb_alloc_coherent(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
6348c2ecf20Sopenharmony_ci		if (!ar2->buf[i])
6358c2ecf20Sopenharmony_ci			return -ENOMEM;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
6388c2ecf20Sopenharmony_ci		if (!ar2->urb[i])
6398c2ecf20Sopenharmony_ci			return -ENOMEM;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
6428c2ecf20Sopenharmony_ci		maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
6438c2ecf20Sopenharmony_ci		maxp = maxp > 4 ? 4 : maxp;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
6468c2ecf20Sopenharmony_ci				 i ? ati_remote2_complete_key : ati_remote2_complete_mouse,
6478c2ecf20Sopenharmony_ci				 ar2, ar2->ep[i]->bInterval);
6488c2ecf20Sopenharmony_ci		ar2->urb[i]->transfer_dma = ar2->buf_dma[i];
6498c2ecf20Sopenharmony_ci		ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	return 0;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	int i;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
6608c2ecf20Sopenharmony_ci		usb_free_urb(ar2->urb[i]);
6618c2ecf20Sopenharmony_ci		usb_free_coherent(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
6628c2ecf20Sopenharmony_ci	}
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic int ati_remote2_setup(struct ati_remote2 *ar2, unsigned int ch_mask)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	int r, i, channel;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	/*
6708c2ecf20Sopenharmony_ci	 * Configure receiver to only accept input from remote "channel"
6718c2ecf20Sopenharmony_ci	 *  channel == 0  -> Accept input from any remote channel
6728c2ecf20Sopenharmony_ci	 *  channel == 1  -> Only accept input from remote channel 1
6738c2ecf20Sopenharmony_ci	 *  channel == 2  -> Only accept input from remote channel 2
6748c2ecf20Sopenharmony_ci	 *  ...
6758c2ecf20Sopenharmony_ci	 *  channel == 16 -> Only accept input from remote channel 16
6768c2ecf20Sopenharmony_ci	 */
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	channel = 0;
6798c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++) {
6808c2ecf20Sopenharmony_ci		if ((1 << i) & ch_mask) {
6818c2ecf20Sopenharmony_ci			if (!(~(1 << i) & ch_mask))
6828c2ecf20Sopenharmony_ci				channel = i + 1;
6838c2ecf20Sopenharmony_ci			break;
6848c2ecf20Sopenharmony_ci		}
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0),
6888c2ecf20Sopenharmony_ci			    0x20,
6898c2ecf20Sopenharmony_ci			    USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
6908c2ecf20Sopenharmony_ci			    channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT);
6918c2ecf20Sopenharmony_ci	if (r) {
6928c2ecf20Sopenharmony_ci		dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n",
6938c2ecf20Sopenharmony_ci			__func__, r);
6948c2ecf20Sopenharmony_ci		return r;
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	return 0;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic ssize_t ati_remote2_show_channel_mask(struct device *dev,
7018c2ecf20Sopenharmony_ci					     struct device_attribute *attr,
7028c2ecf20Sopenharmony_ci					     char *buf)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
7058c2ecf20Sopenharmony_ci	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
7068c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%04x\n", ar2->channel_mask);
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_cistatic ssize_t ati_remote2_store_channel_mask(struct device *dev,
7128c2ecf20Sopenharmony_ci					      struct device_attribute *attr,
7138c2ecf20Sopenharmony_ci					      const char *buf, size_t count)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
7168c2ecf20Sopenharmony_ci	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
7178c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
7188c2ecf20Sopenharmony_ci	unsigned int mask;
7198c2ecf20Sopenharmony_ci	int r;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	r = kstrtouint(buf, 0, &mask);
7228c2ecf20Sopenharmony_ci	if (r)
7238c2ecf20Sopenharmony_ci		return r;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	if (mask & ~ATI_REMOTE2_MAX_CHANNEL_MASK)
7268c2ecf20Sopenharmony_ci		return -EINVAL;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	r = usb_autopm_get_interface(ar2->intf[0]);
7298c2ecf20Sopenharmony_ci	if (r) {
7308c2ecf20Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
7318c2ecf20Sopenharmony_ci			"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
7328c2ecf20Sopenharmony_ci		return r;
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	if (mask != ar2->channel_mask) {
7388c2ecf20Sopenharmony_ci		r = ati_remote2_setup(ar2, mask);
7398c2ecf20Sopenharmony_ci		if (!r)
7408c2ecf20Sopenharmony_ci			ar2->channel_mask = mask;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	usb_autopm_put_interface(ar2->intf[0]);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	return r ? r : count;
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic ssize_t ati_remote2_show_mode_mask(struct device *dev,
7518c2ecf20Sopenharmony_ci					  struct device_attribute *attr,
7528c2ecf20Sopenharmony_ci					  char *buf)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
7558c2ecf20Sopenharmony_ci	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
7568c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%02x\n", ar2->mode_mask);
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic ssize_t ati_remote2_store_mode_mask(struct device *dev,
7628c2ecf20Sopenharmony_ci					   struct device_attribute *attr,
7638c2ecf20Sopenharmony_ci					   const char *buf, size_t count)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
7668c2ecf20Sopenharmony_ci	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
7678c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
7688c2ecf20Sopenharmony_ci	unsigned int mask;
7698c2ecf20Sopenharmony_ci	int err;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	err = kstrtouint(buf, 0, &mask);
7728c2ecf20Sopenharmony_ci	if (err)
7738c2ecf20Sopenharmony_ci		return err;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (mask & ~ATI_REMOTE2_MAX_MODE_MASK)
7768c2ecf20Sopenharmony_ci		return -EINVAL;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	ar2->mode_mask = mask;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	return count;
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic DEVICE_ATTR(channel_mask, 0644, ati_remote2_show_channel_mask,
7848c2ecf20Sopenharmony_ci		   ati_remote2_store_channel_mask);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cistatic DEVICE_ATTR(mode_mask, 0644, ati_remote2_show_mode_mask,
7878c2ecf20Sopenharmony_ci		   ati_remote2_store_mode_mask);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cistatic struct attribute *ati_remote2_attrs[] = {
7908c2ecf20Sopenharmony_ci	&dev_attr_channel_mask.attr,
7918c2ecf20Sopenharmony_ci	&dev_attr_mode_mask.attr,
7928c2ecf20Sopenharmony_ci	NULL,
7938c2ecf20Sopenharmony_ci};
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_cistatic struct attribute_group ati_remote2_attr_group = {
7968c2ecf20Sopenharmony_ci	.attrs = ati_remote2_attrs,
7978c2ecf20Sopenharmony_ci};
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(interface);
8028c2ecf20Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
8038c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2;
8048c2ecf20Sopenharmony_ci	int r;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
8078c2ecf20Sopenharmony_ci		return -ENODEV;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL);
8108c2ecf20Sopenharmony_ci	if (!ar2)
8118c2ecf20Sopenharmony_ci		return -ENOMEM;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	ar2->udev = udev;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	/* Sanity check, first interface must have an endpoint */
8168c2ecf20Sopenharmony_ci	if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
8178c2ecf20Sopenharmony_ci		dev_err(&interface->dev,
8188c2ecf20Sopenharmony_ci			"%s(): interface 0 must have an endpoint\n", __func__);
8198c2ecf20Sopenharmony_ci		r = -ENODEV;
8208c2ecf20Sopenharmony_ci		goto fail1;
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci	ar2->intf[0] = interface;
8238c2ecf20Sopenharmony_ci	ar2->ep[0] = &alt->endpoint[0].desc;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	/* Sanity check, the device must have two interfaces */
8268c2ecf20Sopenharmony_ci	ar2->intf[1] = usb_ifnum_to_if(udev, 1);
8278c2ecf20Sopenharmony_ci	if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) {
8288c2ecf20Sopenharmony_ci		dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n",
8298c2ecf20Sopenharmony_ci			__func__, udev->actconfig->desc.bNumInterfaces);
8308c2ecf20Sopenharmony_ci		r = -ENODEV;
8318c2ecf20Sopenharmony_ci		goto fail1;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
8358c2ecf20Sopenharmony_ci	if (r)
8368c2ecf20Sopenharmony_ci		goto fail1;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	/* Sanity check, second interface must have an endpoint */
8398c2ecf20Sopenharmony_ci	alt = ar2->intf[1]->cur_altsetting;
8408c2ecf20Sopenharmony_ci	if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
8418c2ecf20Sopenharmony_ci		dev_err(&interface->dev,
8428c2ecf20Sopenharmony_ci			"%s(): interface 1 must have an endpoint\n", __func__);
8438c2ecf20Sopenharmony_ci		r = -ENODEV;
8448c2ecf20Sopenharmony_ci		goto fail2;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci	ar2->ep[1] = &alt->endpoint[0].desc;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	r = ati_remote2_urb_init(ar2);
8498c2ecf20Sopenharmony_ci	if (r)
8508c2ecf20Sopenharmony_ci		goto fail3;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	ar2->channel_mask = channel_mask;
8538c2ecf20Sopenharmony_ci	ar2->mode_mask = mode_mask;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	r = ati_remote2_setup(ar2, ar2->channel_mask);
8568c2ecf20Sopenharmony_ci	if (r)
8578c2ecf20Sopenharmony_ci		goto fail3;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
8608c2ecf20Sopenharmony_ci	strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);
8658c2ecf20Sopenharmony_ci	if (r)
8668c2ecf20Sopenharmony_ci		goto fail3;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	r = ati_remote2_input_init(ar2);
8698c2ecf20Sopenharmony_ci	if (r)
8708c2ecf20Sopenharmony_ci		goto fail4;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	usb_set_intfdata(interface, ar2);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	interface->needs_remote_wakeup = 1;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	return 0;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci fail4:
8798c2ecf20Sopenharmony_ci	sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);
8808c2ecf20Sopenharmony_ci fail3:
8818c2ecf20Sopenharmony_ci	ati_remote2_urb_cleanup(ar2);
8828c2ecf20Sopenharmony_ci fail2:
8838c2ecf20Sopenharmony_ci	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
8848c2ecf20Sopenharmony_ci fail1:
8858c2ecf20Sopenharmony_ci	kfree(ar2);
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	return r;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic void ati_remote2_disconnect(struct usb_interface *interface)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2;
8938c2ecf20Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
8968c2ecf20Sopenharmony_ci		return;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
8998c2ecf20Sopenharmony_ci	usb_set_intfdata(interface, NULL);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	input_unregister_device(ar2->idev);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	sysfs_remove_group(&ar2->udev->dev.kobj, &ati_remote2_attr_group);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	ati_remote2_urb_cleanup(ar2);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	kfree(ar2);
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic int ati_remote2_suspend(struct usb_interface *interface,
9138c2ecf20Sopenharmony_ci			       pm_message_t message)
9148c2ecf20Sopenharmony_ci{
9158c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2;
9168c2ecf20Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
9198c2ecf20Sopenharmony_ci		return 0;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	if (ar2->flags & ATI_REMOTE2_OPENED)
9288c2ecf20Sopenharmony_ci		ati_remote2_kill_urbs(ar2);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	ar2->flags |= ATI_REMOTE2_SUSPENDED;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	return 0;
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic int ati_remote2_resume(struct usb_interface *interface)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2;
9408c2ecf20Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
9418c2ecf20Sopenharmony_ci	int r = 0;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
9448c2ecf20Sopenharmony_ci		return 0;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	if (ar2->flags & ATI_REMOTE2_OPENED)
9538c2ecf20Sopenharmony_ci		r = ati_remote2_submit_urbs(ar2);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (!r)
9568c2ecf20Sopenharmony_ci		ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	return r;
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cistatic int ati_remote2_reset_resume(struct usb_interface *interface)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2;
9668c2ecf20Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
9678c2ecf20Sopenharmony_ci	int r = 0;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
9708c2ecf20Sopenharmony_ci		return 0;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	r = ati_remote2_setup(ar2, ar2->channel_mask);
9798c2ecf20Sopenharmony_ci	if (r)
9808c2ecf20Sopenharmony_ci		goto out;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	if (ar2->flags & ATI_REMOTE2_OPENED)
9838c2ecf20Sopenharmony_ci		r = ati_remote2_submit_urbs(ar2);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (!r)
9868c2ecf20Sopenharmony_ci		ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci out:
9898c2ecf20Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	return r;
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic int ati_remote2_pre_reset(struct usb_interface *interface)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2;
9978c2ecf20Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
10008c2ecf20Sopenharmony_ci		return 0;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	if (ar2->flags == ATI_REMOTE2_OPENED)
10098c2ecf20Sopenharmony_ci		ati_remote2_kill_urbs(ar2);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	return 0;
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_cistatic int ati_remote2_post_reset(struct usb_interface *interface)
10158c2ecf20Sopenharmony_ci{
10168c2ecf20Sopenharmony_ci	struct ati_remote2 *ar2;
10178c2ecf20Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
10188c2ecf20Sopenharmony_ci	int r = 0;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
10218c2ecf20Sopenharmony_ci		return 0;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if (ar2->flags == ATI_REMOTE2_OPENED)
10288c2ecf20Sopenharmony_ci		r = ati_remote2_submit_urbs(ar2);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	return r;
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_cimodule_usb_driver(ati_remote2_driver);
1036