blob: bc2da64858c3feaf0d3d7e111e54bdc08d7e4e40 [file] [log] [blame]
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -05001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * USB ATI Remote support
3 *
Anssi Hannula9d454d42012-04-01 16:41:46 -03004 * Copyright (c) 2011, 2012 Anssi Hannula <anssi.hannula@iki.fi>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
6 * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
7 *
8 * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -05009 * porting to the 2.6 kernel interfaces, along with other modification
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * to better match the style of the existing usb/input drivers. However, the
11 * protocol and hardware handling is essentially unchanged from 2.1.1.
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050012 *
13 * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 * Vojtech Pavlik.
15 *
16 * Changes:
17 *
18 * Feb 2004: Torrey Hoffman <thoffman@arnor.net>
19 * Version 2.2.0
20 * Jun 2004: Torrey Hoffman <thoffman@arnor.net>
21 * Version 2.2.1
22 * Added key repeat support contributed by:
23 * Vincent Vanackere <vanackere@lif.univ-mrs.fr>
24 * Added support for the "Lola" remote contributed by:
25 * Seth Cohn <sethcohn@yahoo.com>
26 *
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050027 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050031 * the Free Software Foundation; either version 2 of the License, or
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 * (at your option) any later version.
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050033 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050038 *
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050039 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 *
41 * Hardware & software notes
42 *
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050043 * These remote controls are distributed by ATI as part of their
44 * "All-In-Wonder" video card packages. The receiver self-identifies as a
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
46 *
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050047 * The "Lola" remote is available from X10. See:
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 * http://www.x10.com/products/lola_sg1.htm
49 * The Lola is similar to the ATI remote but has no mouse support, and slightly
50 * different keys.
51 *
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050052 * It is possible to use multiple receivers and remotes on multiple computers
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 * simultaneously by configuring them to use specific channels.
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050054 *
55 * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
56 * Actually, it may even support more, at least in some revisions of the
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 * hardware.
58 *
59 * Each remote can be configured to transmit on one channel as follows:
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050060 * - Press and hold the "hand icon" button.
61 * - When the red LED starts to blink, let go of the "hand icon" button.
62 * - When it stops blinking, input the channel code as two digits, from 01
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 * to 16, and press the hand icon again.
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050064 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 * The timing can be a little tricky. Try loading the module with debug=1
66 * to have the kernel print out messages about the remote control number
67 * and mask. Note: debugging prints remote numbers as zero-based hexadecimal.
68 *
69 * The driver has a "channel_mask" parameter. This bitmask specifies which
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050070 * channels will be ignored by the module. To mask out channels, just add
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 * all the 2^channel_number values together.
72 *
73 * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050074 * ignore signals coming from remote controls transmitting on channel 4, but
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 * accept all other channels.
76 *
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050077 * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 * ignored.
79 *
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050080 * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 * parameter are unused.
82 *
83 */
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#include <linux/kernel.h>
86#include <linux/errno.h>
87#include <linux/init.h>
88#include <linux/slab.h>
89#include <linux/module.h>
Anssi Hannulac34516e2011-08-06 18:18:08 -030090#include <linux/mutex.h>
David Brownellae0dadc2006-06-13 10:04:34 -070091#include <linux/usb/input.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070092#include <linux/wait.h>
Marcelo Feitoza Parisif0b80fb2005-12-01 00:50:39 +030093#include <linux/jiffies.h>
Anssi Hannulac34516e2011-08-06 18:18:08 -030094#include <media/rc-core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96/*
97 * Module and Version Information, Module Parameters
98 */
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050099
Jarod Wilson51320882010-05-03 23:30:32 -0700100#define ATI_REMOTE_VENDOR_ID 0x0bc7
101#define LOLA_REMOTE_PRODUCT_ID 0x0002
102#define LOLA2_REMOTE_PRODUCT_ID 0x0003
103#define ATI_REMOTE_PRODUCT_ID 0x0004
104#define NVIDIA_REMOTE_PRODUCT_ID 0x0005
105#define MEDION_REMOTE_PRODUCT_ID 0x0006
Anssi Hannula999d6bc2011-08-06 18:18:12 -0300106#define FIREFLY_REMOTE_PRODUCT_ID 0x0008
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Anssi Hannula9688efd2011-08-06 18:18:07 -0300108#define DRIVER_VERSION "2.2.1"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#define DRIVER_AUTHOR "Torrey Hoffman <thoffman@arnor.net>"
110#define DRIVER_DESC "ATI/X10 RF USB Remote Control"
111
112#define NAME_BUFSIZE 80 /* size of product name, path buffers */
113#define DATA_BUFSIZE 63 /* size of URB data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Edwin Huffstutlerc6698692006-08-04 22:53:02 -0400115/*
116 * Duplicate event filtering time.
117 * Sequential, identical KIND_FILTERED inputs with less than
118 * FILTER_TIME milliseconds between them are considered as repeat
119 * events. The hardware generates 5 events for the first keypress
120 * and we have to take this into account for an accurate repeat
121 * behaviour.
122 */
123#define FILTER_TIME 60 /* msec */
Karl Pickett0de95502007-04-12 01:35:59 -0400124#define REPEAT_DELAY 500 /* msec */
Edwin Huffstutlerc6698692006-08-04 22:53:02 -0400125
Dmitry Torokhov65cde542005-05-29 02:29:38 -0500126static unsigned long channel_mask;
Dmitry Torokhovc605b672006-08-04 22:53:15 -0400127module_param(channel_mask, ulong, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
129
Dmitry Torokhov65cde542005-05-29 02:29:38 -0500130static int debug;
Dmitry Torokhovc605b672006-08-04 22:53:15 -0400131module_param(debug, int, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
133
Edwin Huffstutlerc6698692006-08-04 22:53:02 -0400134static int repeat_filter = FILTER_TIME;
135module_param(repeat_filter, int, 0644);
136MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
137
Karl Pickett0de95502007-04-12 01:35:59 -0400138static int repeat_delay = REPEAT_DELAY;
139module_param(repeat_delay, int, 0644);
140MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec");
141
Anssi Hannulac34516e2011-08-06 18:18:08 -0300142static bool mouse = true;
143module_param(mouse, bool, 0444);
144MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes");
145
Du, Changbina342daea2012-07-07 03:53:28 -0300146#define dbginfo(dev, format, arg...) \
147 do { if (debug) dev_info(dev , format , ## arg); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148#undef err
149#define err(format, arg...) printk(KERN_ERR format , ## arg)
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500150
Anssi Hannula0d746792012-04-01 16:41:45 -0300151struct ati_receiver_type {
152 /* either default_keymap or get_default_keymap should be set */
153 const char *default_keymap;
154 const char *(*get_default_keymap)(struct usb_interface *interface);
155};
156
Anssi Hannula9d454d42012-04-01 16:41:46 -0300157static const char *get_medion_keymap(struct usb_interface *interface)
158{
159 struct usb_device *udev = interface_to_usbdev(interface);
160
Anssi Hannula5085c992012-05-14 09:52:37 -0300161 /*
162 * There are many different Medion remotes shipped with a receiver
163 * with the same usb id, but the receivers have subtle differences
164 * in the USB descriptors allowing us to detect them.
165 */
166
167 if (udev->manufacturer && udev->product) {
168 if (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP) {
169
170 if (!strcmp(udev->manufacturer, "X10 Wireless Technology Inc")
171 && !strcmp(udev->product, "USB Receiver"))
172 return RC_MAP_MEDION_X10_DIGITAINER;
173
174 if (!strcmp(udev->manufacturer, "X10 WTI")
175 && !strcmp(udev->product, "RF receiver"))
176 return RC_MAP_MEDION_X10_OR2X;
177 } else {
178
179 if (!strcmp(udev->manufacturer, "X10 Wireless Technology Inc")
180 && !strcmp(udev->product, "USB Receiver"))
181 return RC_MAP_MEDION_X10;
182 }
183 }
184
185 dev_info(&interface->dev,
186 "Unknown Medion X10 receiver, using default ati_remote Medion keymap\n");
Anssi Hannula9d454d42012-04-01 16:41:46 -0300187
188 return RC_MAP_MEDION_X10;
189}
190
Du, Changbina342daea2012-07-07 03:53:28 -0300191static const struct ati_receiver_type type_ati = {
192 .default_keymap = RC_MAP_ATI_X10
193};
194static const struct ati_receiver_type type_medion = {
195 .get_default_keymap = get_medion_keymap
196};
197static const struct ati_receiver_type type_firefly = {
198 .default_keymap = RC_MAP_SNAPSTREAM_FIREFLY
199};
Anssi Hannula0d746792012-04-01 16:41:45 -0300200
Arvind Yadav5fad16b2017-08-13 05:54:44 -0300201static const struct usb_device_id ati_remote_table[] = {
Du, Changbina342daea2012-07-07 03:53:28 -0300202 {
203 USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID),
204 .driver_info = (unsigned long)&type_ati
205 },
206 {
207 USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID),
208 .driver_info = (unsigned long)&type_ati
209 },
210 {
211 USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID),
212 .driver_info = (unsigned long)&type_ati
213 },
214 {
215 USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID),
216 .driver_info = (unsigned long)&type_ati
217 },
218 {
219 USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID),
220 .driver_info = (unsigned long)&type_medion
221 },
222 {
223 USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID),
224 .driver_info = (unsigned long)&type_firefly
225 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 {} /* Terminating entry */
227};
228
229MODULE_DEVICE_TABLE(usb, ati_remote_table);
230
231/* Get hi and low bytes of a 16-bits int */
232#define HI(a) ((unsigned char)((a) >> 8))
233#define LO(a) ((unsigned char)((a) & 0xff))
234
235#define SEND_FLAG_IN_PROGRESS 1
236#define SEND_FLAG_COMPLETE 2
237
238/* Device initialization strings */
239static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
240static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
241
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242struct ati_remote {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500243 struct input_dev *idev;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300244 struct rc_dev *rdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 struct usb_device *udev;
246 struct usb_interface *interface;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 struct urb *irq_urb;
249 struct urb *out_urb;
250 struct usb_endpoint_descriptor *endpoint_in;
251 struct usb_endpoint_descriptor *endpoint_out;
252 unsigned char *inbuf;
253 unsigned char *outbuf;
254 dma_addr_t inbuf_dma;
255 dma_addr_t outbuf_dma;
256
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300257 unsigned char old_data; /* Detect duplicate events */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 unsigned long old_jiffies;
259 unsigned long acc_jiffies; /* handle acceleration */
Karl Pickett0de95502007-04-12 01:35:59 -0400260 unsigned long first_jiffies;
261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 unsigned int repeat_count;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500263
Anssi Hannulac34516e2011-08-06 18:18:08 -0300264 char rc_name[NAME_BUFSIZE];
265 char rc_phys[NAME_BUFSIZE];
266 char mouse_name[NAME_BUFSIZE];
267 char mouse_phys[NAME_BUFSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
269 wait_queue_head_t wait;
270 int send_flags;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300271
272 int users; /* 0-2, users are rc and input */
273 struct mutex open_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274};
275
276/* "Kinds" of messages sent from the hardware to the driver. */
277#define KIND_END 0
George Spelvin3f245b92014-05-11 08:14:54 -0300278#define KIND_LITERAL 1 /* Simply pass to input system as EV_KEY */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279#define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */
George Spelvin3f245b92014-05-11 08:14:54 -0300280#define KIND_ACCEL 3 /* Translate to EV_REL mouse-move events */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282/* Translation table from hardware messages to input events. */
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100283static const struct {
George Spelvin528abb92014-05-11 08:12:55 -0300284 unsigned char kind;
George Spelvin3f245b92014-05-11 08:14:54 -0300285 unsigned char data; /* Raw key code from remote */
286 unsigned short code; /* Input layer translation */
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500287} ati_remote_tbl[] = {
George Spelvin8ecd5e32014-05-11 08:14:18 -0300288 /* Directional control pad axes. Code is xxyy */
George Spelvin3f245b92014-05-11 08:14:54 -0300289 {KIND_ACCEL, 0x70, 0xff00}, /* left */
290 {KIND_ACCEL, 0x71, 0x0100}, /* right */
291 {KIND_ACCEL, 0x72, 0x00ff}, /* up */
292 {KIND_ACCEL, 0x73, 0x0001}, /* down */
George Spelvin8ecd5e32014-05-11 08:14:18 -0300293
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500294 /* Directional control pad diagonals */
George Spelvin3f245b92014-05-11 08:14:54 -0300295 {KIND_ACCEL, 0x74, 0xffff}, /* left up */
296 {KIND_ACCEL, 0x75, 0x01ff}, /* right up */
297 {KIND_ACCEL, 0x77, 0xff01}, /* left down */
298 {KIND_ACCEL, 0x76, 0x0101}, /* right down */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
George Spelvin3f245b92014-05-11 08:14:54 -0300300 /* "Mouse button" buttons. The code below uses the fact that the
301 * lsbit of the raw code is a down/up indicator. */
302 {KIND_LITERAL, 0x78, BTN_LEFT}, /* left btn down */
303 {KIND_LITERAL, 0x79, BTN_LEFT}, /* left btn up */
304 {KIND_LITERAL, 0x7c, BTN_RIGHT},/* right btn down */
305 {KIND_LITERAL, 0x7d, BTN_RIGHT},/* right btn up */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Mauro Carvalho Chehab04ad3012019-02-18 14:29:01 -0500307 /* Artificial "double-click" events are generated by the hardware.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 * They are mapped to the "side" and "extra" mouse buttons here. */
George Spelvin3f245b92014-05-11 08:14:54 -0300309 {KIND_FILTERED, 0x7a, BTN_SIDE}, /* left dblclick */
310 {KIND_FILTERED, 0x7e, BTN_EXTRA},/* right dblclick */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Anssi Hannulac34516e2011-08-06 18:18:08 -0300312 /* Non-mouse events are handled by rc-core */
George Spelvin3f245b92014-05-11 08:14:54 -0300313 {KIND_END, 0x00, 0}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314};
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316/*
Du, Changbina342daea2012-07-07 03:53:28 -0300317 * ati_remote_dump_input
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 */
Greg Kroah-Hartman1817b162008-08-14 09:37:34 -0700319static void ati_remote_dump(struct device *dev, unsigned char *data,
320 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Anssi Hannula0224e042011-08-06 18:18:10 -0300322 if (len == 1) {
323 if (data[0] != (unsigned char)0xff && data[0] != 0x00)
324 dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
325 } else if (len == 4)
Andy Shevchenko7c94c692012-08-07 12:43:09 -0300326 dev_warn(dev, "Weird key %*ph\n", 4, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 else
Andy Shevchenko7c94c692012-08-07 12:43:09 -0300328 dev_warn(dev, "Weird data, len=%d %*ph ...\n", len, 6, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
331/*
Du, Changbina342daea2012-07-07 03:53:28 -0300332 * ati_remote_open
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 */
Anssi Hannulac34516e2011-08-06 18:18:08 -0300334static int ati_remote_open(struct ati_remote *ati_remote)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Anssi Hannulac34516e2011-08-06 18:18:08 -0300336 int err = 0;
337
338 mutex_lock(&ati_remote->open_mutex);
339
340 if (ati_remote->users++ != 0)
341 goto out; /* one was already active */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 /* On first open, submit the read urb which was set up previously. */
344 ati_remote->irq_urb->dev = ati_remote->udev;
345 if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500346 dev_err(&ati_remote->interface->dev,
Harvey Harrisonea3e6c52008-05-05 11:36:18 -0400347 "%s: usb_submit_urb failed!\n", __func__);
Anssi Hannulac34516e2011-08-06 18:18:08 -0300348 err = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 }
350
Anssi Hannulac34516e2011-08-06 18:18:08 -0300351out: mutex_unlock(&ati_remote->open_mutex);
352 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353}
354
355/*
Du, Changbina342daea2012-07-07 03:53:28 -0300356 * ati_remote_close
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 */
Anssi Hannulac34516e2011-08-06 18:18:08 -0300358static void ati_remote_close(struct ati_remote *ati_remote)
359{
360 mutex_lock(&ati_remote->open_mutex);
361 if (--ati_remote->users == 0)
362 usb_kill_urb(ati_remote->irq_urb);
363 mutex_unlock(&ati_remote->open_mutex);
364}
365
366static int ati_remote_input_open(struct input_dev *inputdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
Dmitry Torokhov7791bda2007-04-12 01:34:39 -0400368 struct ati_remote *ati_remote = input_get_drvdata(inputdev);
Anssi Hannulac34516e2011-08-06 18:18:08 -0300369 return ati_remote_open(ati_remote);
370}
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500371
Anssi Hannulac34516e2011-08-06 18:18:08 -0300372static void ati_remote_input_close(struct input_dev *inputdev)
373{
374 struct ati_remote *ati_remote = input_get_drvdata(inputdev);
375 ati_remote_close(ati_remote);
376}
377
378static int ati_remote_rc_open(struct rc_dev *rdev)
379{
380 struct ati_remote *ati_remote = rdev->priv;
381 return ati_remote_open(ati_remote);
382}
383
384static void ati_remote_rc_close(struct rc_dev *rdev)
385{
386 struct ati_remote *ati_remote = rdev->priv;
387 ati_remote_close(ati_remote);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
390/*
Du, Changbina342daea2012-07-07 03:53:28 -0300391 * ati_remote_irq_out
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 */
David Howells7d12e782006-10-05 14:55:46 +0100393static void ati_remote_irq_out(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
395 struct ati_remote *ati_remote = urb->context;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (urb->status) {
398 dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
Harvey Harrisonea3e6c52008-05-05 11:36:18 -0400399 __func__, urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 return;
401 }
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 ati_remote->send_flags |= SEND_FLAG_COMPLETE;
404 wmb();
405 wake_up(&ati_remote->wait);
406}
407
408/*
Du, Changbina342daea2012-07-07 03:53:28 -0300409 * ati_remote_sendpacket
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500410 *
Du, Changbina342daea2012-07-07 03:53:28 -0300411 * Used to send device initialization strings
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 */
Du, Changbina342daea2012-07-07 03:53:28 -0300413static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd,
414 unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 int retval = 0;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 /* Set up out_urb */
419 memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500420 ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
422 ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
423 ati_remote->out_urb->dev = ati_remote->udev;
424 ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
425
426 retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
427 if (retval) {
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500428 dev_dbg(&ati_remote->interface->dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 "sendpacket: usb_submit_urb failed: %d\n", retval);
430 return retval;
431 }
432
433 wait_event_timeout(ati_remote->wait,
434 ((ati_remote->out_urb->status != -EINPROGRESS) ||
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500435 (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 HZ);
437 usb_kill_urb(ati_remote->out_urb);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 return retval;
440}
441
Mauro Carvalho Chehabfe28f5d2016-02-27 07:51:12 -0300442struct accel_times {
443 const char value;
444 unsigned int msecs;
445};
446
447static const struct accel_times accel[] = {
448 { 1, 125 },
449 { 2, 250 },
450 { 4, 500 },
451 { 6, 1000 },
452 { 9, 1500 },
453 { 13, 2000 },
454 { 20, 0 },
455};
456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457/*
Du, Changbina342daea2012-07-07 03:53:28 -0300458 * ati_remote_compute_accel
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400459 *
460 * Implements acceleration curve for directional control pad
461 * If elapsed time since last event is > 1/4 second, user "stopped",
462 * so reset acceleration. Otherwise, user is probably holding the control
463 * pad down, so we increase acceleration, ramping up over two seconds to
464 * a maximum speed.
465 */
466static int ati_remote_compute_accel(struct ati_remote *ati_remote)
467{
Mauro Carvalho Chehabfe28f5d2016-02-27 07:51:12 -0300468 unsigned long now = jiffies, reset_time;
469 int i;
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400470
Mauro Carvalho Chehabfe28f5d2016-02-27 07:51:12 -0300471 reset_time = msecs_to_jiffies(250);
472
473 if (time_after(now, ati_remote->old_jiffies + reset_time)) {
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400474 ati_remote->acc_jiffies = now;
Mauro Carvalho Chehabfe28f5d2016-02-27 07:51:12 -0300475 return 1;
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400476 }
Mauro Carvalho Chehabfe28f5d2016-02-27 07:51:12 -0300477 for (i = 0; i < ARRAY_SIZE(accel) - 1; i++) {
478 unsigned long timeout = msecs_to_jiffies(accel[i].msecs);
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400479
Mauro Carvalho Chehabfe28f5d2016-02-27 07:51:12 -0300480 if (time_before(now, ati_remote->acc_jiffies + timeout))
481 return accel[i].value;
482 }
483 return accel[i].value;
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400484}
485
486/*
Du, Changbina342daea2012-07-07 03:53:28 -0300487 * ati_remote_report_input
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 */
David Howells7d12e782006-10-05 14:55:46 +0100489static void ati_remote_input_report(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
491 struct ati_remote *ati_remote = urb->context;
492 unsigned char *data= ati_remote->inbuf;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500493 struct input_dev *dev = ati_remote->idev;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300494 int index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 int remote_num;
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300496 unsigned char scancode;
Anssi Hannula9d454d42012-04-01 16:41:46 -0300497 u32 wheel_keycode = KEY_RESERVED;
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300498 int i;
499
500 /*
501 * data[0] = 0x14
502 * data[1] = data[2] + data[3] + 0xd5 (a checksum byte)
503 * data[2] = the key code (with toggle bit in MSB with some models)
504 * data[3] = channel << 4 (the low 4 bits must be zero)
505 */
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 /* Deal with strange looking inputs */
George Spelvin20d7e3c2014-05-11 08:12:09 -0300508 if ( urb->actual_length != 4 || data[0] != 0x14 ||
509 data[1] != (unsigned char)(data[2] + data[3] + 0xD5) ||
510 (data[3] & 0x0f) != 0x00) {
Greg Kroah-Hartman1817b162008-08-14 09:37:34 -0700511 ati_remote_dump(&urb->dev->dev, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return;
513 }
514
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300515 if (data[1] != ((data[2] + data[3] + 0xd5) & 0xff)) {
516 dbginfo(&ati_remote->interface->dev,
Andy Shevchenko7c94c692012-08-07 12:43:09 -0300517 "wrong checksum in input: %*ph\n", 4, data);
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300518 return;
519 }
520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 /* Mask unwanted remote channels. */
522 /* note: remote_num is 0-based, channel 1 on remote == 0 here */
523 remote_num = (data[3] >> 4) & 0x0f;
Anssi Hannula9688efd2011-08-06 18:18:07 -0300524 if (channel_mask & (1 << (remote_num + 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 dbginfo(&ati_remote->interface->dev,
Mauro Carvalho Chehab25ec5872016-10-18 17:44:25 -0200526 "Masked input from channel 0x%02x: data %02x, mask= 0x%02lx\n",
George Spelvin20d7e3c2014-05-11 08:12:09 -0300527 remote_num, data[2], channel_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 return;
529 }
530
Anssi Hannula999d6bc2011-08-06 18:18:12 -0300531 /*
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300532 * MSB is a toggle code, though only used by some devices
533 * (e.g. SnapStream Firefly)
Anssi Hannula999d6bc2011-08-06 18:18:12 -0300534 */
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300535 scancode = data[2] & 0x7f;
Anssi Hannula999d6bc2011-08-06 18:18:12 -0300536
Anssi Hannula9d454d42012-04-01 16:41:46 -0300537 dbginfo(&ati_remote->interface->dev,
538 "channel 0x%02x; key data %02x, scancode %02x\n",
539 remote_num, data[2], scancode);
540
541 if (scancode >= 0x70) {
542 /*
543 * This is either a mouse or scrollwheel event, depending on
544 * the remote/keymap.
545 * Get the keycode assigned to scancode 0x78/0x70. If it is
546 * set, assume this is a scrollwheel up/down event.
547 */
548 wheel_keycode = rc_g_keycode_from_table(ati_remote->rdev,
549 scancode & 0x78);
550
551 if (wheel_keycode == KEY_RESERVED) {
552 /* scrollwheel was not mapped, assume mouse */
553
Du, Changbina342daea2012-07-07 03:53:28 -0300554 /* Look up event code index in the mouse translation
555 * table.
556 */
Anssi Hannula9d454d42012-04-01 16:41:46 -0300557 for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
558 if (scancode == ati_remote_tbl[i].data) {
559 index = i;
560 break;
561 }
562 }
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300563 }
564 }
Anssi Hannulac34516e2011-08-06 18:18:08 -0300565
Anssi Hannulac34516e2011-08-06 18:18:08 -0300566 if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) {
George Spelvin3f245b92014-05-11 08:14:54 -0300567 /*
568 * The lsbit of the raw key code is a down/up flag.
569 * Invert it to match the input layer's conventions.
570 */
571 input_event(dev, EV_KEY, ati_remote_tbl[index].code,
572 !(data[2] & 1));
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 ati_remote->old_jiffies = jiffies;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500575
George Spelvin8ecd5e32014-05-11 08:14:18 -0300576 } else if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) {
Karl Pickett0de95502007-04-12 01:35:59 -0400577 unsigned long now = jiffies;
578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 /* Filter duplicate events which happen "too close" together. */
Anssi Hannula5eefb4f2011-12-06 22:34:29 -0300580 if (ati_remote->old_data == data[2] &&
Karl Pickett0de95502007-04-12 01:35:59 -0400581 time_before(now, ati_remote->old_jiffies +
582 msecs_to_jiffies(repeat_filter))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 ati_remote->repeat_count++;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500584 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 ati_remote->repeat_count = 0;
Karl Pickett0de95502007-04-12 01:35:59 -0400586 ati_remote->first_jiffies = now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 }
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500588
Karl Pickett0de95502007-04-12 01:35:59 -0400589 ati_remote->old_jiffies = now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
George Spelvin3f245b92014-05-11 08:14:54 -0300591 /* Ensure we skip at least the 4 first duplicate events
592 * (generated by a single keypress), and continue skipping
593 * until repeat_delay msecs have passed.
Karl Pickett0de95502007-04-12 01:35:59 -0400594 */
Edwin Huffstutlerc6698692006-08-04 22:53:02 -0400595 if (ati_remote->repeat_count > 0 &&
Karl Pickett0de95502007-04-12 01:35:59 -0400596 (ati_remote->repeat_count < 5 ||
597 time_before(now, ati_remote->first_jiffies +
598 msecs_to_jiffies(repeat_delay))))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 return;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500600
George Spelvin89b0c0d2014-05-11 08:15:44 -0300601 if (index >= 0) {
602 input_event(dev, EV_KEY, ati_remote_tbl[index].code, 1);
603 input_event(dev, EV_KEY, ati_remote_tbl[index].code, 0);
604 } else {
Anssi Hannulac34516e2011-08-06 18:18:08 -0300605 /* Not a mouse event, hand it to rc-core. */
Anssi Hannula9d454d42012-04-01 16:41:46 -0300606 int count = 1;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300607
Anssi Hannula9d454d42012-04-01 16:41:46 -0300608 if (wheel_keycode != KEY_RESERVED) {
609 /*
610 * This is a scrollwheel event, send the
611 * scroll up (0x78) / down (0x70) scancode
612 * repeatedly as many times as indicated by
613 * rest of the scancode.
614 */
615 count = (scancode & 0x07) + 1;
616 scancode &= 0x78;
617 }
618
619 while (count--) {
620 /*
621 * We don't use the rc-core repeat handling yet as
622 * it would cause ghost repeats which would be a
623 * regression for this driver.
624 */
Sean Young6d741bf2017-08-07 16:20:58 -0400625 rc_keydown_notimeout(ati_remote->rdev,
626 RC_PROTO_OTHER,
David Härdeman120703f2014-04-03 20:31:30 -0300627 scancode, data[2]);
Anssi Hannula9d454d42012-04-01 16:41:46 -0300628 rc_keyup(ati_remote->rdev);
629 }
George Spelvin89b0c0d2014-05-11 08:15:44 -0300630 goto nosync;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
George Spelvin8ecd5e32014-05-11 08:14:18 -0300633 } else if (ati_remote_tbl[index].kind == KIND_ACCEL) {
634 signed char dx = ati_remote_tbl[index].code >> 8;
635 signed char dy = ati_remote_tbl[index].code & 255;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500636
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400637 /*
Du, Changbina342daea2012-07-07 03:53:28 -0300638 * Other event kinds are from the directional control pad, and
639 * have an acceleration factor applied to them. Without this
640 * acceleration, the control pad is mostly unusable.
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400641 */
George Spelvin8ecd5e32014-05-11 08:14:18 -0300642 int acc = ati_remote_compute_accel(ati_remote);
643 if (dx)
644 input_report_rel(dev, REL_X, dx * acc);
645 if (dy)
646 input_report_rel(dev, REL_Y, dy * acc);
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400647 ati_remote->old_jiffies = jiffies;
George Spelvin89b0c0d2014-05-11 08:15:44 -0300648
George Spelvin8ecd5e32014-05-11 08:14:18 -0300649 } else {
650 dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
651 ati_remote_tbl[index].kind);
George Spelvin89b0c0d2014-05-11 08:15:44 -0300652 return;
Dmitry Torokhov2ffc1cc2006-08-04 22:53:37 -0400653 }
George Spelvin89b0c0d2014-05-11 08:15:44 -0300654 input_sync(dev);
655nosync:
656 ati_remote->old_data = data[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657}
658
659/*
Du, Changbina342daea2012-07-07 03:53:28 -0300660 * ati_remote_irq_in
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 */
David Howells7d12e782006-10-05 14:55:46 +0100662static void ati_remote_irq_in(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
664 struct ati_remote *ati_remote = urb->context;
665 int retval;
666
667 switch (urb->status) {
668 case 0: /* success */
David Howells7d12e782006-10-05 14:55:46 +0100669 ati_remote_input_report(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 break;
671 case -ECONNRESET: /* unlink */
672 case -ENOENT:
673 case -ESHUTDOWN:
Du, Changbina342daea2012-07-07 03:53:28 -0300674 dev_dbg(&ati_remote->interface->dev,
675 "%s: urb error status, unlink?\n",
Harvey Harrisonea3e6c52008-05-05 11:36:18 -0400676 __func__);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500677 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 default: /* error */
Du, Changbina342daea2012-07-07 03:53:28 -0300679 dev_dbg(&ati_remote->interface->dev,
680 "%s: Nonzero urb status %d\n",
Harvey Harrisonea3e6c52008-05-05 11:36:18 -0400681 __func__, urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500683
Christoph Lameter54e6ecb2006-12-06 20:33:16 -0800684 retval = usb_submit_urb(urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (retval)
Du, Changbina342daea2012-07-07 03:53:28 -0300686 dev_err(&ati_remote->interface->dev,
687 "%s: usb_submit_urb()=%d\n",
Harvey Harrisonea3e6c52008-05-05 11:36:18 -0400688 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
691/*
Du, Changbina342daea2012-07-07 03:53:28 -0300692 * ati_remote_alloc_buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 */
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500694static int ati_remote_alloc_buffers(struct usb_device *udev,
695 struct ati_remote *ati_remote)
696{
Daniel Mack997ea582010-04-12 13:17:25 +0200697 ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
698 &ati_remote->inbuf_dma);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500699 if (!ati_remote->inbuf)
700 return -1;
701
Daniel Mack997ea582010-04-12 13:17:25 +0200702 ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
Anssi Hannula9688efd2011-08-06 18:18:07 -0300703 &ati_remote->outbuf_dma);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500704 if (!ati_remote->outbuf)
705 return -1;
706
707 ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
708 if (!ati_remote->irq_urb)
709 return -1;
710
711 ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
712 if (!ati_remote->out_urb)
713 return -1;
714
715 return 0;
716}
717
718/*
Du, Changbina342daea2012-07-07 03:53:28 -0300719 * ati_remote_free_buffers
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500720 */
721static void ati_remote_free_buffers(struct ati_remote *ati_remote)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Mariusz Kozlowski459f8362006-11-08 15:35:46 +0100723 usb_free_urb(ati_remote->irq_urb);
724 usb_free_urb(ati_remote->out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Daniel Mack997ea582010-04-12 13:17:25 +0200726 usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
Mariusz Kozlowski9dce4472006-11-25 11:09:38 -0800727 ati_remote->inbuf, ati_remote->inbuf_dma);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500728
Daniel Mack997ea582010-04-12 13:17:25 +0200729 usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
Mariusz Kozlowski9dce4472006-11-25 11:09:38 -0800730 ati_remote->outbuf, ati_remote->outbuf_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
733static void ati_remote_input_init(struct ati_remote *ati_remote)
734{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500735 struct input_dev *idev = ati_remote->idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 int i;
737
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700738 idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
739 idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
740 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
741 idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
George Spelvin3f245b92014-05-11 08:14:54 -0300743 if (ati_remote_tbl[i].kind == KIND_LITERAL ||
744 ati_remote_tbl[i].kind == KIND_FILTERED)
George Spelvin1e182702014-05-11 08:16:15 -0300745 __set_bit(ati_remote_tbl[i].code, idev->keybit);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500746
Dmitry Torokhov7791bda2007-04-12 01:34:39 -0400747 input_set_drvdata(idev, ati_remote);
748
Anssi Hannulac34516e2011-08-06 18:18:08 -0300749 idev->open = ati_remote_input_open;
750 idev->close = ati_remote_input_close;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500751
Anssi Hannulac34516e2011-08-06 18:18:08 -0300752 idev->name = ati_remote->mouse_name;
753 idev->phys = ati_remote->mouse_phys;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500754
Dmitry Torokhov16a334c2005-06-30 00:49:08 -0500755 usb_to_input_id(ati_remote->udev, &idev->id);
Anssi Hannula44fd0b62011-08-06 18:18:09 -0300756 idev->dev.parent = &ati_remote->interface->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
Anssi Hannulac34516e2011-08-06 18:18:08 -0300759static void ati_remote_rc_init(struct ati_remote *ati_remote)
760{
761 struct rc_dev *rdev = ati_remote->rdev;
762
763 rdev->priv = ati_remote;
Sean Young6d741bf2017-08-07 16:20:58 -0400764 rdev->allowed_protocols = RC_PROTO_BIT_OTHER;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300765 rdev->driver_name = "ati_remote";
766
767 rdev->open = ati_remote_rc_open;
768 rdev->close = ati_remote_rc_close;
769
Sean Young518f4b22017-07-01 12:13:19 -0400770 rdev->device_name = ati_remote->rc_name;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300771 rdev->input_phys = ati_remote->rc_phys;
772
773 usb_to_input_id(ati_remote->udev, &rdev->input_id);
Anssi Hannula44fd0b62011-08-06 18:18:09 -0300774 rdev->dev.parent = &ati_remote->interface->dev;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300775}
776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777static int ati_remote_initialize(struct ati_remote *ati_remote)
778{
779 struct usb_device *udev = ati_remote->udev;
780 int pipe, maxp;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 init_waitqueue_head(&ati_remote->wait);
783
784 /* Set up irq_urb */
785 pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
786 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
787 maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500788
789 usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
790 maxp, ati_remote_irq_in, ati_remote,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 ati_remote->endpoint_in->bInterval);
792 ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
793 ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 /* Set up out_urb */
796 pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
797 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
798 maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
799
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500800 usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
801 maxp, ati_remote_irq_out, ati_remote,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 ati_remote->endpoint_out->bInterval);
803 ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
804 ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
805
806 /* send initialization strings */
807 if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
808 (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500809 dev_err(&ati_remote->interface->dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 "Initializing ati_remote hardware failed.\n");
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500811 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 }
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 return 0;
815}
816
817/*
Du, Changbina342daea2012-07-07 03:53:28 -0300818 * ati_remote_probe
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 */
Du, Changbina342daea2012-07-07 03:53:28 -0300820static int ati_remote_probe(struct usb_interface *interface,
821 const struct usb_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
823 struct usb_device *udev = interface_to_usbdev(interface);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500824 struct usb_host_interface *iface_host = interface->cur_altsetting;
825 struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
Anssi Hannula0d746792012-04-01 16:41:45 -0300826 struct ati_receiver_type *type = (struct ati_receiver_type *)id->driver_info;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500827 struct ati_remote *ati_remote;
828 struct input_dev *input_dev;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300829 struct rc_dev *rc_dev;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500830 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if (iface_host->desc.bNumEndpoints != 2) {
Harvey Harrisonea3e6c52008-05-05 11:36:18 -0400833 err("%s: Unexpected desc.bNumEndpoints\n", __func__);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500834 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 }
836
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500837 endpoint_in = &iface_host->endpoint[0].desc;
838 endpoint_out = &iface_host->endpoint[1].desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Luiz Fernando N. Capitulino96642a22006-09-27 11:58:53 -0700840 if (!usb_endpoint_is_int_in(endpoint_in)) {
Harvey Harrisonea3e6c52008-05-05 11:36:18 -0400841 err("%s: Unexpected endpoint_in\n", __func__);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500842 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 }
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500844 if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
Harvey Harrisonea3e6c52008-05-05 11:36:18 -0400845 err("%s: endpoint_in message size==0? \n", __func__);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500846 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500849 ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
Andi Shyti0f7499f2016-12-16 06:50:58 -0200850 rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
Anssi Hannulac34516e2011-08-06 18:18:08 -0300851 if (!ati_remote || !rc_dev)
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300852 goto exit_free_dev_rdev;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 /* Allocate URB buffers, URBs */
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500855 if (ati_remote_alloc_buffers(udev, ati_remote))
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300856 goto exit_free_buffers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500858 ati_remote->endpoint_in = endpoint_in;
859 ati_remote->endpoint_out = endpoint_out;
860 ati_remote->udev = udev;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300861 ati_remote->rdev = rc_dev;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500862 ati_remote->interface = interface;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
Anssi Hannulac34516e2011-08-06 18:18:08 -0300864 usb_make_path(udev, ati_remote->rc_phys, sizeof(ati_remote->rc_phys));
Mauro Carvalho Chehabc0decac2018-09-10 08:19:14 -0400865 strscpy(ati_remote->mouse_phys, ati_remote->rc_phys,
Anssi Hannulac34516e2011-08-06 18:18:08 -0300866 sizeof(ati_remote->mouse_phys));
867
868 strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys));
869 strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Rasmus Villemoes869f0762016-03-08 17:40:53 -0300871 snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), "%s%s%s",
872 udev->manufacturer ?: "",
873 udev->manufacturer && udev->product ? " " : "",
874 udev->product ?: "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Anssi Hannulac34516e2011-08-06 18:18:08 -0300876 if (!strlen(ati_remote->rc_name))
877 snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name),
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500878 DRIVER_DESC "(%04x,%04x)",
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500879 le16_to_cpu(ati_remote->udev->descriptor.idVendor),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 le16_to_cpu(ati_remote->udev->descriptor.idProduct));
881
Anssi Hannulac34516e2011-08-06 18:18:08 -0300882 snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name),
883 "%s mouse", ati_remote->rc_name);
884
Anssi Hannula0d746792012-04-01 16:41:45 -0300885 rc_dev->map_name = RC_MAP_ATI_X10; /* default map */
886
887 /* set default keymap according to receiver model */
888 if (type) {
889 if (type->default_keymap)
890 rc_dev->map_name = type->default_keymap;
891 else if (type->get_default_keymap)
892 rc_dev->map_name = type->get_default_keymap(interface);
893 }
Anssi Hannula175fcec2011-08-06 18:18:11 -0300894
Anssi Hannulac34516e2011-08-06 18:18:08 -0300895 ati_remote_rc_init(ati_remote);
896 mutex_init(&ati_remote->open_mutex);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500897
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 /* Device Hardware Initialization - fills in ati_remote->idev from udev. */
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500899 err = ati_remote_initialize(ati_remote);
900 if (err)
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300901 goto exit_kill_urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Anssi Hannulac34516e2011-08-06 18:18:08 -0300903 /* Set up and register rc device */
904 err = rc_register_device(ati_remote->rdev);
Dmitry Torokhov50141862007-04-12 01:33:39 -0400905 if (err)
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300906 goto exit_kill_urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Anssi Hannulac34516e2011-08-06 18:18:08 -0300908 /* Set up and register mouse input device */
909 if (mouse) {
910 input_dev = input_allocate_device();
Peter Senna Tschudina84b17e2012-09-04 08:05:04 -0300911 if (!input_dev) {
912 err = -ENOMEM;
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300913 goto exit_unregister_device;
Peter Senna Tschudina84b17e2012-09-04 08:05:04 -0300914 }
Anssi Hannulac34516e2011-08-06 18:18:08 -0300915
916 ati_remote->idev = input_dev;
917 ati_remote_input_init(ati_remote);
918 err = input_register_device(input_dev);
919
920 if (err)
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300921 goto exit_free_input_device;
Anssi Hannulac34516e2011-08-06 18:18:08 -0300922 }
923
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 usb_set_intfdata(interface, ati_remote);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500925 return 0;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500926
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300927 exit_free_input_device:
928 input_free_device(input_dev);
929 exit_unregister_device:
930 rc_unregister_device(rc_dev);
Anssi Hannulac34516e2011-08-06 18:18:08 -0300931 rc_dev = NULL;
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300932 exit_kill_urbs:
933 usb_kill_urb(ati_remote->irq_urb);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500934 usb_kill_urb(ati_remote->out_urb);
Matthijs Kooijman70ef6992012-11-02 09:13:54 -0300935 exit_free_buffers:
936 ati_remote_free_buffers(ati_remote);
937 exit_free_dev_rdev:
938 rc_free_device(rc_dev);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500939 kfree(ati_remote);
940 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941}
942
943/*
Du, Changbina342daea2012-07-07 03:53:28 -0300944 * ati_remote_disconnect
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 */
946static void ati_remote_disconnect(struct usb_interface *interface)
947{
948 struct ati_remote *ati_remote;
949
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 ati_remote = usb_get_intfdata(interface);
951 usb_set_intfdata(interface, NULL);
952 if (!ati_remote) {
Greg Kroah-Hartman1817b162008-08-14 09:37:34 -0700953 dev_warn(&interface->dev, "%s - null device?\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 return;
955 }
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500956
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500957 usb_kill_urb(ati_remote->irq_urb);
958 usb_kill_urb(ati_remote->out_urb);
Anssi Hannulac34516e2011-08-06 18:18:08 -0300959 if (ati_remote->idev)
960 input_unregister_device(ati_remote->idev);
961 rc_unregister_device(ati_remote->rdev);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500962 ati_remote_free_buffers(ati_remote);
963 kfree(ati_remote);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964}
965
Du, Changbina342daea2012-07-07 03:53:28 -0300966/* usb specific object to register with the usb subsystem */
967static struct usb_driver ati_remote_driver = {
968 .name = "ati_remote",
969 .probe = ati_remote_probe,
970 .disconnect = ati_remote_disconnect,
971 .id_table = ati_remote_table,
972};
973
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800974module_usb_driver(ati_remote_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976MODULE_AUTHOR(DRIVER_AUTHOR);
977MODULE_DESCRIPTION(DRIVER_DESC);
978MODULE_LICENSE("GPL");