*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
#include <linux/wait.h>
#include <linux/jiffies.h>
#define NAME_BUFSIZE 80 /* size of product name, path buffers */
#define DATA_BUFSIZE 63 /* size of URB data buffers */
+/*
+ * Duplicate event filtering time.
+ * Sequential, identical KIND_FILTERED inputs with less than
+ * FILTER_TIME milliseconds between them are considered as repeat
+ * events. The hardware generates 5 events for the first keypress
+ * and we have to take this into account for an accurate repeat
+ * behaviour.
+ */
+#define FILTER_TIME 60 /* msec */
+
static unsigned long channel_mask;
-module_param(channel_mask, ulong, 0444);
+module_param(channel_mask, ulong, 0644);
MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
static int debug;
-module_param(debug, int, 0444);
+module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+static int repeat_filter = FILTER_TIME;
+module_param(repeat_filter, int, 0644);
+MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
+
#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
#undef err
#define err(format, arg...) printk(KERN_ERR format , ## arg)
static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
-/* Acceleration curve for directional control pad */
-static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
-
-/* Duplicate event filtering time.
- * Sequential, identical KIND_FILTERED inputs with less than
- * FILTER_TIME jiffies between them are considered as repeat
- * events. The hardware generates 5 events for the first keypress
- * and we have to take this into account for an accurate repeat
- * behaviour.
- * (HZ / 20) == 50 ms and works well for me.
- */
-#define FILTER_TIME (HZ / 20)
-
-static DECLARE_MUTEX(disconnect_sem);
-
struct ati_remote {
struct input_dev *idev;
struct usb_device *udev;
static int ati_remote_open (struct input_dev *inputdev);
static void ati_remote_close (struct input_dev *inputdev);
static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
-static void ati_remote_irq_out (struct urb *urb, struct pt_regs *regs);
-static void ati_remote_irq_in (struct urb *urb, struct pt_regs *regs);
-static void ati_remote_input_report (struct urb *urb, struct pt_regs *regs);
+static void ati_remote_irq_out (struct urb *urb);
+static void ati_remote_irq_in (struct urb *urb);
+static void ati_remote_input_report (struct urb *urb);
static int ati_remote_initialize (struct ati_remote *ati_remote);
static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id);
static void ati_remote_disconnect (struct usb_interface *interface);
/*
* ati_remote_irq_out
*/
-static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
+static void ati_remote_irq_out(struct urb *urb)
{
struct ati_remote *ati_remote = urb->context;
return -1;
}
+/*
+ * ati_remote_compute_accel
+ *
+ * Implements acceleration curve for directional control pad
+ * If elapsed time since last event is > 1/4 second, user "stopped",
+ * so reset acceleration. Otherwise, user is probably holding the control
+ * pad down, so we increase acceleration, ramping up over two seconds to
+ * a maximum speed.
+ */
+static int ati_remote_compute_accel(struct ati_remote *ati_remote)
+{
+ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
+ unsigned long now = jiffies;
+ int acc;
+
+ if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
+ acc = 1;
+ ati_remote->acc_jiffies = now;
+ }
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
+ acc = accel[0];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
+ acc = accel[1];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
+ acc = accel[2];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
+ acc = accel[3];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
+ acc = accel[4];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
+ acc = accel[5];
+ else
+ acc = accel[6];
+
+ return acc;
+}
+
/*
* ati_remote_report_input
*/
-static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
+static void ati_remote_input_report(struct urb *urb)
{
struct ati_remote *ati_remote = urb->context;
unsigned char *data= ati_remote->inbuf;
remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
if (ati_remote_tbl[index].kind == KIND_LITERAL) {
- input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code,
ati_remote_tbl[index].value);
if (ati_remote_tbl[index].kind == KIND_FILTERED) {
/* Filter duplicate events which happen "too close" together. */
- if ((ati_remote->old_data[0] == data[1]) &&
- (ati_remote->old_data[1] == data[2]) &&
- time_before(jiffies, ati_remote->old_jiffies + FILTER_TIME)) {
+ if (ati_remote->old_data[0] == data[1] &&
+ ati_remote->old_data[1] == data[2] &&
+ time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) {
ati_remote->repeat_count++;
} else {
ati_remote->repeat_count = 0;
ati_remote->old_data[1] = data[2];
ati_remote->old_jiffies = jiffies;
- if ((ati_remote->repeat_count > 0)
- && (ati_remote->repeat_count < 5))
+ if (ati_remote->repeat_count > 0 &&
+ ati_remote->repeat_count < 5)
return;
- input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 1);
+ input_sync(dev);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 0);
input_sync(dev);
- return;
- }
+ } else {
- /*
- * Other event kinds are from the directional control pad, and have an
- * acceleration factor applied to them. Without this acceleration, the
- * control pad is mostly unusable.
- *
- * If elapsed time since last event is > 1/4 second, user "stopped",
- * so reset acceleration. Otherwise, user is probably holding the control
- * pad down, so we increase acceleration, ramping up over two seconds to
- * a maximum speed. The acceleration curve is #defined above.
- */
- if (time_after(jiffies, ati_remote->old_jiffies + (HZ >> 2))) {
- acc = 1;
- ati_remote->acc_jiffies = jiffies;
- }
- else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 3))) acc = accel[0];
- else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 2))) acc = accel[1];
- else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 1))) acc = accel[2];
- else if (time_before(jiffies, ati_remote->acc_jiffies + HZ)) acc = accel[3];
- else if (time_before(jiffies, ati_remote->acc_jiffies + HZ+(HZ>>1))) acc = accel[4];
- else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ << 1))) acc = accel[5];
- else acc = accel[6];
-
- input_regs(dev, regs);
- switch (ati_remote_tbl[index].kind) {
- case KIND_ACCEL:
- input_event(dev, ati_remote_tbl[index].type,
- ati_remote_tbl[index].code,
- ati_remote_tbl[index].value * acc);
- break;
- case KIND_LU:
- input_report_rel(dev, REL_X, -acc);
- input_report_rel(dev, REL_Y, -acc);
- break;
- case KIND_RU:
- input_report_rel(dev, REL_X, acc);
- input_report_rel(dev, REL_Y, -acc);
- break;
- case KIND_LD:
- input_report_rel(dev, REL_X, -acc);
- input_report_rel(dev, REL_Y, acc);
- break;
- case KIND_RD:
- input_report_rel(dev, REL_X, acc);
- input_report_rel(dev, REL_Y, acc);
- break;
- default:
- dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
- ati_remote_tbl[index].kind);
- }
- input_sync(dev);
+ /*
+ * Other event kinds are from the directional control pad, and have an
+ * acceleration factor applied to them. Without this acceleration, the
+ * control pad is mostly unusable.
+ */
+ acc = ati_remote_compute_accel(ati_remote);
+
+ switch (ati_remote_tbl[index].kind) {
+ case KIND_ACCEL:
+ input_event(dev, ati_remote_tbl[index].type,
+ ati_remote_tbl[index].code,
+ ati_remote_tbl[index].value * acc);
+ break;
+ case KIND_LU:
+ input_report_rel(dev, REL_X, -acc);
+ input_report_rel(dev, REL_Y, -acc);
+ break;
+ case KIND_RU:
+ input_report_rel(dev, REL_X, acc);
+ input_report_rel(dev, REL_Y, -acc);
+ break;
+ case KIND_LD:
+ input_report_rel(dev, REL_X, -acc);
+ input_report_rel(dev, REL_Y, acc);
+ break;
+ case KIND_RD:
+ input_report_rel(dev, REL_X, acc);
+ input_report_rel(dev, REL_Y, acc);
+ break;
+ default:
+ dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
+ ati_remote_tbl[index].kind);
+ }
+ input_sync(dev);
- ati_remote->old_jiffies = jiffies;
- ati_remote->old_data[0] = data[1];
- ati_remote->old_data[1] = data[2];
+ ati_remote->old_jiffies = jiffies;
+ ati_remote->old_data[0] = data[1];
+ ati_remote->old_data[1] = data[2];
+ }
}
/*
* ati_remote_irq_in
*/
-static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
+static void ati_remote_irq_in(struct urb *urb)
{
struct ati_remote *ati_remote = urb->context;
int retval;
switch (urb->status) {
case 0: /* success */
- ati_remote_input_report(urb, regs);
+ ati_remote_input_report(urb);
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
__FUNCTION__, urb->status);
}
- retval = usb_submit_urb(urb, SLAB_ATOMIC);
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
__FUNCTION__, retval);
static int ati_remote_alloc_buffers(struct usb_device *udev,
struct ati_remote *ati_remote)
{
- ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC,
+ ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
&ati_remote->inbuf_dma);
if (!ati_remote->inbuf)
return -1;
- ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC,
+ ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
&ati_remote->outbuf_dma);
if (!ati_remote->outbuf)
return -1;
*/
static void ati_remote_free_buffers(struct ati_remote *ati_remote)
{
- if (ati_remote->irq_urb)
- usb_free_urb(ati_remote->irq_urb);
+ usb_free_urb(ati_remote->irq_urb);
+ usb_free_urb(ati_remote->out_urb);
- if (ati_remote->out_urb)
- usb_free_urb(ati_remote->out_urb);
+ usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+ ati_remote->inbuf, ati_remote->inbuf_dma);
- if (ati_remote->inbuf)
- usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
- ati_remote->inbuf, ati_remote->inbuf_dma);
-
- if (ati_remote->outbuf)
- usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
- ati_remote->outbuf, ati_remote->outbuf_dma);
+ usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+ ati_remote->outbuf, ati_remote->outbuf_dma);
}
static void ati_remote_input_init(struct ati_remote *ati_remote)
endpoint_in = &iface_host->endpoint[0].desc;
endpoint_out = &iface_host->endpoint[1].desc;
- if (!(endpoint_in->bEndpointAddress & USB_DIR_IN)) {
- err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__);
- return -ENODEV;
- }
- if ((endpoint_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
- err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__);
+ if (!usb_endpoint_is_int_in(endpoint_in)) {
+ err("%s: Unexpected endpoint_in\n", __FUNCTION__);
return -ENODEV;
}
if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {