162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ati_remote2 - ATI/Philips USB RF remote driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi>
662306a36Sopenharmony_ci * Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/usb/input.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define DRIVER_DESC    "ATI/Philips USB RF remote driver"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
1662306a36Sopenharmony_ciMODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
1762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * ATI Remote Wonder II Channel Configuration
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * The remote control can be assigned one of sixteen "channels" in order to facilitate
2362306a36Sopenharmony_ci * the use of multiple remote controls within range of each other.
2462306a36Sopenharmony_ci * A remote's "channel" may be altered by pressing and holding the "PC" button for
2562306a36Sopenharmony_ci * approximately 3 seconds, after which the button will slowly flash the count of the
2662306a36Sopenharmony_ci * currently configured "channel", using the numeric keypad enter a number between 1 and
2762306a36Sopenharmony_ci * 16 and then press the "PC" button again, the button will slowly flash the count of the
2862306a36Sopenharmony_ci * newly configured "channel".
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cienum {
3262306a36Sopenharmony_ci	ATI_REMOTE2_MAX_CHANNEL_MASK = 0xFFFF,
3362306a36Sopenharmony_ci	ATI_REMOTE2_MAX_MODE_MASK = 0x1F,
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int ati_remote2_set_mask(const char *val,
3762306a36Sopenharmony_ci				const struct kernel_param *kp,
3862306a36Sopenharmony_ci				unsigned int max)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	unsigned int mask;
4162306a36Sopenharmony_ci	int ret;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (!val)
4462306a36Sopenharmony_ci		return -EINVAL;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	ret = kstrtouint(val, 0, &mask);
4762306a36Sopenharmony_ci	if (ret)
4862306a36Sopenharmony_ci		return ret;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (mask & ~max)
5162306a36Sopenharmony_ci		return -EINVAL;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	*(unsigned int *)kp->arg = mask;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return 0;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int ati_remote2_set_channel_mask(const char *val,
5962306a36Sopenharmony_ci					const struct kernel_param *kp)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	pr_debug("%s()\n", __func__);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_CHANNEL_MASK);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int ati_remote2_get_channel_mask(char *buffer,
6762306a36Sopenharmony_ci					const struct kernel_param *kp)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	pr_debug("%s()\n", __func__);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return sprintf(buffer, "0x%04x\n", *(unsigned int *)kp->arg);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int ati_remote2_set_mode_mask(const char *val,
7562306a36Sopenharmony_ci				     const struct kernel_param *kp)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	pr_debug("%s()\n", __func__);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_MODE_MASK);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int ati_remote2_get_mode_mask(char *buffer,
8362306a36Sopenharmony_ci				     const struct kernel_param *kp)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	pr_debug("%s()\n", __func__);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return sprintf(buffer, "0x%02x\n", *(unsigned int *)kp->arg);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
9162306a36Sopenharmony_ci#define param_check_channel_mask(name, p) __param_check(name, p, unsigned int)
9262306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_channel_mask = {
9362306a36Sopenharmony_ci	.set = ati_remote2_set_channel_mask,
9462306a36Sopenharmony_ci	.get = ati_remote2_get_channel_mask,
9562306a36Sopenharmony_ci};
9662306a36Sopenharmony_cimodule_param(channel_mask, channel_mask, 0644);
9762306a36Sopenharmony_ciMODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK;
10062306a36Sopenharmony_ci#define param_check_mode_mask(name, p) __param_check(name, p, unsigned int)
10162306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_mode_mask = {
10262306a36Sopenharmony_ci	.set = ati_remote2_set_mode_mask,
10362306a36Sopenharmony_ci	.get = ati_remote2_get_mode_mask,
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_cimodule_param(mode_mask, mode_mask, 0644);
10662306a36Sopenharmony_ciMODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic const struct usb_device_id ati_remote2_id_table[] = {
10962306a36Sopenharmony_ci	{ USB_DEVICE(0x0471, 0x0602) },	/* ATI Remote Wonder II */
11062306a36Sopenharmony_ci	{ }
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic DEFINE_MUTEX(ati_remote2_mutex);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cienum {
11762306a36Sopenharmony_ci	ATI_REMOTE2_OPENED = 0x1,
11862306a36Sopenharmony_ci	ATI_REMOTE2_SUSPENDED = 0x2,
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cienum {
12262306a36Sopenharmony_ci	ATI_REMOTE2_AUX1,
12362306a36Sopenharmony_ci	ATI_REMOTE2_AUX2,
12462306a36Sopenharmony_ci	ATI_REMOTE2_AUX3,
12562306a36Sopenharmony_ci	ATI_REMOTE2_AUX4,
12662306a36Sopenharmony_ci	ATI_REMOTE2_PC,
12762306a36Sopenharmony_ci	ATI_REMOTE2_MODES,
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic const struct {
13162306a36Sopenharmony_ci	u8  hw_code;
13262306a36Sopenharmony_ci	u16 keycode;
13362306a36Sopenharmony_ci} ati_remote2_key_table[] = {
13462306a36Sopenharmony_ci	{ 0x00, KEY_0 },
13562306a36Sopenharmony_ci	{ 0x01, KEY_1 },
13662306a36Sopenharmony_ci	{ 0x02, KEY_2 },
13762306a36Sopenharmony_ci	{ 0x03, KEY_3 },
13862306a36Sopenharmony_ci	{ 0x04, KEY_4 },
13962306a36Sopenharmony_ci	{ 0x05, KEY_5 },
14062306a36Sopenharmony_ci	{ 0x06, KEY_6 },
14162306a36Sopenharmony_ci	{ 0x07, KEY_7 },
14262306a36Sopenharmony_ci	{ 0x08, KEY_8 },
14362306a36Sopenharmony_ci	{ 0x09, KEY_9 },
14462306a36Sopenharmony_ci	{ 0x0c, KEY_POWER },
14562306a36Sopenharmony_ci	{ 0x0d, KEY_MUTE },
14662306a36Sopenharmony_ci	{ 0x10, KEY_VOLUMEUP },
14762306a36Sopenharmony_ci	{ 0x11, KEY_VOLUMEDOWN },
14862306a36Sopenharmony_ci	{ 0x20, KEY_CHANNELUP },
14962306a36Sopenharmony_ci	{ 0x21, KEY_CHANNELDOWN },
15062306a36Sopenharmony_ci	{ 0x28, KEY_FORWARD },
15162306a36Sopenharmony_ci	{ 0x29, KEY_REWIND },
15262306a36Sopenharmony_ci	{ 0x2c, KEY_PLAY },
15362306a36Sopenharmony_ci	{ 0x30, KEY_PAUSE },
15462306a36Sopenharmony_ci	{ 0x31, KEY_STOP },
15562306a36Sopenharmony_ci	{ 0x37, KEY_RECORD },
15662306a36Sopenharmony_ci	{ 0x38, KEY_DVD },
15762306a36Sopenharmony_ci	{ 0x39, KEY_TV },
15862306a36Sopenharmony_ci	{ 0x3f, KEY_PROG1 }, /* AUX1-AUX4 and PC */
15962306a36Sopenharmony_ci	{ 0x54, KEY_MENU },
16062306a36Sopenharmony_ci	{ 0x58, KEY_UP },
16162306a36Sopenharmony_ci	{ 0x59, KEY_DOWN },
16262306a36Sopenharmony_ci	{ 0x5a, KEY_LEFT },
16362306a36Sopenharmony_ci	{ 0x5b, KEY_RIGHT },
16462306a36Sopenharmony_ci	{ 0x5c, KEY_OK },
16562306a36Sopenharmony_ci	{ 0x78, KEY_A },
16662306a36Sopenharmony_ci	{ 0x79, KEY_B },
16762306a36Sopenharmony_ci	{ 0x7a, KEY_C },
16862306a36Sopenharmony_ci	{ 0x7b, KEY_D },
16962306a36Sopenharmony_ci	{ 0x7c, KEY_E },
17062306a36Sopenharmony_ci	{ 0x7d, KEY_F },
17162306a36Sopenharmony_ci	{ 0x82, KEY_ENTER },
17262306a36Sopenharmony_ci	{ 0x8e, KEY_VENDOR },
17362306a36Sopenharmony_ci	{ 0x96, KEY_COFFEE },
17462306a36Sopenharmony_ci	{ 0xa9, BTN_LEFT },
17562306a36Sopenharmony_ci	{ 0xaa, BTN_RIGHT },
17662306a36Sopenharmony_ci	{ 0xbe, KEY_QUESTION },
17762306a36Sopenharmony_ci	{ 0xd0, KEY_EDIT },
17862306a36Sopenharmony_ci	{ 0xd5, KEY_FRONT },
17962306a36Sopenharmony_ci	{ 0xf9, KEY_INFO },
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistruct ati_remote2 {
18362306a36Sopenharmony_ci	struct input_dev *idev;
18462306a36Sopenharmony_ci	struct usb_device *udev;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	struct usb_interface *intf[2];
18762306a36Sopenharmony_ci	struct usb_endpoint_descriptor *ep[2];
18862306a36Sopenharmony_ci	struct urb *urb[2];
18962306a36Sopenharmony_ci	void *buf[2];
19062306a36Sopenharmony_ci	dma_addr_t buf_dma[2];
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	unsigned long jiffies;
19362306a36Sopenharmony_ci	int mode;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	char name[64];
19662306a36Sopenharmony_ci	char phys[64];
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* Each mode (AUX1-AUX4 and PC) can have an independent keymap. */
19962306a36Sopenharmony_ci	u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)];
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	unsigned int flags;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	unsigned int channel_mask;
20462306a36Sopenharmony_ci	unsigned int mode_mask;
20562306a36Sopenharmony_ci};
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
20862306a36Sopenharmony_cistatic void ati_remote2_disconnect(struct usb_interface *interface);
20962306a36Sopenharmony_cistatic int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message);
21062306a36Sopenharmony_cistatic int ati_remote2_resume(struct usb_interface *interface);
21162306a36Sopenharmony_cistatic int ati_remote2_reset_resume(struct usb_interface *interface);
21262306a36Sopenharmony_cistatic int ati_remote2_pre_reset(struct usb_interface *interface);
21362306a36Sopenharmony_cistatic int ati_remote2_post_reset(struct usb_interface *interface);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic struct usb_driver ati_remote2_driver = {
21662306a36Sopenharmony_ci	.name       = "ati_remote2",
21762306a36Sopenharmony_ci	.probe      = ati_remote2_probe,
21862306a36Sopenharmony_ci	.disconnect = ati_remote2_disconnect,
21962306a36Sopenharmony_ci	.id_table   = ati_remote2_id_table,
22062306a36Sopenharmony_ci	.suspend    = ati_remote2_suspend,
22162306a36Sopenharmony_ci	.resume     = ati_remote2_resume,
22262306a36Sopenharmony_ci	.reset_resume = ati_remote2_reset_resume,
22362306a36Sopenharmony_ci	.pre_reset  = ati_remote2_pre_reset,
22462306a36Sopenharmony_ci	.post_reset = ati_remote2_post_reset,
22562306a36Sopenharmony_ci	.supports_autosuspend = 1,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int ati_remote2_submit_urbs(struct ati_remote2 *ar2)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	int r;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
23362306a36Sopenharmony_ci	if (r) {
23462306a36Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
23562306a36Sopenharmony_ci			"%s(): usb_submit_urb() = %d\n", __func__, r);
23662306a36Sopenharmony_ci		return r;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci	r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
23962306a36Sopenharmony_ci	if (r) {
24062306a36Sopenharmony_ci		usb_kill_urb(ar2->urb[0]);
24162306a36Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
24262306a36Sopenharmony_ci			"%s(): usb_submit_urb() = %d\n", __func__, r);
24362306a36Sopenharmony_ci		return r;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void ati_remote2_kill_urbs(struct ati_remote2 *ar2)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	usb_kill_urb(ar2->urb[1]);
25262306a36Sopenharmony_ci	usb_kill_urb(ar2->urb[0]);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic int ati_remote2_open(struct input_dev *idev)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct ati_remote2 *ar2 = input_get_drvdata(idev);
25862306a36Sopenharmony_ci	int r;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	r = usb_autopm_get_interface(ar2->intf[0]);
26362306a36Sopenharmony_ci	if (r) {
26462306a36Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
26562306a36Sopenharmony_ci			"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
26662306a36Sopenharmony_ci		goto fail1;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) {
27262306a36Sopenharmony_ci		r = ati_remote2_submit_urbs(ar2);
27362306a36Sopenharmony_ci		if (r)
27462306a36Sopenharmony_ci			goto fail2;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ar2->flags |= ATI_REMOTE2_OPENED;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	usb_autopm_put_interface(ar2->intf[0]);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return 0;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci fail2:
28662306a36Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
28762306a36Sopenharmony_ci	usb_autopm_put_interface(ar2->intf[0]);
28862306a36Sopenharmony_ci fail1:
28962306a36Sopenharmony_ci	return r;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic void ati_remote2_close(struct input_dev *idev)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct ati_remote2 *ar2 = input_get_drvdata(idev);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (!(ar2->flags & ATI_REMOTE2_SUSPENDED))
30162306a36Sopenharmony_ci		ati_remote2_kill_urbs(ar2);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	ar2->flags &= ~ATI_REMOTE2_OPENED;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic void ati_remote2_input_mouse(struct ati_remote2 *ar2)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct input_dev *idev = ar2->idev;
31162306a36Sopenharmony_ci	u8 *data = ar2->buf[0];
31262306a36Sopenharmony_ci	int channel, mode;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	channel = data[0] >> 4;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (!((1 << channel) & ar2->channel_mask))
31762306a36Sopenharmony_ci		return;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	mode = data[0] & 0x0F;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (mode > ATI_REMOTE2_PC) {
32262306a36Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
32362306a36Sopenharmony_ci			"Unknown mode byte (%02x %02x %02x %02x)\n",
32462306a36Sopenharmony_ci			data[3], data[2], data[1], data[0]);
32562306a36Sopenharmony_ci		return;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (!((1 << mode) & ar2->mode_mask))
32962306a36Sopenharmony_ci		return;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	input_event(idev, EV_REL, REL_X, (s8) data[1]);
33262306a36Sopenharmony_ci	input_event(idev, EV_REL, REL_Y, (s8) data[2]);
33362306a36Sopenharmony_ci	input_sync(idev);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int ati_remote2_lookup(unsigned int hw_code)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	int i;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ati_remote2_key_table); i++)
34162306a36Sopenharmony_ci		if (ati_remote2_key_table[i].hw_code == hw_code)
34262306a36Sopenharmony_ci			return i;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return -1;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic void ati_remote2_input_key(struct ati_remote2 *ar2)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct input_dev *idev = ar2->idev;
35062306a36Sopenharmony_ci	u8 *data = ar2->buf[1];
35162306a36Sopenharmony_ci	int channel, mode, hw_code, index;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	channel = data[0] >> 4;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (!((1 << channel) & ar2->channel_mask))
35662306a36Sopenharmony_ci		return;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	mode = data[0] & 0x0F;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (mode > ATI_REMOTE2_PC) {
36162306a36Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
36262306a36Sopenharmony_ci			"Unknown mode byte (%02x %02x %02x %02x)\n",
36362306a36Sopenharmony_ci			data[3], data[2], data[1], data[0]);
36462306a36Sopenharmony_ci		return;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	hw_code = data[2];
36862306a36Sopenharmony_ci	if (hw_code == 0x3f) {
36962306a36Sopenharmony_ci		/*
37062306a36Sopenharmony_ci		 * For some incomprehensible reason the mouse pad generates
37162306a36Sopenharmony_ci		 * events which look identical to the events from the last
37262306a36Sopenharmony_ci		 * pressed mode key. Naturally we don't want to generate key
37362306a36Sopenharmony_ci		 * events for the mouse pad so we filter out any subsequent
37462306a36Sopenharmony_ci		 * events from the same mode key.
37562306a36Sopenharmony_ci		 */
37662306a36Sopenharmony_ci		if (ar2->mode == mode)
37762306a36Sopenharmony_ci			return;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		if (data[1] == 0)
38062306a36Sopenharmony_ci			ar2->mode = mode;
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (!((1 << mode) & ar2->mode_mask))
38462306a36Sopenharmony_ci		return;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	index = ati_remote2_lookup(hw_code);
38762306a36Sopenharmony_ci	if (index < 0) {
38862306a36Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
38962306a36Sopenharmony_ci			"Unknown code byte (%02x %02x %02x %02x)\n",
39062306a36Sopenharmony_ci			data[3], data[2], data[1], data[0]);
39162306a36Sopenharmony_ci		return;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	switch (data[1]) {
39562306a36Sopenharmony_ci	case 0:	/* release */
39662306a36Sopenharmony_ci		break;
39762306a36Sopenharmony_ci	case 1:	/* press */
39862306a36Sopenharmony_ci		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]);
39962306a36Sopenharmony_ci		break;
40062306a36Sopenharmony_ci	case 2:	/* repeat */
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		/* No repeat for mouse buttons. */
40362306a36Sopenharmony_ci		if (ar2->keycode[mode][index] == BTN_LEFT ||
40462306a36Sopenharmony_ci		    ar2->keycode[mode][index] == BTN_RIGHT)
40562306a36Sopenharmony_ci			return;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		if (!time_after_eq(jiffies, ar2->jiffies))
40862306a36Sopenharmony_ci			return;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]);
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	default:
41362306a36Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
41462306a36Sopenharmony_ci			"Unknown state byte (%02x %02x %02x %02x)\n",
41562306a36Sopenharmony_ci			data[3], data[2], data[1], data[0]);
41662306a36Sopenharmony_ci		return;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	input_event(idev, EV_KEY, ar2->keycode[mode][index], data[1]);
42062306a36Sopenharmony_ci	input_sync(idev);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void ati_remote2_complete_mouse(struct urb *urb)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct ati_remote2 *ar2 = urb->context;
42662306a36Sopenharmony_ci	int r;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	switch (urb->status) {
42962306a36Sopenharmony_ci	case 0:
43062306a36Sopenharmony_ci		usb_mark_last_busy(ar2->udev);
43162306a36Sopenharmony_ci		ati_remote2_input_mouse(ar2);
43262306a36Sopenharmony_ci		break;
43362306a36Sopenharmony_ci	case -ENOENT:
43462306a36Sopenharmony_ci	case -EILSEQ:
43562306a36Sopenharmony_ci	case -ECONNRESET:
43662306a36Sopenharmony_ci	case -ESHUTDOWN:
43762306a36Sopenharmony_ci		dev_dbg(&ar2->intf[0]->dev,
43862306a36Sopenharmony_ci			"%s(): urb status = %d\n", __func__, urb->status);
43962306a36Sopenharmony_ci		return;
44062306a36Sopenharmony_ci	default:
44162306a36Sopenharmony_ci		usb_mark_last_busy(ar2->udev);
44262306a36Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
44362306a36Sopenharmony_ci			"%s(): urb status = %d\n", __func__, urb->status);
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	r = usb_submit_urb(urb, GFP_ATOMIC);
44762306a36Sopenharmony_ci	if (r)
44862306a36Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
44962306a36Sopenharmony_ci			"%s(): usb_submit_urb() = %d\n", __func__, r);
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic void ati_remote2_complete_key(struct urb *urb)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct ati_remote2 *ar2 = urb->context;
45562306a36Sopenharmony_ci	int r;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	switch (urb->status) {
45862306a36Sopenharmony_ci	case 0:
45962306a36Sopenharmony_ci		usb_mark_last_busy(ar2->udev);
46062306a36Sopenharmony_ci		ati_remote2_input_key(ar2);
46162306a36Sopenharmony_ci		break;
46262306a36Sopenharmony_ci	case -ENOENT:
46362306a36Sopenharmony_ci	case -EILSEQ:
46462306a36Sopenharmony_ci	case -ECONNRESET:
46562306a36Sopenharmony_ci	case -ESHUTDOWN:
46662306a36Sopenharmony_ci		dev_dbg(&ar2->intf[1]->dev,
46762306a36Sopenharmony_ci			"%s(): urb status = %d\n", __func__, urb->status);
46862306a36Sopenharmony_ci		return;
46962306a36Sopenharmony_ci	default:
47062306a36Sopenharmony_ci		usb_mark_last_busy(ar2->udev);
47162306a36Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
47262306a36Sopenharmony_ci			"%s(): urb status = %d\n", __func__, urb->status);
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	r = usb_submit_urb(urb, GFP_ATOMIC);
47662306a36Sopenharmony_ci	if (r)
47762306a36Sopenharmony_ci		dev_err(&ar2->intf[1]->dev,
47862306a36Sopenharmony_ci			"%s(): usb_submit_urb() = %d\n", __func__, r);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic int ati_remote2_getkeycode(struct input_dev *idev,
48262306a36Sopenharmony_ci				  struct input_keymap_entry *ke)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct ati_remote2 *ar2 = input_get_drvdata(idev);
48562306a36Sopenharmony_ci	unsigned int mode;
48662306a36Sopenharmony_ci	int offset;
48762306a36Sopenharmony_ci	unsigned int index;
48862306a36Sopenharmony_ci	unsigned int scancode;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
49162306a36Sopenharmony_ci		index = ke->index;
49262306a36Sopenharmony_ci		if (index >= ATI_REMOTE2_MODES *
49362306a36Sopenharmony_ci				ARRAY_SIZE(ati_remote2_key_table))
49462306a36Sopenharmony_ci			return -EINVAL;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci		mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
49762306a36Sopenharmony_ci		offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
49862306a36Sopenharmony_ci		scancode = (mode << 8) + ati_remote2_key_table[offset].hw_code;
49962306a36Sopenharmony_ci	} else {
50062306a36Sopenharmony_ci		if (input_scancode_to_scalar(ke, &scancode))
50162306a36Sopenharmony_ci			return -EINVAL;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		mode = scancode >> 8;
50462306a36Sopenharmony_ci		if (mode > ATI_REMOTE2_PC)
50562306a36Sopenharmony_ci			return -EINVAL;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		offset = ati_remote2_lookup(scancode & 0xff);
50862306a36Sopenharmony_ci		if (offset < 0)
50962306a36Sopenharmony_ci			return -EINVAL;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		index = mode * ARRAY_SIZE(ati_remote2_key_table) + offset;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	ke->keycode = ar2->keycode[mode][offset];
51562306a36Sopenharmony_ci	ke->len = sizeof(scancode);
51662306a36Sopenharmony_ci	memcpy(&ke->scancode, &scancode, sizeof(scancode));
51762306a36Sopenharmony_ci	ke->index = index;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return 0;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int ati_remote2_setkeycode(struct input_dev *idev,
52362306a36Sopenharmony_ci				  const struct input_keymap_entry *ke,
52462306a36Sopenharmony_ci				  unsigned int *old_keycode)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct ati_remote2 *ar2 = input_get_drvdata(idev);
52762306a36Sopenharmony_ci	unsigned int mode;
52862306a36Sopenharmony_ci	int offset;
52962306a36Sopenharmony_ci	unsigned int index;
53062306a36Sopenharmony_ci	unsigned int scancode;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
53362306a36Sopenharmony_ci		if (ke->index >= ATI_REMOTE2_MODES *
53462306a36Sopenharmony_ci				ARRAY_SIZE(ati_remote2_key_table))
53562306a36Sopenharmony_ci			return -EINVAL;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
53862306a36Sopenharmony_ci		offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
53962306a36Sopenharmony_ci	} else {
54062306a36Sopenharmony_ci		if (input_scancode_to_scalar(ke, &scancode))
54162306a36Sopenharmony_ci			return -EINVAL;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		mode = scancode >> 8;
54462306a36Sopenharmony_ci		if (mode > ATI_REMOTE2_PC)
54562306a36Sopenharmony_ci			return -EINVAL;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		offset = ati_remote2_lookup(scancode & 0xff);
54862306a36Sopenharmony_ci		if (offset < 0)
54962306a36Sopenharmony_ci			return -EINVAL;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	*old_keycode = ar2->keycode[mode][offset];
55362306a36Sopenharmony_ci	ar2->keycode[mode][offset] = ke->keycode;
55462306a36Sopenharmony_ci	__set_bit(ke->keycode, idev->keybit);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
55762306a36Sopenharmony_ci		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
55862306a36Sopenharmony_ci			if (ar2->keycode[mode][index] == *old_keycode)
55962306a36Sopenharmony_ci				return 0;
56062306a36Sopenharmony_ci		}
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	__clear_bit(*old_keycode, idev->keybit);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	return 0;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic int ati_remote2_input_init(struct ati_remote2 *ar2)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct input_dev *idev;
57162306a36Sopenharmony_ci	int index, mode, retval;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	idev = input_allocate_device();
57462306a36Sopenharmony_ci	if (!idev)
57562306a36Sopenharmony_ci		return -ENOMEM;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	ar2->idev = idev;
57862306a36Sopenharmony_ci	input_set_drvdata(idev, ar2);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
58162306a36Sopenharmony_ci	idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
58262306a36Sopenharmony_ci		BIT_MASK(BTN_RIGHT);
58362306a36Sopenharmony_ci	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
58662306a36Sopenharmony_ci		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
58762306a36Sopenharmony_ci			ar2->keycode[mode][index] = ati_remote2_key_table[index].keycode;
58862306a36Sopenharmony_ci			__set_bit(ar2->keycode[mode][index], idev->keybit);
58962306a36Sopenharmony_ci		}
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	/* AUX1-AUX4 and PC generate the same scancode. */
59362306a36Sopenharmony_ci	index = ati_remote2_lookup(0x3f);
59462306a36Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_AUX1][index] = KEY_PROG1;
59562306a36Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_AUX2][index] = KEY_PROG2;
59662306a36Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_AUX3][index] = KEY_PROG3;
59762306a36Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_AUX4][index] = KEY_PROG4;
59862306a36Sopenharmony_ci	ar2->keycode[ATI_REMOTE2_PC][index] = KEY_PC;
59962306a36Sopenharmony_ci	__set_bit(KEY_PROG1, idev->keybit);
60062306a36Sopenharmony_ci	__set_bit(KEY_PROG2, idev->keybit);
60162306a36Sopenharmony_ci	__set_bit(KEY_PROG3, idev->keybit);
60262306a36Sopenharmony_ci	__set_bit(KEY_PROG4, idev->keybit);
60362306a36Sopenharmony_ci	__set_bit(KEY_PC, idev->keybit);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	idev->rep[REP_DELAY]  = 250;
60662306a36Sopenharmony_ci	idev->rep[REP_PERIOD] = 33;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	idev->open = ati_remote2_open;
60962306a36Sopenharmony_ci	idev->close = ati_remote2_close;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	idev->getkeycode = ati_remote2_getkeycode;
61262306a36Sopenharmony_ci	idev->setkeycode = ati_remote2_setkeycode;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	idev->name = ar2->name;
61562306a36Sopenharmony_ci	idev->phys = ar2->phys;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	usb_to_input_id(ar2->udev, &idev->id);
61862306a36Sopenharmony_ci	idev->dev.parent = &ar2->udev->dev;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	retval = input_register_device(idev);
62162306a36Sopenharmony_ci	if (retval)
62262306a36Sopenharmony_ci		input_free_device(idev);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	return retval;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic int ati_remote2_urb_init(struct ati_remote2 *ar2)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	struct usb_device *udev = ar2->udev;
63062306a36Sopenharmony_ci	int i, pipe, maxp;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
63362306a36Sopenharmony_ci		ar2->buf[i] = usb_alloc_coherent(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
63462306a36Sopenharmony_ci		if (!ar2->buf[i])
63562306a36Sopenharmony_ci			return -ENOMEM;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
63862306a36Sopenharmony_ci		if (!ar2->urb[i])
63962306a36Sopenharmony_ci			return -ENOMEM;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci		pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
64262306a36Sopenharmony_ci		maxp = usb_maxpacket(udev, pipe);
64362306a36Sopenharmony_ci		maxp = maxp > 4 ? 4 : maxp;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
64662306a36Sopenharmony_ci				 i ? ati_remote2_complete_key : ati_remote2_complete_mouse,
64762306a36Sopenharmony_ci				 ar2, ar2->ep[i]->bInterval);
64862306a36Sopenharmony_ci		ar2->urb[i]->transfer_dma = ar2->buf_dma[i];
64962306a36Sopenharmony_ci		ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	return 0;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	int i;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
66062306a36Sopenharmony_ci		usb_free_urb(ar2->urb[i]);
66162306a36Sopenharmony_ci		usb_free_coherent(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic int ati_remote2_setup(struct ati_remote2 *ar2, unsigned int ch_mask)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	int r, i, channel;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/*
67062306a36Sopenharmony_ci	 * Configure receiver to only accept input from remote "channel"
67162306a36Sopenharmony_ci	 *  channel == 0  -> Accept input from any remote channel
67262306a36Sopenharmony_ci	 *  channel == 1  -> Only accept input from remote channel 1
67362306a36Sopenharmony_ci	 *  channel == 2  -> Only accept input from remote channel 2
67462306a36Sopenharmony_ci	 *  ...
67562306a36Sopenharmony_ci	 *  channel == 16 -> Only accept input from remote channel 16
67662306a36Sopenharmony_ci	 */
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	channel = 0;
67962306a36Sopenharmony_ci	for (i = 0; i < 16; i++) {
68062306a36Sopenharmony_ci		if ((1 << i) & ch_mask) {
68162306a36Sopenharmony_ci			if (!(~(1 << i) & ch_mask))
68262306a36Sopenharmony_ci				channel = i + 1;
68362306a36Sopenharmony_ci			break;
68462306a36Sopenharmony_ci		}
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0),
68862306a36Sopenharmony_ci			    0x20,
68962306a36Sopenharmony_ci			    USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
69062306a36Sopenharmony_ci			    channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT);
69162306a36Sopenharmony_ci	if (r) {
69262306a36Sopenharmony_ci		dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n",
69362306a36Sopenharmony_ci			__func__, r);
69462306a36Sopenharmony_ci		return r;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	return 0;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic ssize_t ati_remote2_show_channel_mask(struct device *dev,
70162306a36Sopenharmony_ci					     struct device_attribute *attr,
70262306a36Sopenharmony_ci					     char *buf)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
70562306a36Sopenharmony_ci	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
70662306a36Sopenharmony_ci	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	return sprintf(buf, "0x%04x\n", ar2->channel_mask);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic ssize_t ati_remote2_store_channel_mask(struct device *dev,
71262306a36Sopenharmony_ci					      struct device_attribute *attr,
71362306a36Sopenharmony_ci					      const char *buf, size_t count)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
71662306a36Sopenharmony_ci	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
71762306a36Sopenharmony_ci	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
71862306a36Sopenharmony_ci	unsigned int mask;
71962306a36Sopenharmony_ci	int r;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	r = kstrtouint(buf, 0, &mask);
72262306a36Sopenharmony_ci	if (r)
72362306a36Sopenharmony_ci		return r;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (mask & ~ATI_REMOTE2_MAX_CHANNEL_MASK)
72662306a36Sopenharmony_ci		return -EINVAL;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	r = usb_autopm_get_interface(ar2->intf[0]);
72962306a36Sopenharmony_ci	if (r) {
73062306a36Sopenharmony_ci		dev_err(&ar2->intf[0]->dev,
73162306a36Sopenharmony_ci			"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
73262306a36Sopenharmony_ci		return r;
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	if (mask != ar2->channel_mask) {
73862306a36Sopenharmony_ci		r = ati_remote2_setup(ar2, mask);
73962306a36Sopenharmony_ci		if (!r)
74062306a36Sopenharmony_ci			ar2->channel_mask = mask;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	usb_autopm_put_interface(ar2->intf[0]);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return r ? r : count;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic ssize_t ati_remote2_show_mode_mask(struct device *dev,
75162306a36Sopenharmony_ci					  struct device_attribute *attr,
75262306a36Sopenharmony_ci					  char *buf)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
75562306a36Sopenharmony_ci	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
75662306a36Sopenharmony_ci	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	return sprintf(buf, "0x%02x\n", ar2->mode_mask);
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic ssize_t ati_remote2_store_mode_mask(struct device *dev,
76262306a36Sopenharmony_ci					   struct device_attribute *attr,
76362306a36Sopenharmony_ci					   const char *buf, size_t count)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
76662306a36Sopenharmony_ci	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
76762306a36Sopenharmony_ci	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
76862306a36Sopenharmony_ci	unsigned int mask;
76962306a36Sopenharmony_ci	int err;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	err = kstrtouint(buf, 0, &mask);
77262306a36Sopenharmony_ci	if (err)
77362306a36Sopenharmony_ci		return err;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (mask & ~ATI_REMOTE2_MAX_MODE_MASK)
77662306a36Sopenharmony_ci		return -EINVAL;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	ar2->mode_mask = mask;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	return count;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic DEVICE_ATTR(channel_mask, 0644, ati_remote2_show_channel_mask,
78462306a36Sopenharmony_ci		   ati_remote2_store_channel_mask);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic DEVICE_ATTR(mode_mask, 0644, ati_remote2_show_mode_mask,
78762306a36Sopenharmony_ci		   ati_remote2_store_mode_mask);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic struct attribute *ati_remote2_attrs[] = {
79062306a36Sopenharmony_ci	&dev_attr_channel_mask.attr,
79162306a36Sopenharmony_ci	&dev_attr_mode_mask.attr,
79262306a36Sopenharmony_ci	NULL,
79362306a36Sopenharmony_ci};
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic struct attribute_group ati_remote2_attr_group = {
79662306a36Sopenharmony_ci	.attrs = ati_remote2_attrs,
79762306a36Sopenharmony_ci};
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_cistatic int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(interface);
80262306a36Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
80362306a36Sopenharmony_ci	struct ati_remote2 *ar2;
80462306a36Sopenharmony_ci	int r;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
80762306a36Sopenharmony_ci		return -ENODEV;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL);
81062306a36Sopenharmony_ci	if (!ar2)
81162306a36Sopenharmony_ci		return -ENOMEM;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	ar2->udev = udev;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/* Sanity check, first interface must have an endpoint */
81662306a36Sopenharmony_ci	if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
81762306a36Sopenharmony_ci		dev_err(&interface->dev,
81862306a36Sopenharmony_ci			"%s(): interface 0 must have an endpoint\n", __func__);
81962306a36Sopenharmony_ci		r = -ENODEV;
82062306a36Sopenharmony_ci		goto fail1;
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci	ar2->intf[0] = interface;
82362306a36Sopenharmony_ci	ar2->ep[0] = &alt->endpoint[0].desc;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	/* Sanity check, the device must have two interfaces */
82662306a36Sopenharmony_ci	ar2->intf[1] = usb_ifnum_to_if(udev, 1);
82762306a36Sopenharmony_ci	if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) {
82862306a36Sopenharmony_ci		dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n",
82962306a36Sopenharmony_ci			__func__, udev->actconfig->desc.bNumInterfaces);
83062306a36Sopenharmony_ci		r = -ENODEV;
83162306a36Sopenharmony_ci		goto fail1;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
83562306a36Sopenharmony_ci	if (r)
83662306a36Sopenharmony_ci		goto fail1;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	/* Sanity check, second interface must have an endpoint */
83962306a36Sopenharmony_ci	alt = ar2->intf[1]->cur_altsetting;
84062306a36Sopenharmony_ci	if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
84162306a36Sopenharmony_ci		dev_err(&interface->dev,
84262306a36Sopenharmony_ci			"%s(): interface 1 must have an endpoint\n", __func__);
84362306a36Sopenharmony_ci		r = -ENODEV;
84462306a36Sopenharmony_ci		goto fail2;
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci	ar2->ep[1] = &alt->endpoint[0].desc;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	r = ati_remote2_urb_init(ar2);
84962306a36Sopenharmony_ci	if (r)
85062306a36Sopenharmony_ci		goto fail3;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	ar2->channel_mask = channel_mask;
85362306a36Sopenharmony_ci	ar2->mode_mask = mode_mask;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	r = ati_remote2_setup(ar2, ar2->channel_mask);
85662306a36Sopenharmony_ci	if (r)
85762306a36Sopenharmony_ci		goto fail3;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
86062306a36Sopenharmony_ci	strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);
86562306a36Sopenharmony_ci	if (r)
86662306a36Sopenharmony_ci		goto fail3;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	r = ati_remote2_input_init(ar2);
86962306a36Sopenharmony_ci	if (r)
87062306a36Sopenharmony_ci		goto fail4;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	usb_set_intfdata(interface, ar2);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	interface->needs_remote_wakeup = 1;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	return 0;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci fail4:
87962306a36Sopenharmony_ci	sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);
88062306a36Sopenharmony_ci fail3:
88162306a36Sopenharmony_ci	ati_remote2_urb_cleanup(ar2);
88262306a36Sopenharmony_ci fail2:
88362306a36Sopenharmony_ci	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
88462306a36Sopenharmony_ci fail1:
88562306a36Sopenharmony_ci	kfree(ar2);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	return r;
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistatic void ati_remote2_disconnect(struct usb_interface *interface)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	struct ati_remote2 *ar2;
89362306a36Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
89662306a36Sopenharmony_ci		return;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
89962306a36Sopenharmony_ci	usb_set_intfdata(interface, NULL);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	input_unregister_device(ar2->idev);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	sysfs_remove_group(&ar2->udev->dev.kobj, &ati_remote2_attr_group);
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	ati_remote2_urb_cleanup(ar2);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	kfree(ar2);
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cistatic int ati_remote2_suspend(struct usb_interface *interface,
91362306a36Sopenharmony_ci			       pm_message_t message)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	struct ati_remote2 *ar2;
91662306a36Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
91962306a36Sopenharmony_ci		return 0;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	if (ar2->flags & ATI_REMOTE2_OPENED)
92862306a36Sopenharmony_ci		ati_remote2_kill_urbs(ar2);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	ar2->flags |= ATI_REMOTE2_SUSPENDED;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	return 0;
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_cistatic int ati_remote2_resume(struct usb_interface *interface)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	struct ati_remote2 *ar2;
94062306a36Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
94162306a36Sopenharmony_ci	int r = 0;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
94462306a36Sopenharmony_ci		return 0;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	if (ar2->flags & ATI_REMOTE2_OPENED)
95362306a36Sopenharmony_ci		r = ati_remote2_submit_urbs(ar2);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!r)
95662306a36Sopenharmony_ci		ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	return r;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic int ati_remote2_reset_resume(struct usb_interface *interface)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct ati_remote2 *ar2;
96662306a36Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
96762306a36Sopenharmony_ci	int r = 0;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
97062306a36Sopenharmony_ci		return 0;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	r = ati_remote2_setup(ar2, ar2->channel_mask);
97962306a36Sopenharmony_ci	if (r)
98062306a36Sopenharmony_ci		goto out;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (ar2->flags & ATI_REMOTE2_OPENED)
98362306a36Sopenharmony_ci		r = ati_remote2_submit_urbs(ar2);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (!r)
98662306a36Sopenharmony_ci		ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci out:
98962306a36Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	return r;
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_cistatic int ati_remote2_pre_reset(struct usb_interface *interface)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	struct ati_remote2 *ar2;
99762306a36Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
100062306a36Sopenharmony_ci		return 0;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	mutex_lock(&ati_remote2_mutex);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (ar2->flags == ATI_REMOTE2_OPENED)
100962306a36Sopenharmony_ci		ati_remote2_kill_urbs(ar2);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	return 0;
101262306a36Sopenharmony_ci}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_cistatic int ati_remote2_post_reset(struct usb_interface *interface)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	struct ati_remote2 *ar2;
101762306a36Sopenharmony_ci	struct usb_host_interface *alt = interface->cur_altsetting;
101862306a36Sopenharmony_ci	int r = 0;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	if (alt->desc.bInterfaceNumber)
102162306a36Sopenharmony_ci		return 0;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	ar2 = usb_get_intfdata(interface);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (ar2->flags == ATI_REMOTE2_OPENED)
102862306a36Sopenharmony_ci		r = ati_remote2_submit_urbs(ar2);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	mutex_unlock(&ati_remote2_mutex);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	return r;
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cimodule_usb_driver(ati_remote2_driver);
1036