]> git.openfabrics.org - ~emulex/infiniband.git/commitdiff
Input: move USB miscellaneous devices under drivers/input/misc
authorDmitry Torokhov <dtor@insightbb.com>
Mon, 7 May 2007 21:31:32 +0000 (17:31 -0400)
committerDmitry Torokhov <dtor@insightbb.com>
Tue, 8 May 2007 05:41:29 +0000 (01:41 -0400)
This will allow concentrating all input devices in one place
in {menu|x|q}config.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
20 files changed:
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ati_remote.c [new file with mode: 0644]
drivers/input/misc/ati_remote2.c [new file with mode: 0644]
drivers/input/misc/keyspan_remote.c [new file with mode: 0644]
drivers/input/misc/map_to_7segment.h [new file with mode: 0644]
drivers/input/misc/powermate.c [new file with mode: 0644]
drivers/input/misc/yealink.c [new file with mode: 0644]
drivers/input/misc/yealink.h [new file with mode: 0644]
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/input/Kconfig [deleted file]
drivers/usb/input/Makefile [deleted file]
drivers/usb/input/ati_remote.c [deleted file]
drivers/usb/input/ati_remote2.c [deleted file]
drivers/usb/input/keyspan_remote.c [deleted file]
drivers/usb/input/map_to_7segment.h [deleted file]
drivers/usb/input/powermate.c [deleted file]
drivers/usb/input/yealink.c [deleted file]
drivers/usb/input/yealink.h [deleted file]

index 1d0d3e765db67a1ee0919dcbf2202b88c505a3db..6013ace94d98675a1ba1b47781d9470db82ca161 100644 (file)
@@ -40,6 +40,18 @@ config INPUT_M68K_BEEP
        tristate "M68k Beeper support"
        depends on M68K
 
+config INPUT_IXP4XX_BEEPER
+       tristate "IXP4XX Beeper support"
+       depends on ARCH_IXP4XX
+       help
+         If you say yes here, you can connect a beeper to the
+         ixp4xx gpio pins. This is used by the LinkSys NSLU2.
+
+         If unsure, say Y.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ixp4xx-beeper.
+
 config INPUT_COBALT_BTNS
        tristate "Cobalt button interface"
        depends on MIPS_COBALT
@@ -70,17 +82,79 @@ config INPUT_ATLAS_BTNS
          To compile this driver as a module, choose M here: the module will
          be called atlas_btns.
 
-config INPUT_IXP4XX_BEEPER
-       tristate "IXP4XX Beeper support"
-       depends on ARCH_IXP4XX
+config INPUT_ATI_REMOTE
+       tristate "ATI / X10 USB RF remote control"
+       select USB
        help
-         If you say yes here, you can connect a beeper to the
-         ixp4xx gpio pins. This is used by the LinkSys NSLU2.
+         Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
+         These are RF remotes with USB receivers.
+         The ATI remote comes with many of ATI's All-In-Wonder video cards.
+         The X10 "Lola" remote is available at:
+            <http://www.x10.com/products/lola_sg1.htm>
+         This driver provides mouse pointer, left and right mouse buttons,
+         and maps all the other remote buttons to keypress events.
+
+         To compile this driver as a module, choose M here: the module will be
+         called ati_remote.
+
+config INPUT_ATI_REMOTE2
+       tristate "ATI / Philips USB RF remote control"
+       select USB
+       help
+         Say Y here if you want to use an ATI or Philips USB RF remote control.
+         These are RF remotes with USB receivers.
+         ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards
+         and is also available as a separate product.
+         This driver provides mouse pointer, left and right mouse buttons,
+         and maps all the other remote buttons to keypress events.
+
+         To compile this driver as a module, choose M here: the module will be
+         called ati_remote2.
+
+config INPUT_KEYSPAN_REMOTE
+       tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       select USB
+       help
+         Say Y here if you want to use a Keyspan DMR USB remote control.
+         Currently only the UIA-11 type of receiver has been tested.  The tag
+         on the receiver that connects to the USB port should have a P/N that
+         will tell you what type of DMR you have.  The UIA-10 type is not
+         supported at this time.  This driver maps all buttons to keypress
+         events.
 
-         If unsure, say Y.
+         To compile this driver as a module, choose M here: the module will
+         be called keyspan_remote.
+
+config INPUT_POWERMATE
+       tristate "Griffin PowerMate and Contour Jog support"
+       select USB
+       help
+         Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
+         These are aluminum dials which can measure clockwise and anticlockwise
+         rotation.  The dial also acts as a pushbutton.  The base contains an LED
+         which can be instructed to pulse or to switch to a particular intensity.
+
+         You can download userspace tools from
+         <http://sowerbutts.com/powermate/>.
 
          To compile this driver as a module, choose M here: the
-         module will be called ixp4xx-beeper.
+         module will be called powermate.
+
+config INPUT_YEALINK
+       tristate "Yealink usb-p1k voip phone"
+       depends EXPERIMENTAL
+       select USB
+       help
+         Say Y here if you want to enable keyboard and LCD functions of the
+         Yealink usb-p1k usb phones. The audio part is enabled by the generic
+         usb sound driver, so you might want to enable that as well.
+
+         For information about how to use these additional functions, see
+         <file:Documentation/input/yealink.txt>.
+
+         To compile this driver as a module, choose M here: the module will be
+         called yealink.
 
 config INPUT_UINPUT
        tristate "User level driver support"
index 21e3cca0d33e13667c0cb90661d1d82a1b04b893..8b2f7799e25c98e2e33668b6cdfb6d0299c796ce 100644 (file)
@@ -8,9 +8,14 @@ obj-$(CONFIG_INPUT_POLLDEV)            += input-polldev.o
 obj-$(CONFIG_INPUT_SPARCSPKR)          += sparcspkr.o
 obj-$(CONFIG_INPUT_PCSPKR)             += pcspkr.o
 obj-$(CONFIG_INPUT_M68K_BEEP)          += m68kspkr.o
-obj-$(CONFIG_INPUT_UINPUT)             += uinput.o
+obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)                += cobalt_btns.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)       += wistron_btns.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)         += atlas_btns.o
+obj-$(CONFIG_INPUT_ATI_REMOTE)         += ati_remote.o
+obj-$(CONFIG_INPUT_ATI_REMOTE2)                += ati_remote2.o
+obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)     += keyspan_remote.o
+obj-$(CONFIG_INPUT_POWERMATE)          += powermate.o
+obj-$(CONFIG_INPUT_YEALINK)            += yealink.o
 obj-$(CONFIG_HP_SDC_RTC)               += hp_sdc_rtc.o
-obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o
+obj-$(CONFIG_INPUT_UINPUT)             += uinput.o
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
new file mode 100644 (file)
index 0000000..471aab2
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ *  USB ATI Remote support
+ *
+ *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
+ *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
+ *
+ *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
+ *  porting to the 2.6 kernel interfaces, along with other modification
+ *  to better match the style of the existing usb/input drivers.  However, the
+ *  protocol and hardware handling is essentially unchanged from 2.1.1.
+ *
+ *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
+ *  Vojtech Pavlik.
+ *
+ *  Changes:
+ *
+ *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.0
+ *  Jun 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.1
+ *            Added key repeat support contributed by:
+ *                Vincent Vanackere <vanackere@lif.univ-mrs.fr>
+ *            Added support for the "Lola" remote contributed by:
+ *                Seth Cohn <sethcohn@yahoo.com>
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * Hardware & software notes
+ *
+ * These remote controls are distributed by ATI as part of their
+ * "All-In-Wonder" video card packages.  The receiver self-identifies as a
+ * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
+ *
+ * The "Lola" remote is available from X10.  See:
+ *    http://www.x10.com/products/lola_sg1.htm
+ * The Lola is similar to the ATI remote but has no mouse support, and slightly
+ * different keys.
+ *
+ * It is possible to use multiple receivers and remotes on multiple computers
+ * simultaneously by configuring them to use specific channels.
+ *
+ * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
+ * Actually, it may even support more, at least in some revisions of the
+ * hardware.
+ *
+ * Each remote can be configured to transmit on one channel as follows:
+ *   - Press and hold the "hand icon" button.
+ *   - When the red LED starts to blink, let go of the "hand icon" button.
+ *   - When it stops blinking, input the channel code as two digits, from 01
+ *     to 16, and press the hand icon again.
+ *
+ * The timing can be a little tricky.  Try loading the module with debug=1
+ * to have the kernel print out messages about the remote control number
+ * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
+ *
+ * The driver has a "channel_mask" parameter. This bitmask specifies which
+ * channels will be ignored by the module.  To mask out channels, just add
+ * all the 2^channel_number values together.
+ *
+ * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
+ * ignore signals coming from remote controls transmitting on channel 4, but
+ * accept all other channels.
+ *
+ * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
+ * ignored.
+ *
+ * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
+ * parameter are unused.
+ *
+ */
+
+#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/usb/input.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+
+/*
+ * Module and Version Information, Module Parameters
+ */
+
+#define ATI_REMOTE_VENDOR_ID   0x0bc7
+#define ATI_REMOTE_PRODUCT_ID  0x004
+#define LOLA_REMOTE_PRODUCT_ID 0x002
+#define MEDION_REMOTE_PRODUCT_ID 0x006
+
+#define DRIVER_VERSION         "2.2.1"
+#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
+#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
+
+#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 */
+#define REPEAT_DELAY   500 /* msec */
+
+static unsigned long channel_mask;
+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, 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");
+
+static int repeat_delay = REPEAT_DELAY;
+module_param(repeat_delay, int, 0644);
+MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 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 struct usb_device_id ati_remote_table[] = {
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
+       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
+       {}      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ati_remote_table);
+
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a)  ((unsigned char)((a) >> 8))
+#define LO(a)  ((unsigned char)((a) & 0xff))
+
+#define SEND_FLAG_IN_PROGRESS  1
+#define SEND_FLAG_COMPLETE     2
+
+/* Device initialization strings */
+static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
+static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
+
+struct ati_remote {
+       struct input_dev *idev;
+       struct usb_device *udev;
+       struct usb_interface *interface;
+
+       struct urb *irq_urb;
+       struct urb *out_urb;
+       struct usb_endpoint_descriptor *endpoint_in;
+       struct usb_endpoint_descriptor *endpoint_out;
+       unsigned char *inbuf;
+       unsigned char *outbuf;
+       dma_addr_t inbuf_dma;
+       dma_addr_t outbuf_dma;
+
+       unsigned char old_data[2];  /* Detect duplicate events */
+       unsigned long old_jiffies;
+       unsigned long acc_jiffies;  /* handle acceleration */
+       unsigned long first_jiffies;
+
+       unsigned int repeat_count;
+
+       char name[NAME_BUFSIZE];
+       char phys[NAME_BUFSIZE];
+
+       wait_queue_head_t wait;
+       int send_flags;
+};
+
+/* "Kinds" of messages sent from the hardware to the driver. */
+#define KIND_END        0
+#define KIND_LITERAL    1   /* Simply pass to input system */
+#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
+#define KIND_LU         3   /* Directional keypad diagonals - left up, */
+#define KIND_RU         4   /*   right up,  */
+#define KIND_LD         5   /*   left down, */
+#define KIND_RD         6   /*   right down */
+#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
+
+/* Translation table from hardware messages to input events. */
+static const struct {
+       short kind;
+       unsigned char data1, data2;
+       int type;
+       unsigned int code;
+       int value;
+}  ati_remote_tbl[] = {
+       /* Directional control pad axes */
+       {KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},   /* left */
+       {KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
+       {KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},   /* up */
+       {KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
+       /* Directional control pad diagonals */
+       {KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
+       {KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
+       {KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
+       {KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
+
+       /* "Mouse button" buttons */
+       {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
+       {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
+       {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
+       {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
+
+       /* Artificial "doubleclick" events are generated by the hardware.
+        * They are mapped to the "side" and "extra" mouse buttons here. */
+       {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
+       {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
+
+       /* keyboard. */
+       {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
+       {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
+       {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
+       {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
+       {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
+       {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
+       {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
+       {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
+       {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
+       {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
+       {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
+       {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
+       {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
+       {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
+       {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
+       {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
+
+       /* "special" keys */
+       {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
+       {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
+       {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
+       {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
+       {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
+       {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
+       {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
+       {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
+       {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
+       {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
+       {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
+       {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
+       {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
+       {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
+       {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
+       {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
+       {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
+       {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
+       {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
+       {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
+       {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
+       {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
+       {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
+       {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
+       {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
+       {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
+       {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
+       {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
+       {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
+       {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
+       {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
+       {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
+
+       {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
+};
+
+/* Local function prototypes */
+static void ati_remote_dump            (unsigned char *data, unsigned int actual_length);
+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);
+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);
+
+/* usb specific object to register with the usb subsystem */
+static struct usb_driver ati_remote_driver = {
+       .name         = "ati_remote",
+       .probe        = ati_remote_probe,
+       .disconnect   = ati_remote_disconnect,
+       .id_table     = ati_remote_table,
+};
+
+/*
+ *     ati_remote_dump_input
+ */
+static void ati_remote_dump(unsigned char *data, unsigned int len)
+{
+       if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
+               warn("Weird byte 0x%02x", data[0]);
+       else if (len == 4)
+               warn("Weird key %02x %02x %02x %02x",
+                    data[0], data[1], data[2], data[3]);
+       else
+               warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
+                    len, data[0], data[1], data[2], data[3], data[4], data[5]);
+}
+
+/*
+ *     ati_remote_open
+ */
+static int ati_remote_open(struct input_dev *inputdev)
+{
+       struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+
+       /* On first open, submit the read urb which was set up previously. */
+       ati_remote->irq_urb->dev = ati_remote->udev;
+       if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
+               dev_err(&ati_remote->interface->dev,
+                       "%s: usb_submit_urb failed!\n", __FUNCTION__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ *     ati_remote_close
+ */
+static void ati_remote_close(struct input_dev *inputdev)
+{
+       struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+
+       usb_kill_urb(ati_remote->irq_urb);
+}
+
+/*
+ *             ati_remote_irq_out
+ */
+static void ati_remote_irq_out(struct urb *urb)
+{
+       struct ati_remote *ati_remote = urb->context;
+
+       if (urb->status) {
+               dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
+                       __FUNCTION__, urb->status);
+               return;
+       }
+
+       ati_remote->send_flags |= SEND_FLAG_COMPLETE;
+       wmb();
+       wake_up(&ati_remote->wait);
+}
+
+/*
+ *     ati_remote_sendpacket
+ *
+ *     Used to send device initialization strings
+ */
+static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
+{
+       int retval = 0;
+
+       /* Set up out_urb */
+       memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
+       ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
+
+       ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
+       ati_remote->out_urb->dev = ati_remote->udev;
+       ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
+
+       retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
+       if (retval) {
+               dev_dbg(&ati_remote->interface->dev,
+                        "sendpacket: usb_submit_urb failed: %d\n", retval);
+               return retval;
+       }
+
+       wait_event_timeout(ati_remote->wait,
+               ((ati_remote->out_urb->status != -EINPROGRESS) ||
+                       (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+               HZ);
+       usb_kill_urb(ati_remote->out_urb);
+
+       return retval;
+}
+
+/*
+ *     ati_remote_event_lookup
+ */
+static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
+{
+       int i;
+
+       for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
+               /*
+                * Decide if the table entry matches the remote input.
+                */
+               if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
+                   ((((ati_remote_tbl[i].data1 >> 4) -
+                      (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
+                   (ati_remote_tbl[i].data2 == d2))
+                       return i;
+
+       }
+       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 ati_remote *ati_remote = urb->context;
+       unsigned char *data= ati_remote->inbuf;
+       struct input_dev *dev = ati_remote->idev;
+       int index, acc;
+       int remote_num;
+
+       /* Deal with strange looking inputs */
+       if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
+               ((data[3] & 0x0f) != 0x00) ) {
+               ati_remote_dump(data, urb->actual_length);
+               return;
+       }
+
+       /* Mask unwanted remote channels.  */
+       /* note: remote_num is 0-based, channel 1 on remote == 0 here */
+       remote_num = (data[3] >> 4) & 0x0f;
+        if (channel_mask & (1 << (remote_num + 1))) {
+               dbginfo(&ati_remote->interface->dev,
+                       "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
+                       remote_num, data[1], data[2], channel_mask);
+               return;
+       }
+
+       /* Look up event code index in translation table */
+       index = ati_remote_event_lookup(remote_num, data[1], data[2]);
+       if (index < 0) {
+               dev_warn(&ati_remote->interface->dev,
+                        "Unknown input from channel 0x%02x: data %02x,%02x\n",
+                        remote_num, data[1], data[2]);
+               return;
+       }
+       dbginfo(&ati_remote->interface->dev,
+               "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
+               remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
+
+       if (ati_remote_tbl[index].kind == KIND_LITERAL) {
+               input_event(dev, ati_remote_tbl[index].type,
+                       ati_remote_tbl[index].code,
+                       ati_remote_tbl[index].value);
+               input_sync(dev);
+
+               ati_remote->old_jiffies = jiffies;
+               return;
+       }
+
+       if (ati_remote_tbl[index].kind == KIND_FILTERED) {
+               unsigned long now = jiffies;
+
+               /* 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(now, ati_remote->old_jiffies +
+                                    msecs_to_jiffies(repeat_filter))) {
+                       ati_remote->repeat_count++;
+               } else {
+                       ati_remote->repeat_count = 0;
+                       ati_remote->first_jiffies = now;
+               }
+
+               ati_remote->old_data[0] = data[1];
+               ati_remote->old_data[1] = data[2];
+               ati_remote->old_jiffies = now;
+
+               /* Ensure we skip at least the 4 first duplicate events (generated
+                * by a single keypress), and continue skipping until repeat_delay
+                * msecs have passed
+                */
+               if (ati_remote->repeat_count > 0 &&
+                   (ati_remote->repeat_count < 5 ||
+                    time_before(now, ati_remote->first_jiffies +
+                                     msecs_to_jiffies(repeat_delay))))
+                       return;
+
+
+               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);
+
+       } 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.
+                */
+               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_irq_in
+ */
+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);
+               break;
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
+                       __FUNCTION__);
+               return;
+       default:                /* error */
+               dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
+                       __FUNCTION__, urb->status);
+       }
+
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
+                       __FUNCTION__, retval);
+}
+
+/*
+ *     ati_remote_alloc_buffers
+ */
+static int ati_remote_alloc_buffers(struct usb_device *udev,
+                                   struct ati_remote *ati_remote)
+{
+       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, GFP_ATOMIC,
+                                             &ati_remote->outbuf_dma);
+       if (!ati_remote->outbuf)
+               return -1;
+
+       ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!ati_remote->irq_urb)
+               return -1;
+
+       ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!ati_remote->out_urb)
+               return -1;
+
+       return 0;
+}
+
+/*
+ *     ati_remote_free_buffers
+ */
+static void ati_remote_free_buffers(struct ati_remote *ati_remote)
+{
+       usb_free_urb(ati_remote->irq_urb);
+       usb_free_urb(ati_remote->out_urb);
+
+       usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+               ati_remote->inbuf, ati_remote->inbuf_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)
+{
+       struct input_dev *idev = ati_remote->idev;
+       int i;
+
+       idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+                                         BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
+       idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
+               if (ati_remote_tbl[i].type == EV_KEY)
+                       set_bit(ati_remote_tbl[i].code, idev->keybit);
+
+       input_set_drvdata(idev, ati_remote);
+
+       idev->open = ati_remote_open;
+       idev->close = ati_remote_close;
+
+       idev->name = ati_remote->name;
+       idev->phys = ati_remote->phys;
+
+       usb_to_input_id(ati_remote->udev, &idev->id);
+       idev->dev.parent = &ati_remote->udev->dev;
+}
+
+static int ati_remote_initialize(struct ati_remote *ati_remote)
+{
+       struct usb_device *udev = ati_remote->udev;
+       int pipe, maxp;
+
+       init_waitqueue_head(&ati_remote->wait);
+
+       /* Set up irq_urb */
+       pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
+       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+       usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
+                        maxp, ati_remote_irq_in, ati_remote,
+                        ati_remote->endpoint_in->bInterval);
+       ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
+       ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* Set up out_urb */
+       pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
+       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+       usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
+                        maxp, ati_remote_irq_out, ati_remote,
+                        ati_remote->endpoint_out->bInterval);
+       ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
+       ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* send initialization strings */
+       if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
+           (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
+               dev_err(&ati_remote->interface->dev,
+                        "Initializing ati_remote hardware failed.\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ *     ati_remote_probe
+ */
+static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct usb_host_interface *iface_host = interface->cur_altsetting;
+       struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
+       struct ati_remote *ati_remote;
+       struct input_dev *input_dev;
+       int err = -ENOMEM;
+
+       if (iface_host->desc.bNumEndpoints != 2) {
+               err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       endpoint_in = &iface_host->endpoint[0].desc;
+       endpoint_out = &iface_host->endpoint[1].desc;
+
+       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) {
+               err("%s: endpoint_in message size==0? \n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ati_remote || !input_dev)
+               goto fail1;
+
+       /* Allocate URB buffers, URBs */
+       if (ati_remote_alloc_buffers(udev, ati_remote))
+               goto fail2;
+
+       ati_remote->endpoint_in = endpoint_in;
+       ati_remote->endpoint_out = endpoint_out;
+       ati_remote->udev = udev;
+       ati_remote->idev = input_dev;
+       ati_remote->interface = interface;
+
+       usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys));
+       strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys));
+
+       if (udev->manufacturer)
+               strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
+
+       if (udev->product)
+               snprintf(ati_remote->name, sizeof(ati_remote->name),
+                        "%s %s", ati_remote->name, udev->product);
+
+       if (!strlen(ati_remote->name))
+               snprintf(ati_remote->name, sizeof(ati_remote->name),
+                       DRIVER_DESC "(%04x,%04x)",
+                       le16_to_cpu(ati_remote->udev->descriptor.idVendor),
+                       le16_to_cpu(ati_remote->udev->descriptor.idProduct));
+
+       ati_remote_input_init(ati_remote);
+
+       /* Device Hardware Initialization - fills in ati_remote->idev from udev. */
+       err = ati_remote_initialize(ati_remote);
+       if (err)
+               goto fail3;
+
+       /* Set up and register input device */
+       err = input_register_device(ati_remote->idev);
+       if (err)
+               goto fail3;
+
+       usb_set_intfdata(interface, ati_remote);
+       return 0;
+
+ fail3:        usb_kill_urb(ati_remote->irq_urb);
+       usb_kill_urb(ati_remote->out_urb);
+ fail2:        ati_remote_free_buffers(ati_remote);
+ fail1:        input_free_device(input_dev);
+       kfree(ati_remote);
+       return err;
+}
+
+/*
+ *     ati_remote_disconnect
+ */
+static void ati_remote_disconnect(struct usb_interface *interface)
+{
+       struct ati_remote *ati_remote;
+
+       ati_remote = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+       if (!ati_remote) {
+               warn("%s - null device?\n", __FUNCTION__);
+               return;
+       }
+
+       usb_kill_urb(ati_remote->irq_urb);
+       usb_kill_urb(ati_remote->out_urb);
+       input_unregister_device(ati_remote->idev);
+       ati_remote_free_buffers(ati_remote);
+       kfree(ati_remote);
+}
+
+/*
+ *     ati_remote_init
+ */
+static int __init ati_remote_init(void)
+{
+       int result;
+
+       result = usb_register(&ati_remote_driver);
+       if (result)
+               err("usb_register error #%d\n", result);
+       else
+               info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION);
+
+       return result;
+}
+
+/*
+ *     ati_remote_exit
+ */
+static void __exit ati_remote_exit(void)
+{
+       usb_deregister(&ati_remote_driver);
+}
+
+/*
+ *     module specification
+ */
+
+module_init(ati_remote_init);
+module_exit(ati_remote_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
new file mode 100644 (file)
index 0000000..1031543
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * ati_remote2 - ATI/Philips USB RF remote driver
+ *
+ * Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi>
+ * Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/usb/input.h>
+
+#define DRIVER_DESC    "ATI/Philips USB RF remote driver"
+#define DRIVER_VERSION "0.2"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
+MODULE_LICENSE("GPL");
+
+/*
+ * ATI Remote Wonder II Channel Configuration
+ *
+ * The remote control can by assigned one of sixteen "channels" in order to facilitate
+ * the use of multiple remote controls within range of each other.
+ * A remote's "channel" may be altered by pressing and holding the "PC" button for
+ * approximately 3 seconds, after which the button will slowly flash the count of the
+ * currently configured "channel", using the numeric keypad enter a number between 1 and
+ * 16 and then the "PC" button again, the button will slowly flash the count of the
+ * newly configured "channel".
+ */
+
+static unsigned int channel_mask = 0xFFFF;
+module_param(channel_mask, uint, 0644);
+MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
+
+static unsigned int mode_mask = 0x1F;
+module_param(mode_mask, uint, 0644);
+MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
+
+static struct usb_device_id ati_remote2_id_table[] = {
+       { USB_DEVICE(0x0471, 0x0602) }, /* ATI Remote Wonder II */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
+
+static struct {
+       int hw_code;
+       int key_code;
+} ati_remote2_key_table[] = {
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+       { 0x0c, KEY_POWER },
+       { 0x0d, KEY_MUTE },
+       { 0x10, KEY_VOLUMEUP },
+       { 0x11, KEY_VOLUMEDOWN },
+       { 0x20, KEY_CHANNELUP },
+       { 0x21, KEY_CHANNELDOWN },
+       { 0x28, KEY_FORWARD },
+       { 0x29, KEY_REWIND },
+       { 0x2c, KEY_PLAY },
+       { 0x30, KEY_PAUSE },
+       { 0x31, KEY_STOP },
+       { 0x37, KEY_RECORD },
+       { 0x38, KEY_DVD },
+       { 0x39, KEY_TV },
+       { 0x54, KEY_MENU },
+       { 0x58, KEY_UP },
+       { 0x59, KEY_DOWN },
+       { 0x5a, KEY_LEFT },
+       { 0x5b, KEY_RIGHT },
+       { 0x5c, KEY_OK },
+       { 0x78, KEY_A },
+       { 0x79, KEY_B },
+       { 0x7a, KEY_C },
+       { 0x7b, KEY_D },
+       { 0x7c, KEY_E },
+       { 0x7d, KEY_F },
+       { 0x82, KEY_ENTER },
+       { 0x8e, KEY_VENDOR },
+       { 0x96, KEY_COFFEE },
+       { 0xa9, BTN_LEFT },
+       { 0xaa, BTN_RIGHT },
+       { 0xbe, KEY_QUESTION },
+       { 0xd5, KEY_FRONT },
+       { 0xd0, KEY_EDIT },
+       { 0xf9, KEY_INFO },
+       { (0x00 << 8) | 0x3f, KEY_PROG1 },
+       { (0x01 << 8) | 0x3f, KEY_PROG2 },
+       { (0x02 << 8) | 0x3f, KEY_PROG3 },
+       { (0x03 << 8) | 0x3f, KEY_PROG4 },
+       { (0x04 << 8) | 0x3f, KEY_PC },
+       { 0, KEY_RESERVED }
+};
+
+struct ati_remote2 {
+       struct input_dev *idev;
+       struct usb_device *udev;
+
+       struct usb_interface *intf[2];
+       struct usb_endpoint_descriptor *ep[2];
+       struct urb *urb[2];
+       void *buf[2];
+       dma_addr_t buf_dma[2];
+
+       unsigned long jiffies;
+       int mode;
+
+       char name[64];
+       char phys[64];
+};
+
+static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
+static void ati_remote2_disconnect(struct usb_interface *interface);
+
+static struct usb_driver ati_remote2_driver = {
+       .name       = "ati_remote2",
+       .probe      = ati_remote2_probe,
+       .disconnect = ati_remote2_disconnect,
+       .id_table   = ati_remote2_id_table,
+};
+
+static int ati_remote2_open(struct input_dev *idev)
+{
+       struct ati_remote2 *ar2 = input_get_drvdata(idev);
+       int r;
+
+       r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
+       if (r) {
+               dev_err(&ar2->intf[0]->dev,
+                       "%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
+               return r;
+       }
+       r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
+       if (r) {
+               usb_kill_urb(ar2->urb[0]);
+               dev_err(&ar2->intf[1]->dev,
+                       "%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
+               return r;
+       }
+
+       return 0;
+}
+
+static void ati_remote2_close(struct input_dev *idev)
+{
+       struct ati_remote2 *ar2 = input_get_drvdata(idev);
+
+       usb_kill_urb(ar2->urb[0]);
+       usb_kill_urb(ar2->urb[1]);
+}
+
+static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
+{
+       struct input_dev *idev = ar2->idev;
+       u8 *data = ar2->buf[0];
+       int channel, mode;
+
+       channel = data[0] >> 4;
+
+       if (!((1 << channel) & channel_mask))
+               return;
+
+       mode = data[0] & 0x0F;
+
+       if (mode > 4) {
+               dev_err(&ar2->intf[0]->dev,
+                       "Unknown mode byte (%02x %02x %02x %02x)\n",
+                       data[3], data[2], data[1], data[0]);
+               return;
+       }
+
+       if (!((1 << mode) & mode_mask))
+               return;
+
+       input_event(idev, EV_REL, REL_X, (s8) data[1]);
+       input_event(idev, EV_REL, REL_Y, (s8) data[2]);
+       input_sync(idev);
+}
+
+static int ati_remote2_lookup(unsigned int hw_code)
+{
+       int i;
+
+       for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
+               if (ati_remote2_key_table[i].hw_code == hw_code)
+                       return i;
+
+       return -1;
+}
+
+static void ati_remote2_input_key(struct ati_remote2 *ar2)
+{
+       struct input_dev *idev = ar2->idev;
+       u8 *data = ar2->buf[1];
+       int channel, mode, hw_code, index;
+
+       channel = data[0] >> 4;
+
+       if (!((1 << channel) & channel_mask))
+               return;
+
+       mode = data[0] & 0x0F;
+
+       if (mode > 4) {
+               dev_err(&ar2->intf[1]->dev,
+                       "Unknown mode byte (%02x %02x %02x %02x)\n",
+                       data[3], data[2], data[1], data[0]);
+               return;
+       }
+
+       hw_code = data[2];
+       /*
+        * Mode keys (AUX1-AUX4, PC) all generate the same code byte.
+        * Use the mode byte to figure out which one was pressed.
+        */
+       if (hw_code == 0x3f) {
+               /*
+                * For some incomprehensible reason the mouse pad generates
+                * events which look identical to the events from the last
+                * pressed mode key. Naturally we don't want to generate key
+                * events for the mouse pad so we filter out any subsequent
+                * events from the same mode key.
+                */
+               if (ar2->mode == mode)
+                       return;
+
+               if (data[1] == 0)
+                       ar2->mode = mode;
+
+               hw_code |= mode << 8;
+       }
+
+       if (!((1 << mode) & mode_mask))
+               return;
+
+       index = ati_remote2_lookup(hw_code);
+       if (index < 0) {
+               dev_err(&ar2->intf[1]->dev,
+                       "Unknown code byte (%02x %02x %02x %02x)\n",
+                       data[3], data[2], data[1], data[0]);
+               return;
+       }
+
+       switch (data[1]) {
+       case 0: /* release */
+               break;
+       case 1: /* press */
+               ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]);
+               break;
+       case 2: /* repeat */
+
+               /* No repeat for mouse buttons. */
+               if (ati_remote2_key_table[index].key_code == BTN_LEFT ||
+                   ati_remote2_key_table[index].key_code == BTN_RIGHT)
+                       return;
+
+               if (!time_after_eq(jiffies, ar2->jiffies))
+                       return;
+
+               ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]);
+               break;
+       default:
+               dev_err(&ar2->intf[1]->dev,
+                       "Unknown state byte (%02x %02x %02x %02x)\n",
+                       data[3], data[2], data[1], data[0]);
+               return;
+       }
+
+       input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]);
+       input_sync(idev);
+}
+
+static void ati_remote2_complete_mouse(struct urb *urb)
+{
+       struct ati_remote2 *ar2 = urb->context;
+       int r;
+
+       switch (urb->status) {
+       case 0:
+               ati_remote2_input_mouse(ar2);
+               break;
+       case -ENOENT:
+       case -EILSEQ:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               dev_dbg(&ar2->intf[0]->dev,
+                       "%s(): urb status = %d\n", __FUNCTION__, urb->status);
+               return;
+       default:
+               dev_err(&ar2->intf[0]->dev,
+                       "%s(): urb status = %d\n", __FUNCTION__, urb->status);
+       }
+
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       if (r)
+               dev_err(&ar2->intf[0]->dev,
+                       "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
+}
+
+static void ati_remote2_complete_key(struct urb *urb)
+{
+       struct ati_remote2 *ar2 = urb->context;
+       int r;
+
+       switch (urb->status) {
+       case 0:
+               ati_remote2_input_key(ar2);
+               break;
+       case -ENOENT:
+       case -EILSEQ:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               dev_dbg(&ar2->intf[1]->dev,
+                       "%s(): urb status = %d\n", __FUNCTION__, urb->status);
+               return;
+       default:
+               dev_err(&ar2->intf[1]->dev,
+                       "%s(): urb status = %d\n", __FUNCTION__, urb->status);
+       }
+
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       if (r)
+               dev_err(&ar2->intf[1]->dev,
+                       "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
+}
+
+static int ati_remote2_input_init(struct ati_remote2 *ar2)
+{
+       struct input_dev *idev;
+       int i, retval;
+
+       idev = input_allocate_device();
+       if (!idev)
+               return -ENOMEM;
+
+       ar2->idev = idev;
+       input_set_drvdata(idev, ar2);
+
+       idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
+       idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+       idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
+               set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
+
+       idev->rep[REP_DELAY]  = 250;
+       idev->rep[REP_PERIOD] = 33;
+
+       idev->open = ati_remote2_open;
+       idev->close = ati_remote2_close;
+
+       idev->name = ar2->name;
+       idev->phys = ar2->phys;
+
+       usb_to_input_id(ar2->udev, &idev->id);
+       idev->dev.parent = &ar2->udev->dev;
+
+       retval = input_register_device(idev);
+       if (retval)
+               input_free_device(idev);
+
+       return retval;
+}
+
+static int ati_remote2_urb_init(struct ati_remote2 *ar2)
+{
+       struct usb_device *udev = ar2->udev;
+       int i, pipe, maxp;
+
+       for (i = 0; i < 2; i++) {
+               ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
+               if (!ar2->buf[i])
+                       return -ENOMEM;
+
+               ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+               if (!ar2->urb[i])
+                       return -ENOMEM;
+
+               pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
+               maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+               maxp = maxp > 4 ? 4 : maxp;
+
+               usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
+                                i ? ati_remote2_complete_key : ati_remote2_complete_mouse,
+                                ar2, ar2->ep[i]->bInterval);
+               ar2->urb[i]->transfer_dma = ar2->buf_dma[i];
+               ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+       }
+
+       return 0;
+}
+
+static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
+{
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               usb_free_urb(ar2->urb[i]);
+               usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
+       }
+}
+
+static int ati_remote2_setup(struct ati_remote2 *ar2)
+{
+       int r, i, channel;
+
+       /*
+        * Configure receiver to only accept input from remote "channel"
+        *  channel == 0  -> Accept input from any remote channel
+        *  channel == 1  -> Only accept input from remote channel 1
+        *  channel == 2  -> Only accept input from remote channel 2
+        *  ...
+        *  channel == 16 -> Only accept input from remote channel 16
+        */
+
+       channel = 0;
+       for (i = 0; i < 16; i++) {
+               if ((1 << i) & channel_mask) {
+                       if (!(~(1 << i) & 0xFFFF & channel_mask))
+                               channel = i + 1;
+                       break;
+               }
+       }
+
+       r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0),
+                           0x20,
+                           USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                           channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (r) {
+               dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n",
+                       __FUNCTION__, r);
+               return r;
+       }
+
+       return 0;
+}
+
+static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct usb_host_interface *alt = interface->cur_altsetting;
+       struct ati_remote2 *ar2;
+       int r;
+
+       if (alt->desc.bInterfaceNumber)
+               return -ENODEV;
+
+       ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL);
+       if (!ar2)
+               return -ENOMEM;
+
+       ar2->udev = udev;
+
+       ar2->intf[0] = interface;
+       ar2->ep[0] = &alt->endpoint[0].desc;
+
+       ar2->intf[1] = usb_ifnum_to_if(udev, 1);
+       r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
+       if (r)
+               goto fail1;
+       alt = ar2->intf[1]->cur_altsetting;
+       ar2->ep[1] = &alt->endpoint[0].desc;
+
+       r = ati_remote2_urb_init(ar2);
+       if (r)
+               goto fail2;
+
+       r = ati_remote2_setup(ar2);
+       if (r)
+               goto fail2;
+
+       usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
+       strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
+
+       strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
+
+       r = ati_remote2_input_init(ar2);
+       if (r)
+               goto fail2;
+
+       usb_set_intfdata(interface, ar2);
+
+       return 0;
+
+ fail2:
+       ati_remote2_urb_cleanup(ar2);
+
+       usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
+ fail1:
+       kfree(ar2);
+
+       return r;
+}
+
+static void ati_remote2_disconnect(struct usb_interface *interface)
+{
+       struct ati_remote2 *ar2;
+       struct usb_host_interface *alt = interface->cur_altsetting;
+
+       if (alt->desc.bInterfaceNumber)
+               return;
+
+       ar2 = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       input_unregister_device(ar2->idev);
+
+       ati_remote2_urb_cleanup(ar2);
+
+       usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
+
+       kfree(ar2);
+}
+
+static int __init ati_remote2_init(void)
+{
+       int r;
+
+       r = usb_register(&ati_remote2_driver);
+       if (r)
+               printk(KERN_ERR "ati_remote2: usb_register() = %d\n", r);
+       else
+               printk(KERN_INFO "ati_remote2: " DRIVER_DESC " " DRIVER_VERSION "\n");
+
+       return r;
+}
+
+static void __exit ati_remote2_exit(void)
+{
+       usb_deregister(&ati_remote2_driver);
+}
+
+module_init(ati_remote2_init);
+module_exit(ati_remote2_exit);
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
new file mode 100644 (file)
index 0000000..1bffc9f
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * keyspan_remote: USB driver for the Keyspan DMR
+ *
+ * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com)
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation, version 2.
+ *
+ * This driver has been put together with the support of Innosys, Inc.
+ * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product.
+ */
+
+#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/usb/input.h>
+
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR  "Michael Downey <downey@zymeta.com>"
+#define DRIVER_DESC    "Driver for the USB Keyspan remote control."
+#define DRIVER_LICENSE "GPL"
+
+/* Parameters that can be passed to the driver. */
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+/* Vendor and product ids */
+#define USB_KEYSPAN_VENDOR_ID          0x06CD
+#define USB_KEYSPAN_PRODUCT_UIA11      0x0202
+
+/* Defines for converting the data from the remote. */
+#define ZERO           0x18
+#define ZERO_MASK      0x1F    /* 5 bits for a 0 */
+#define ONE            0x3C
+#define ONE_MASK       0x3F    /* 6 bits for a 1 */
+#define SYNC           0x3F80
+#define SYNC_MASK      0x3FFF  /* 14 bits for a SYNC sequence */
+#define STOP           0x00
+#define STOP_MASK      0x1F    /* 5 bits for the STOP sequence */
+#define GAP            0xFF
+
+#define RECV_SIZE      8       /* The UIA-11 type have a 8 byte limit. */
+
+/* table of devices that work with this driver */
+static struct usb_device_id keyspan_table[] = {
+       { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) },
+       { }                                     /* Terminating entry */
+};
+
+/* Structure to store all the real stuff that a remote sends to us. */
+struct keyspan_message {
+       u16     system;
+       u8      button;
+       u8      toggle;
+};
+
+/* Structure used for all the bit testing magic needed to be done. */
+struct bit_tester {
+       u32     tester;
+       int     len;
+       int     pos;
+       int     bits_left;
+       u8      buffer[32];
+};
+
+/* Structure to hold all of our driver specific stuff */
+struct usb_keyspan {
+       char                            name[128];
+       char                            phys[64];
+       struct usb_device*              udev;
+       struct input_dev                *input;
+       struct usb_interface*           interface;
+       struct usb_endpoint_descriptor* in_endpoint;
+       struct urb*                     irq_urb;
+       int                             open;
+       dma_addr_t                      in_dma;
+       unsigned char*                  in_buffer;
+
+       /* variables used to parse messages from remote. */
+       struct bit_tester               data;
+       int                             stage;
+       int                             toggle;
+};
+
+/*
+ * Table that maps the 31 possible keycodes to input keys.
+ * Currently there are 15 and 17 button models so RESERVED codes
+ * are blank areas in the mapping.
+ */
+static const int keyspan_key_table[] = {
+       KEY_RESERVED,           /* 0 is just a place holder. */
+       KEY_RESERVED,
+       KEY_STOP,
+       KEY_PLAYCD,
+       KEY_RESERVED,
+       KEY_PREVIOUSSONG,
+       KEY_REWIND,
+       KEY_FORWARD,
+       KEY_NEXTSONG,
+       KEY_RESERVED,
+       KEY_RESERVED,
+       KEY_RESERVED,
+       KEY_PAUSE,
+       KEY_VOLUMEUP,
+       KEY_RESERVED,
+       KEY_RESERVED,
+       KEY_RESERVED,
+       KEY_VOLUMEDOWN,
+       KEY_RESERVED,
+       KEY_UP,
+       KEY_RESERVED,
+       KEY_MUTE,
+       KEY_LEFT,
+       KEY_ENTER,
+       KEY_RIGHT,
+       KEY_RESERVED,
+       KEY_RESERVED,
+       KEY_DOWN,
+       KEY_RESERVED,
+       KEY_KPASTERISK,
+       KEY_RESERVED,
+       KEY_MENU
+};
+
+static struct usb_driver keyspan_driver;
+
+/*
+ * Debug routine that prints out what we've received from the remote.
+ */
+static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/
+{
+       char codes[4 * RECV_SIZE];
+       int i;
+
+       for (i = 0; i < RECV_SIZE; i++)
+               snprintf(codes + i * 3, 4, "%02x ", dev->in_buffer[i]);
+
+       dev_info(&dev->udev->dev, "%s\n", codes);
+}
+
+/*
+ * Routine that manages the bit_tester structure.  It makes sure that there are
+ * at least bits_needed bits loaded into the tester.
+ */
+static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
+{
+       if (dev->data.bits_left >= bits_needed)
+               return 0;
+
+       /*
+        * Somehow we've missed the last message. The message will be repeated
+        * though so it's not too big a deal
+        */
+       if (dev->data.pos >= dev->data.len) {
+               dev_dbg(&dev->udev->dev,
+                       "%s - Error ran out of data. pos: %d, len: %d\n",
+                       __FUNCTION__, dev->data.pos, dev->data.len);
+               return -1;
+       }
+
+       /* Load as much as we can into the tester. */
+       while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) &&
+              (dev->data.pos < dev->data.len)) {
+               dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left);
+               dev->data.bits_left += 8;
+       }
+
+       return 0;
+}
+
+/*
+ * Routine that handles all the logic needed to parse out the message from the remote.
+ */
+static void keyspan_check_data(struct usb_keyspan *remote)
+{
+       int i;
+       int found = 0;
+       struct keyspan_message message;
+
+       switch(remote->stage) {
+       case 0:
+               /*
+                * In stage 0 we want to find the start of a message.  The remote sends a 0xFF as filler.
+                * So the first byte that isn't a FF should be the start of a new message.
+                */
+               for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i);
+
+               if (i < RECV_SIZE) {
+                       memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE);
+                       remote->data.len = RECV_SIZE;
+                       remote->data.pos = 0;
+                       remote->data.tester = 0;
+                       remote->data.bits_left = 0;
+                       remote->stage = 1;
+               }
+               break;
+
+       case 1:
+               /*
+                * Stage 1 we should have 16 bytes and should be able to detect a
+                * SYNC.  The SYNC is 14 bits, 7 0's and then 7 1's.
+                */
+               memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
+               remote->data.len += RECV_SIZE;
+
+               found = 0;
+               while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) {
+                       for (i = 0; i < 8; ++i) {
+                               if (keyspan_load_tester(remote, 14) != 0) {
+                                       remote->stage = 0;
+                                       return;
+                               }
+
+                               if ((remote->data.tester & SYNC_MASK) == SYNC) {
+                                       remote->data.tester = remote->data.tester >> 14;
+                                       remote->data.bits_left -= 14;
+                                       found = 1;
+                                       break;
+                               } else {
+                                       remote->data.tester = remote->data.tester >> 1;
+                                       --remote->data.bits_left;
+                               }
+                       }
+               }
+
+               if (!found) {
+                       remote->stage = 0;
+                       remote->data.len = 0;
+               } else {
+                       remote->stage = 2;
+               }
+               break;
+
+       case 2:
+               /*
+                * Stage 2 we should have 24 bytes which will be enough for a full
+                * message.  We need to parse out the system code, button code,
+                * toggle code, and stop.
+                */
+               memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
+               remote->data.len += RECV_SIZE;
+
+               message.system = 0;
+               for (i = 0; i < 9; i++) {
+                       keyspan_load_tester(remote, 6);
+
+                       if ((remote->data.tester & ZERO_MASK) == ZERO) {
+                               message.system = message.system << 1;
+                               remote->data.tester = remote->data.tester >> 5;
+                               remote->data.bits_left -= 5;
+                       } else if ((remote->data.tester & ONE_MASK) == ONE) {
+                               message.system = (message.system << 1) + 1;
+                               remote->data.tester = remote->data.tester >> 6;
+                               remote->data.bits_left -= 6;
+                       } else {
+                               err("%s - Unknown sequence found in system data.\n", __FUNCTION__);
+                               remote->stage = 0;
+                               return;
+                       }
+               }
+
+               message.button = 0;
+               for (i = 0; i < 5; i++) {
+                       keyspan_load_tester(remote, 6);
+
+                       if ((remote->data.tester & ZERO_MASK) == ZERO) {
+                               message.button = message.button << 1;
+                               remote->data.tester = remote->data.tester >> 5;
+                               remote->data.bits_left -= 5;
+                       } else if ((remote->data.tester & ONE_MASK) == ONE) {
+                               message.button = (message.button << 1) + 1;
+                               remote->data.tester = remote->data.tester >> 6;
+                               remote->data.bits_left -= 6;
+                       } else {
+                               err("%s - Unknown sequence found in button data.\n", __FUNCTION__);
+                               remote->stage = 0;
+                               return;
+                       }
+               }
+
+               keyspan_load_tester(remote, 6);
+               if ((remote->data.tester & ZERO_MASK) == ZERO) {
+                       message.toggle = 0;
+                       remote->data.tester = remote->data.tester >> 5;
+                       remote->data.bits_left -= 5;
+               } else if ((remote->data.tester & ONE_MASK) == ONE) {
+                       message.toggle = 1;
+                       remote->data.tester = remote->data.tester >> 6;
+                       remote->data.bits_left -= 6;
+               } else {
+                       err("%s - Error in message, invalid toggle.\n", __FUNCTION__);
+                       remote->stage = 0;
+                       return;
+               }
+
+               keyspan_load_tester(remote, 5);
+               if ((remote->data.tester & STOP_MASK) == STOP) {
+                       remote->data.tester = remote->data.tester >> 5;
+                       remote->data.bits_left -= 5;
+               } else {
+                       err("Bad message recieved, no stop bit found.\n");
+               }
+
+               dev_dbg(&remote->udev->dev,
+                       "%s found valid message: system: %d, button: %d, toggle: %d\n",
+                       __FUNCTION__, message.system, message.button, message.toggle);
+
+               if (message.toggle != remote->toggle) {
+                       input_report_key(remote->input, keyspan_key_table[message.button], 1);
+                       input_report_key(remote->input, keyspan_key_table[message.button], 0);
+                       input_sync(remote->input);
+                       remote->toggle = message.toggle;
+               }
+
+               remote->stage = 0;
+               break;
+       }
+}
+
+/*
+ * Routine for sending all the initialization messages to the remote.
+ */
+static int keyspan_setup(struct usb_device* dev)
+{
+       int retval = 0;
+
+       retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                0x11, 0x40, 0x5601, 0x0, NULL, 0, 0);
+       if (retval) {
+               dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n",
+                       __FUNCTION__, retval);
+               return(retval);
+       }
+
+       retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                0x44, 0x40, 0x0, 0x0, NULL, 0, 0);
+       if (retval) {
+               dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n",
+                       __FUNCTION__, retval);
+               return(retval);
+       }
+
+       retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                0x22, 0x40, 0x0, 0x0, NULL, 0, 0);
+       if (retval) {
+               dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n",
+                       __FUNCTION__, retval);
+               return(retval);
+       }
+
+       dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__);
+       return(retval);
+}
+
+/*
+ * Routine used to handle a new message that has come in.
+ */
+static void keyspan_irq_recv(struct urb *urb)
+{
+       struct usb_keyspan *dev = urb->context;
+       int retval;
+
+       /* Check our status in case we need to bail out early. */
+       switch (urb->status) {
+       case 0:
+               break;
+
+       /* Device went away so don't keep trying to read from it. */
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+
+       default:
+               goto resubmit;
+               break;
+       }
+
+       if (debug)
+               keyspan_print(dev);
+
+       keyspan_check_data(dev);
+
+resubmit:
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval);
+}
+
+static int keyspan_open(struct input_dev *dev)
+{
+       struct usb_keyspan *remote = input_get_drvdata(dev);
+
+       remote->irq_urb->dev = remote->udev;
+       if (usb_submit_urb(remote->irq_urb, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void keyspan_close(struct input_dev *dev)
+{
+       struct usb_keyspan *remote = input_get_drvdata(dev);
+
+       usb_kill_urb(remote->irq_urb);
+}
+
+static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface)
+{
+
+       struct usb_endpoint_descriptor *endpoint;
+       int i;
+
+       for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+               endpoint = &iface->endpoint[i].desc;
+
+               if (usb_endpoint_is_int_in(endpoint)) {
+                       /* we found our interrupt in endpoint */
+                       return endpoint;
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * Routine that sets up the driver to handle a specific USB device detected on the bus.
+ */
+static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_keyspan *remote;
+       struct input_dev *input_dev;
+       int i, error;
+
+       endpoint = keyspan_get_in_endpoint(interface->cur_altsetting);
+       if (!endpoint)
+               return -ENODEV;
+
+       remote = kzalloc(sizeof(*remote), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!remote || !input_dev) {
+               error = -ENOMEM;
+               goto fail1;
+       }
+
+       remote->udev = udev;
+       remote->input = input_dev;
+       remote->interface = interface;
+       remote->in_endpoint = endpoint;
+       remote->toggle = -1;    /* Set to -1 so we will always not match the toggle from the first remote message. */
+
+       remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
+       if (!remote->in_buffer) {
+               error = -ENOMEM;
+               goto fail1;
+       }
+
+       remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!remote->irq_urb) {
+               error = -ENOMEM;
+               goto fail2;
+       }
+
+       error = keyspan_setup(udev);
+       if (error) {
+               error = -ENODEV;
+               goto fail3;
+       }
+
+       if (udev->manufacturer)
+               strlcpy(remote->name, udev->manufacturer, sizeof(remote->name));
+
+       if (udev->product) {
+               if (udev->manufacturer)
+                       strlcat(remote->name, " ", sizeof(remote->name));
+               strlcat(remote->name, udev->product, sizeof(remote->name));
+       }
+
+       if (!strlen(remote->name))
+               snprintf(remote->name, sizeof(remote->name),
+                        "USB Keyspan Remote %04x:%04x",
+                        le16_to_cpu(udev->descriptor.idVendor),
+                        le16_to_cpu(udev->descriptor.idProduct));
+
+       usb_make_path(udev, remote->phys, sizeof(remote->phys));
+       strlcat(remote->phys, "/input0", sizeof(remote->phys));
+
+       input_dev->name = remote->name;
+       input_dev->phys = remote->phys;
+       usb_to_input_id(udev, &input_dev->id);
+       input_dev->dev.parent = &interface->dev;
+
+       input_dev->evbit[0] = BIT(EV_KEY);              /* We will only report KEY events. */
+       for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++)
+               if (keyspan_key_table[i] != KEY_RESERVED)
+                       set_bit(keyspan_key_table[i], input_dev->keybit);
+
+       input_set_drvdata(input_dev, remote);
+
+       input_dev->open = keyspan_open;
+       input_dev->close = keyspan_close;
+
+       /*
+        * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open()
+        */
+       usb_fill_int_urb(remote->irq_urb,
+                        remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress),
+                        remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote,
+                        remote->in_endpoint->bInterval);
+       remote->irq_urb->transfer_dma = remote->in_dma;
+       remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* we can register the device now, as it is ready */
+       error = input_register_device(remote->input);
+       if (error)
+               goto fail3;
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, remote);
+
+       return 0;
+
+ fail3:        usb_free_urb(remote->irq_urb);
+ fail2:        usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+ fail1:        kfree(remote);
+       input_free_device(input_dev);
+
+       return error;
+}
+
+/*
+ * Routine called when a device is disconnected from the USB.
+ */
+static void keyspan_disconnect(struct usb_interface *interface)
+{
+       struct usb_keyspan *remote;
+
+       remote = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       if (remote) {   /* We have a valid driver structure so clean up everything we allocated. */
+               input_unregister_device(remote->input);
+               usb_kill_urb(remote->irq_urb);
+               usb_free_urb(remote->irq_urb);
+               usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+               kfree(remote);
+       }
+}
+
+/*
+ * Standard driver set up sections
+ */
+static struct usb_driver keyspan_driver =
+{
+       .name =         "keyspan_remote",
+       .probe =        keyspan_probe,
+       .disconnect =   keyspan_disconnect,
+       .id_table =     keyspan_table
+};
+
+static int __init usb_keyspan_init(void)
+{
+       int result;
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&keyspan_driver);
+       if (result)
+               err("usb_register failed. Error number %d\n", result);
+
+       return result;
+}
+
+static void __exit usb_keyspan_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&keyspan_driver);
+}
+
+module_init(usb_keyspan_init);
+module_exit(usb_keyspan_exit);
+
+MODULE_DEVICE_TABLE(usb, keyspan_table);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/input/misc/map_to_7segment.h b/drivers/input/misc/map_to_7segment.h
new file mode 100644 (file)
index 0000000..a424094
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * drivers/usb/input/map_to_7segment.h
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MAP_TO_7SEGMENT_H
+#define MAP_TO_7SEGMENT_H
+
+/* This file provides translation primitives and tables for the conversion
+ * of (ASCII) characters to a 7-segments notation.
+ *
+ * The 7 segment's wikipedia notation below is used as standard.
+ * See: http://en.wikipedia.org/wiki/Seven_segment_display
+ *
+ * Notation:   +-a-+
+ *             f   b
+ *             +-g-+
+ *             e   c
+ *             +-d-+
+ *
+ * Usage:
+ *
+ *   Register a map variable, and fill it with a character set:
+ *     static SEG7_DEFAULT_MAP(map_seg7);
+ *
+ *
+ *   Then use for conversion:
+ *     seg7 = map_to_seg7(&map_seg7, some_char);
+ *     ...
+ *
+ * In device drivers it is recommended, if required, to make the char map
+ * accessible via the sysfs interface using the following scheme:
+ *
+ * static ssize_t show_map(struct device *dev, char *buf) {
+ *     memcpy(buf, &map_seg7, sizeof(map_seg7));
+ *     return sizeof(map_seg7);
+ * }
+ * static ssize_t store_map(struct device *dev, const char *buf, size_t cnt) {
+ *     if(cnt != sizeof(map_seg7))
+ *             return -EINVAL;
+ *     memcpy(&map_seg7, buf, cnt);
+ *     return cnt;
+ * }
+ * static DEVICE_ATTR(map_seg7, PERMS_RW, show_map, store_map);
+ *
+ * History:
+ * 2005-05-31  RFC linux-kernel@vger.kernel.org
+ */
+#include <linux/errno.h>
+
+
+#define BIT_SEG7_A             0
+#define BIT_SEG7_B             1
+#define BIT_SEG7_C             2
+#define BIT_SEG7_D             3
+#define BIT_SEG7_E             4
+#define BIT_SEG7_F             5
+#define BIT_SEG7_G             6
+#define BIT_SEG7_RESERVED      7
+
+struct seg7_conversion_map {
+       unsigned char   table[128];
+};
+
+static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
+{
+       return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL;
+}
+
+#define SEG7_CONVERSION_MAP(_name, _map)       \
+       struct seg7_conversion_map _name = { .table = { _map } }
+
+/*
+ * It is recommended to use a facility that allows user space to redefine
+ * custom character sets for LCD devices. Please use a sysfs interface
+ * as described above.
+ */
+#define MAP_TO_SEG7_SYSFS_FILE "map_seg7"
+
+/*******************************************************************************
+ * ASCII conversion table
+ ******************************************************************************/
+
+#define _SEG7(l,a,b,c,d,e,f,g) \
+      (        a<<BIT_SEG7_A | b<<BIT_SEG7_B | c<<BIT_SEG7_C | d<<BIT_SEG7_D | \
+       e<<BIT_SEG7_E | f<<BIT_SEG7_F | g<<BIT_SEG7_G )
+
+#define _MAP_0_32_ASCII_SEG7_NON_PRINTABLE     \
+       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+#define _MAP_33_47_ASCII_SEG7_SYMBOL           \
+ _SEG7('!',0,0,0,0,1,1,0), _SEG7('"',0,1,0,0,0,1,0), _SEG7('#',0,1,1,0,1,1,0),\
+ _SEG7('$',1,0,1,1,0,1,1), _SEG7('%',0,0,1,0,0,1,0), _SEG7('&',1,0,1,1,1,1,1),\
+ _SEG7('\'',0,0,0,0,0,1,0),_SEG7('(',1,0,0,1,1,1,0), _SEG7(')',1,1,1,1,0,0,0),\
+ _SEG7('*',0,1,1,0,1,1,1), _SEG7('+',0,1,1,0,0,0,1), _SEG7(',',0,0,0,0,1,0,0),\
+ _SEG7('-',0,0,0,0,0,0,1), _SEG7('.',0,0,0,0,1,0,0), _SEG7('/',0,1,0,0,1,0,1),
+
+#define _MAP_48_57_ASCII_SEG7_NUMERIC          \
+ _SEG7('0',1,1,1,1,1,1,0), _SEG7('1',0,1,1,0,0,0,0), _SEG7('2',1,1,0,1,1,0,1),\
+ _SEG7('3',1,1,1,1,0,0,1), _SEG7('4',0,1,1,0,0,1,1), _SEG7('5',1,0,1,1,0,1,1),\
+ _SEG7('6',1,0,1,1,1,1,1), _SEG7('7',1,1,1,0,0,0,0), _SEG7('8',1,1,1,1,1,1,1),\
+ _SEG7('9',1,1,1,1,0,1,1),
+
+#define _MAP_58_64_ASCII_SEG7_SYMBOL           \
+ _SEG7(':',0,0,0,1,0,0,1), _SEG7(';',0,0,0,1,0,0,1), _SEG7('<',1,0,0,0,0,1,1),\
+ _SEG7('=',0,0,0,1,0,0,1), _SEG7('>',1,1,0,0,0,0,1), _SEG7('?',1,1,1,0,0,1,0),\
+ _SEG7('@',1,1,0,1,1,1,1),
+
+#define _MAP_65_90_ASCII_SEG7_ALPHA_UPPR       \
+ _SEG7('A',1,1,1,0,1,1,1), _SEG7('B',1,1,1,1,1,1,1), _SEG7('C',1,0,0,1,1,1,0),\
+ _SEG7('D',1,1,1,1,1,1,0), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
+ _SEG7('G',1,1,1,1,0,1,1), _SEG7('H',0,1,1,0,1,1,1), _SEG7('I',0,1,1,0,0,0,0),\
+ _SEG7('J',0,1,1,1,0,0,0), _SEG7('K',0,1,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
+ _SEG7('M',1,1,1,0,1,1,0), _SEG7('N',1,1,1,0,1,1,0), _SEG7('O',1,1,1,1,1,1,0),\
+ _SEG7('P',1,1,0,0,1,1,1), _SEG7('Q',1,1,1,1,1,1,0), _SEG7('R',1,1,1,0,1,1,1),\
+ _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('U',0,1,1,1,1,1,0),\
+ _SEG7('V',0,1,1,1,1,1,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
+ _SEG7('Y',0,1,1,0,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
+
+#define _MAP_91_96_ASCII_SEG7_SYMBOL           \
+ _SEG7('[',1,0,0,1,1,1,0), _SEG7('\\',0,0,1,0,0,1,1),_SEG7(']',1,1,1,1,0,0,0),\
+ _SEG7('^',1,1,0,0,0,1,0), _SEG7('_',0,0,0,1,0,0,0), _SEG7('`',0,1,0,0,0,0,0),
+
+#define _MAP_97_122_ASCII_SEG7_ALPHA_LOWER     \
+ _SEG7('A',1,1,1,0,1,1,1), _SEG7('b',0,0,1,1,1,1,1), _SEG7('c',0,0,0,1,1,0,1),\
+ _SEG7('d',0,1,1,1,1,0,1), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
+ _SEG7('G',1,1,1,1,0,1,1), _SEG7('h',0,0,1,0,1,1,1), _SEG7('i',0,0,1,0,0,0,0),\
+ _SEG7('j',0,0,1,1,0,0,0), _SEG7('k',0,0,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
+ _SEG7('M',1,1,1,0,1,1,0), _SEG7('n',0,0,1,0,1,0,1), _SEG7('o',0,0,1,1,1,0,1),\
+ _SEG7('P',1,1,0,0,1,1,1), _SEG7('q',1,1,1,0,0,1,1), _SEG7('r',0,0,0,0,1,0,1),\
+ _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('u',0,0,1,1,1,0,0),\
+ _SEG7('v',0,0,1,1,1,0,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
+ _SEG7('y',0,1,1,1,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
+
+#define _MAP_123_126_ASCII_SEG7_SYMBOL         \
+ _SEG7('{',1,0,0,1,1,1,0), _SEG7('|',0,0,0,0,1,1,0), _SEG7('}',1,1,1,1,0,0,0),\
+ _SEG7('~',1,0,0,0,0,0,0),
+
+/* Maps */
+
+/* This set tries to map as close as possible to the visible characteristics
+ * of the ASCII symbol, lowercase and uppercase letters may differ in
+ * presentation on the display.
+ */
+#define MAP_ASCII7SEG_ALPHANUM                 \
+       _MAP_0_32_ASCII_SEG7_NON_PRINTABLE      \
+       _MAP_33_47_ASCII_SEG7_SYMBOL            \
+       _MAP_48_57_ASCII_SEG7_NUMERIC           \
+       _MAP_58_64_ASCII_SEG7_SYMBOL            \
+       _MAP_65_90_ASCII_SEG7_ALPHA_UPPR        \
+       _MAP_91_96_ASCII_SEG7_SYMBOL            \
+       _MAP_97_122_ASCII_SEG7_ALPHA_LOWER      \
+       _MAP_123_126_ASCII_SEG7_SYMBOL
+
+/* This set tries to map as close as possible to the symbolic characteristics
+ * of the ASCII character for maximum discrimination.
+ * For now this means all alpha chars are in lower case representations.
+ * (This for example facilitates the use of hex numbers with uppercase input.)
+ */
+#define MAP_ASCII7SEG_ALPHANUM_LC                      \
+       _MAP_0_32_ASCII_SEG7_NON_PRINTABLE      \
+       _MAP_33_47_ASCII_SEG7_SYMBOL            \
+       _MAP_48_57_ASCII_SEG7_NUMERIC           \
+       _MAP_58_64_ASCII_SEG7_SYMBOL            \
+       _MAP_97_122_ASCII_SEG7_ALPHA_LOWER      \
+       _MAP_91_96_ASCII_SEG7_SYMBOL            \
+       _MAP_97_122_ASCII_SEG7_ALPHA_LOWER      \
+       _MAP_123_126_ASCII_SEG7_SYMBOL
+
+#define SEG7_DEFAULT_MAP(_name)                \
+       SEG7_CONVERSION_MAP(_name,MAP_ASCII7SEG_ALPHANUM)
+
+#endif /* MAP_TO_7SEGMENT_H */
+
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
new file mode 100644 (file)
index 0000000..448a470
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
+ *
+ * v1.1, (c)2002 William R Sowerbutts <will@sowerbutts.com>
+ *
+ * This device is a anodised aluminium knob which connects over USB. It can measure
+ * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
+ * a spring for automatic release. The base contains a pair of LEDs which illuminate
+ * the translucent base. It rotates without limit and reports its relative rotation
+ * back to the host when polled by the USB controller.
+ *
+ * Testing with the knob I have has shown that it measures approximately 94 "clicks"
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
+ * a variable speed cordless electric drill) has shown that the device can measure
+ * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
+ * the host. If it counts more than 7 clicks before it is polled, it will wrap back
+ * to zero and start counting again. This was at quite high speed, however, almost
+ * certainly faster than the human hand could turn it. Griffin say that it loses a
+ * pulse or two on a direction change; the granularity is so fine that I never
+ * noticed this in practice.
+ *
+ * The device's microcontroller can be programmed to set the LED to either a constant
+ * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
+ *
+ * Griffin were very happy to provide documentation and free hardware for development.
+ *
+ * Some userspace tools are available on the web: http://sowerbutts.com/powermate/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/usb/input.h>
+
+#define POWERMATE_VENDOR       0x077d  /* Griffin Technology, Inc. */
+#define POWERMATE_PRODUCT_NEW  0x0410  /* Griffin PowerMate */
+#define POWERMATE_PRODUCT_OLD  0x04AA  /* Griffin soundKnob */
+
+#define CONTOUR_VENDOR         0x05f3  /* Contour Design, Inc. */
+#define CONTOUR_JOG            0x0240  /* Jog and Shuttle */
+
+/* these are the command codes we send to the device */
+#define SET_STATIC_BRIGHTNESS  0x01
+#define SET_PULSE_ASLEEP       0x02
+#define SET_PULSE_AWAKE        0x03
+#define SET_PULSE_MODE         0x04
+
+/* these refer to bits in the powermate_device's requires_update field. */
+#define UPDATE_STATIC_BRIGHTNESS (1<<0)
+#define UPDATE_PULSE_ASLEEP      (1<<1)
+#define UPDATE_PULSE_AWAKE       (1<<2)
+#define UPDATE_PULSE_MODE        (1<<3)
+
+/* at least two versions of the hardware exist, with differing payload
+   sizes. the first three bytes always contain the "interesting" data in
+   the relevant format. */
+#define POWERMATE_PAYLOAD_SIZE_MAX 6
+#define POWERMATE_PAYLOAD_SIZE_MIN 3
+struct powermate_device {
+       signed char *data;
+       dma_addr_t data_dma;
+       struct urb *irq, *config;
+       struct usb_ctrlrequest *configcr;
+       dma_addr_t configcr_dma;
+       struct usb_device *udev;
+       struct input_dev *input;
+       spinlock_t lock;
+       int static_brightness;
+       int pulse_speed;
+       int pulse_table;
+       int pulse_asleep;
+       int pulse_awake;
+       int requires_update; // physical settings which are out of sync
+       char phys[64];
+};
+
+static char pm_name_powermate[] = "Griffin PowerMate";
+static char pm_name_soundknob[] = "Griffin SoundKnob";
+
+static void powermate_config_complete(struct urb *urb);
+
+/* Callback for data arriving from the PowerMate over the USB interrupt pipe */
+static void powermate_irq(struct urb *urb)
+{
+       struct powermate_device *pm = urb->context;
+       int retval;
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       /* handle updates to device state */
+       input_report_key(pm->input, BTN_0, pm->data[0] & 0x01);
+       input_report_rel(pm->input, REL_DIAL, pm->data[1]);
+       input_sync(pm->input);
+
+exit:
+       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       if (retval)
+               err ("%s - usb_submit_urb failed with result %d",
+                    __FUNCTION__, retval);
+}
+
+/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
+static void powermate_sync_state(struct powermate_device *pm)
+{
+       if (pm->requires_update == 0)
+               return; /* no updates are required */
+       if (pm->config->status == -EINPROGRESS)
+               return; /* an update is already in progress; it'll issue this update when it completes */
+
+       if (pm->requires_update & UPDATE_PULSE_ASLEEP){
+               pm->configcr->wValue = cpu_to_le16( SET_PULSE_ASLEEP );
+               pm->configcr->wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
+               pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
+       }else if (pm->requires_update & UPDATE_PULSE_AWAKE){
+               pm->configcr->wValue = cpu_to_le16( SET_PULSE_AWAKE );
+               pm->configcr->wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
+               pm->requires_update &= ~UPDATE_PULSE_AWAKE;
+       }else if (pm->requires_update & UPDATE_PULSE_MODE){
+               int op, arg;
+               /* the powermate takes an operation and an argument for its pulse algorithm.
+                  the operation can be:
+                  0: divide the speed
+                  1: pulse at normal speed
+                  2: multiply the speed
+                  the argument only has an effect for operations 0 and 2, and ranges between
+                  1 (least effect) to 255 (maximum effect).
+
+                  thus, several states are equivalent and are coalesced into one state.
+
+                  we map this onto a range from 0 to 510, with:
+                  0 -- 254    -- use divide (0 = slowest)
+                  255         -- use normal speed
+                  256 -- 510  -- use multiple (510 = fastest).
+
+                  Only values of 'arg' quite close to 255 are particularly useful/spectacular.
+               */
+               if (pm->pulse_speed < 255) {
+                       op = 0;                   // divide
+                       arg = 255 - pm->pulse_speed;
+               } else if (pm->pulse_speed > 255) {
+                       op = 2;                   // multiply
+                       arg = pm->pulse_speed - 255;
+               } else {
+                       op = 1;                   // normal speed
+                       arg = 0;                  // can be any value
+               }
+               pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
+               pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op );
+               pm->requires_update &= ~UPDATE_PULSE_MODE;
+       } else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) {
+               pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
+               pm->configcr->wIndex = cpu_to_le16( pm->static_brightness );
+               pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
+       } else {
+               printk(KERN_ERR "powermate: unknown update required");
+               pm->requires_update = 0; /* fudge the bug */
+               return;
+       }
+
+/*     printk("powermate: %04x %04x\n", pm->configcr->wValue, pm->configcr->wIndex); */
+
+       pm->configcr->bRequestType = 0x41; /* vendor request */
+       pm->configcr->bRequest = 0x01;
+       pm->configcr->wLength = 0;
+
+       usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0),
+                            (void *) pm->configcr, NULL, 0,
+                            powermate_config_complete, pm);
+       pm->config->setup_dma = pm->configcr_dma;
+       pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP;
+
+       if (usb_submit_urb(pm->config, GFP_ATOMIC))
+               printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
+}
+
+/* Called when our asynchronous control message completes. We may need to issue another immediately */
+static void powermate_config_complete(struct urb *urb)
+{
+       struct powermate_device *pm = urb->context;
+       unsigned long flags;
+
+       if (urb->status)
+               printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
+
+       spin_lock_irqsave(&pm->lock, flags);
+       powermate_sync_state(pm);
+       spin_unlock_irqrestore(&pm->lock, flags);
+}
+
+/* Set the LED up as described and begin the sync with the hardware if required */
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
+                               int pulse_table, int pulse_asleep, int pulse_awake)
+{
+       unsigned long flags;
+
+       if (pulse_speed < 0)
+               pulse_speed = 0;
+       if (pulse_table < 0)
+               pulse_table = 0;
+       if (pulse_speed > 510)
+               pulse_speed = 510;
+       if (pulse_table > 2)
+               pulse_table = 2;
+
+       pulse_asleep = !!pulse_asleep;
+       pulse_awake = !!pulse_awake;
+
+
+       spin_lock_irqsave(&pm->lock, flags);
+
+       /* mark state updates which are required */
+       if (static_brightness != pm->static_brightness) {
+               pm->static_brightness = static_brightness;
+               pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
+       }
+       if (pulse_asleep != pm->pulse_asleep) {
+               pm->pulse_asleep = pulse_asleep;
+               pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS);
+       }
+       if (pulse_awake != pm->pulse_awake) {
+               pm->pulse_awake = pulse_awake;
+               pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS);
+       }
+       if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) {
+               pm->pulse_speed = pulse_speed;
+               pm->pulse_table = pulse_table;
+               pm->requires_update |= UPDATE_PULSE_MODE;
+       }
+
+       powermate_sync_state(pm);
+
+       spin_unlock_irqrestore(&pm->lock, flags);
+}
+
+/* Callback from the Input layer when an event arrives from userspace to configure the LED */
+static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
+{
+       unsigned int command = (unsigned int)_value;
+       struct powermate_device *pm = input_get_drvdata(dev);
+
+       if (type == EV_MSC && code == MSC_PULSELED){
+               /*
+                   bits  0- 7: 8 bits: LED brightness
+                   bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
+                   bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
+                   bit     19: 1 bit : pulse whilst asleep?
+                   bit     20: 1 bit : pulse constantly?
+               */
+               int static_brightness = command & 0xFF;   // bits 0-7
+               int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
+               int pulse_table = (command >> 17) & 0x3;  // bits 17-18
+               int pulse_asleep = (command >> 19) & 0x1; // bit 19
+               int pulse_awake  = (command >> 20) & 0x1; // bit 20
+
+               powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
+       }
+
+       return 0;
+}
+
+static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm)
+{
+       pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+                                   GFP_ATOMIC, &pm->data_dma);
+       if (!pm->data)
+               return -1;
+
+       pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)),
+                                       GFP_ATOMIC, &pm->configcr_dma);
+       if (!pm->configcr)
+               return -1;
+
+       return 0;
+}
+
+static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm)
+{
+       usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+                       pm->data, pm->data_dma);
+       usb_buffer_free(udev, sizeof(*(pm->configcr)),
+                       pm->configcr, pm->configcr_dma);
+}
+
+/* Called whenever a USB device matching one in our supported devices table is connected */
+static int powermate_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev (intf);
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct powermate_device *pm;
+       struct input_dev *input_dev;
+       int pipe, maxp;
+       int error = -ENOMEM;
+
+       interface = intf->cur_altsetting;
+       endpoint = &interface->endpoint[0].desc;
+       if (!usb_endpoint_is_int_in(endpoint))
+               return -EIO;
+
+       usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+               0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               0, interface->desc.bInterfaceNumber, NULL, 0,
+               USB_CTRL_SET_TIMEOUT);
+
+       pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!pm || !input_dev)
+               goto fail1;
+
+       if (powermate_alloc_buffers(udev, pm))
+               goto fail2;
+
+       pm->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!pm->irq)
+               goto fail2;
+
+       pm->config = usb_alloc_urb(0, GFP_KERNEL);
+       if (!pm->config)
+               goto fail3;
+
+       pm->udev = udev;
+       pm->input = input_dev;
+
+       usb_make_path(udev, pm->phys, sizeof(pm->phys));
+       strlcpy(pm->phys, "/input0", sizeof(pm->phys));
+
+       spin_lock_init(&pm->lock);
+
+       switch (le16_to_cpu(udev->descriptor.idProduct)) {
+       case POWERMATE_PRODUCT_NEW:
+               input_dev->name = pm_name_powermate;
+               break;
+       case POWERMATE_PRODUCT_OLD:
+               input_dev->name = pm_name_soundknob;
+               break;
+       default:
+               input_dev->name = pm_name_soundknob;
+               printk(KERN_WARNING "powermate: unknown product id %04x\n",
+                      le16_to_cpu(udev->descriptor.idProduct));
+       }
+
+       input_dev->phys = pm->phys;
+       usb_to_input_id(udev, &input_dev->id);
+       input_dev->dev.parent = &intf->dev;
+
+       input_set_drvdata(input_dev, pm);
+
+       input_dev->event = powermate_input_event;
+
+       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
+       input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+       input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
+       input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
+
+       /* get a handle to the interrupt data pipe */
+       pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+       if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) {
+               printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n",
+                       POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp);
+               maxp = POWERMATE_PAYLOAD_SIZE_MAX;
+       }
+
+       usb_fill_int_urb(pm->irq, udev, pipe, pm->data,
+                        maxp, powermate_irq,
+                        pm, endpoint->bInterval);
+       pm->irq->transfer_dma = pm->data_dma;
+       pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* register our interrupt URB with the USB system */
+       if (usb_submit_urb(pm->irq, GFP_KERNEL)) {
+               error = -EIO;
+               goto fail4;
+       }
+
+       error = input_register_device(pm->input);
+       if (error)
+               goto fail5;
+
+
+       /* force an update of everything */
+       pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
+       powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
+
+       usb_set_intfdata(intf, pm);
+       return 0;
+
+ fail5:        usb_kill_urb(pm->irq);
+ fail4:        usb_free_urb(pm->config);
+ fail3:        usb_free_urb(pm->irq);
+ fail2:        powermate_free_buffers(udev, pm);
+ fail1:        input_free_device(input_dev);
+       kfree(pm);
+       return error;
+}
+
+/* Called when a USB device we've accepted ownership of is removed */
+static void powermate_disconnect(struct usb_interface *intf)
+{
+       struct powermate_device *pm = usb_get_intfdata (intf);
+
+       usb_set_intfdata(intf, NULL);
+       if (pm) {
+               pm->requires_update = 0;
+               usb_kill_urb(pm->irq);
+               input_unregister_device(pm->input);
+               usb_free_urb(pm->irq);
+               usb_free_urb(pm->config);
+               powermate_free_buffers(interface_to_usbdev(intf), pm);
+
+               kfree(pm);
+       }
+}
+
+static struct usb_device_id powermate_devices [] = {
+       { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
+       { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
+       { USB_DEVICE(CONTOUR_VENDOR, CONTOUR_JOG) },
+       { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, powermate_devices);
+
+static struct usb_driver powermate_driver = {
+        .name =         "powermate",
+        .probe =        powermate_probe,
+        .disconnect =   powermate_disconnect,
+        .id_table =     powermate_devices,
+};
+
+static int __init powermate_init(void)
+{
+       return usb_register(&powermate_driver);
+}
+
+static void __exit powermate_cleanup(void)
+{
+       usb_deregister(&powermate_driver);
+}
+
+module_init(powermate_init);
+module_exit(powermate_cleanup);
+
+MODULE_AUTHOR( "William R Sowerbutts" );
+MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
new file mode 100644 (file)
index 0000000..ab15880
--- /dev/null
@@ -0,0 +1,1004 @@
+/*
+ * drivers/usb/input/yealink.c
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * Description:
+ *   Driver for the USB-P1K voip usb phone.
+ *   This device is produced by Yealink Network Technology Co Ltd
+ *   but may be branded under several names:
+ *     - Yealink usb-p1k
+ *     - Tiptel 115
+ *     - ...
+ *
+ * This driver is based on:
+ *   - the usbb2k-api  http://savannah.nongnu.org/projects/usbb2k-api/
+ *   - information from        http://memeteau.free.fr/usbb2k
+ *   - the xpad-driver drivers/input/joystick/xpad.c
+ *
+ * Thanks to:
+ *   - Olivier Vandorpe, for providing the usbb2k-api.
+ *   - Martin Diehl, for spotting my memory allocation bug.
+ *
+ * History:
+ *   20050527 henk     First version, functional keyboard. Keyboard events
+ *                     will pop-up on the ../input/eventX bus.
+ *   20050531 henk     Added led, LCD, dialtone and sysfs interface.
+ *   20050610 henk     Cleanups, make it ready for public consumption.
+ *   20050630 henk     Cleanups, fixes in response to comments.
+ *   20050701 henk     sysfs write serialisation, fix potential unload races
+ *   20050801 henk     Added ringtone, restructure USB
+ *   20050816 henk     Merge 2.6.13-rc6
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/usb/input.h>
+
+#include "map_to_7segment.h"
+#include "yealink.h"
+
+#define DRIVER_VERSION "yld-20051230"
+#define DRIVER_AUTHOR "Henk Vergonet"
+#define DRIVER_DESC "Yealink phone driver"
+
+#define YEALINK_POLLING_FREQUENCY      10      /* in [Hz] */
+
+struct yld_status {
+       u8      lcd[24];
+       u8      led;
+       u8      dialtone;
+       u8      ringtone;
+       u8      keynum;
+} __attribute__ ((packed));
+
+/*
+ * Register the LCD segment and icon map
+ */
+#define _LOC(k,l)      { .a = (k), .m = (l) }
+#define _SEG(t, a, am, b, bm, c, cm, d, dm, e, em, f, fm, g, gm)       \
+       { .type = (t),                                                  \
+         .u = { .s = { _LOC(a, am), _LOC(b, bm), _LOC(c, cm),          \
+                       _LOC(d, dm), _LOC(e, em), _LOC(g, gm),          \
+                       _LOC(f, fm) } } }
+#define _PIC(t, h, hm, n)                                              \
+       { .type = (t),                                                  \
+         .u = { .p = { .name = (n), .a = (h), .m = (hm) } } }
+
+static const struct lcd_segment_map {
+       char    type;
+       union {
+               struct pictogram_map {
+                       u8      a,m;
+                       char    name[10];
+               }       p;
+               struct segment_map {
+                       u8      a,m;
+               } s[7];
+       } u;
+} lcdMap[] = {
+#include "yealink.h"
+};
+
+struct yealink_dev {
+       struct input_dev *idev;         /* input device */
+       struct usb_device *udev;        /* usb device */
+
+       /* irq input channel */
+       struct yld_ctl_packet   *irq_data;
+       dma_addr_t              irq_dma;
+       struct urb              *urb_irq;
+
+       /* control output channel */
+       struct yld_ctl_packet   *ctl_data;
+       dma_addr_t              ctl_dma;
+       struct usb_ctrlrequest  *ctl_req;
+       dma_addr_t              ctl_req_dma;
+       struct urb              *urb_ctl;
+
+       char phys[64];                  /* physical device path */
+
+       u8 lcdMap[ARRAY_SIZE(lcdMap)];  /* state of LCD, LED ... */
+       int key_code;                   /* last reported key     */
+
+       int     stat_ix;
+       union {
+               struct yld_status s;
+               u8                b[sizeof(struct yld_status)];
+       } master, copy;
+};
+
+
+/*******************************************************************************
+ * Yealink lcd interface
+ ******************************************************************************/
+
+/*
+ * Register a default 7 segment character set
+ */
+static SEG7_DEFAULT_MAP(map_seg7);
+
+ /* Display a char,
+  * char '\9' and '\n' are placeholders and do not overwrite the original text.
+  * A space will always hide an icon.
+  */
+static int setChar(struct yealink_dev *yld, int el, int chr)
+{
+       int i, a, m, val;
+
+       if (el >= ARRAY_SIZE(lcdMap))
+               return -EINVAL;
+
+       if (chr == '\t' || chr == '\n')
+           return 0;
+
+       yld->lcdMap[el] = chr;
+
+       if (lcdMap[el].type == '.') {
+               a = lcdMap[el].u.p.a;
+               m = lcdMap[el].u.p.m;
+               if (chr != ' ')
+                       yld->master.b[a] |= m;
+               else
+                       yld->master.b[a] &= ~m;
+               return 0;
+       }
+
+       val = map_to_seg7(&map_seg7, chr);
+       for (i = 0; i < ARRAY_SIZE(lcdMap[0].u.s); i++) {
+               m = lcdMap[el].u.s[i].m;
+
+               if (m == 0)
+                       continue;
+
+               a = lcdMap[el].u.s[i].a;
+               if (val & 1)
+                       yld->master.b[a] |= m;
+               else
+                       yld->master.b[a] &= ~m;
+               val = val >> 1;
+       }
+       return 0;
+};
+
+/*******************************************************************************
+ * Yealink key interface
+ ******************************************************************************/
+
+/* Map device buttons to internal key events.
+ *
+ * USB-P1K button layout:
+ *
+ *             up
+ *       IN           OUT
+ *            down
+ *
+ *     pickup   C    hangup
+ *       1      2      3
+ *       4      5      6
+ *       7      8      9
+ *       *      0      #
+ *
+ * The "up" and "down" keys, are symbolised by arrows on the button.
+ * The "pickup" and "hangup" keys are symbolised by a green and red phone
+ * on the button.
+ */
+static int map_p1k_to_key(int scancode)
+{
+       switch(scancode) {              /* phone key:   */
+       case 0x23: return KEY_LEFT;     /*   IN         */
+       case 0x33: return KEY_UP;       /*   up         */
+       case 0x04: return KEY_RIGHT;    /*   OUT        */
+       case 0x24: return KEY_DOWN;     /*   down       */
+       case 0x03: return KEY_ENTER;    /*   pickup     */
+       case 0x14: return KEY_BACKSPACE; /*  C          */
+       case 0x13: return KEY_ESC;      /*   hangup     */
+       case 0x00: return KEY_1;        /*   1          */
+       case 0x01: return KEY_2;        /*   2          */
+       case 0x02: return KEY_3;        /*   3          */
+       case 0x10: return KEY_4;        /*   4          */
+       case 0x11: return KEY_5;        /*   5          */
+       case 0x12: return KEY_6;        /*   6          */
+       case 0x20: return KEY_7;        /*   7          */
+       case 0x21: return KEY_8;        /*   8          */
+       case 0x22: return KEY_9;        /*   9          */
+       case 0x30: return KEY_KPASTERISK; /* *          */
+       case 0x31: return KEY_0;        /*   0          */
+       case 0x32: return KEY_LEFTSHIFT |
+                         KEY_3 << 8;   /*   #          */
+       }
+       return -EINVAL;
+}
+
+/* Completes a request by converting the data into events for the
+ * input subsystem.
+ *
+ * The key parameter can be cascaded: key2 << 8 | key1
+ */
+static void report_key(struct yealink_dev *yld, int key)
+{
+       struct input_dev *idev = yld->idev;
+
+       if (yld->key_code >= 0) {
+               /* old key up */
+               input_report_key(idev, yld->key_code & 0xff, 0);
+               if (yld->key_code >> 8)
+                       input_report_key(idev, yld->key_code >> 8, 0);
+       }
+
+       yld->key_code = key;
+       if (key >= 0) {
+               /* new valid key */
+               input_report_key(idev, key & 0xff, 1);
+               if (key >> 8)
+                       input_report_key(idev, key >> 8, 1);
+       }
+       input_sync(idev);
+}
+
+/*******************************************************************************
+ * Yealink usb communication interface
+ ******************************************************************************/
+
+static int yealink_cmd(struct yealink_dev *yld, struct yld_ctl_packet *p)
+{
+       u8      *buf = (u8 *)p;
+       int     i;
+       u8      sum = 0;
+
+       for(i=0; i<USB_PKT_LEN-1; i++)
+               sum -= buf[i];
+       p->sum = sum;
+       return usb_control_msg(yld->udev,
+                       usb_sndctrlpipe(yld->udev, 0),
+                       USB_REQ_SET_CONFIGURATION,
+                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                       0x200, 3,
+                       p, sizeof(*p),
+                       USB_CTRL_SET_TIMEOUT);
+}
+
+static u8 default_ringtone[] = {
+       0xEF,                   /* volume [0-255] */
+       0xFB, 0x1E, 0x00, 0x0C, /* 1250 [hz], 12/100 [s] */
+       0xFC, 0x18, 0x00, 0x0C, /* 1000 [hz], 12/100 [s] */
+       0xFB, 0x1E, 0x00, 0x0C,
+       0xFC, 0x18, 0x00, 0x0C,
+       0xFB, 0x1E, 0x00, 0x0C,
+       0xFC, 0x18, 0x00, 0x0C,
+       0xFB, 0x1E, 0x00, 0x0C,
+       0xFC, 0x18, 0x00, 0x0C,
+       0xFF, 0xFF, 0x01, 0x90, /* silent, 400/100 [s] */
+       0x00, 0x00              /* end of sequence */
+};
+
+static int yealink_set_ringtone(struct yealink_dev *yld, u8 *buf, size_t size)
+{
+       struct yld_ctl_packet *p = yld->ctl_data;
+       int     ix, len;
+
+       if (size <= 0)
+               return -EINVAL;
+
+       /* Set the ringtone volume */
+       memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+       yld->ctl_data->cmd      = CMD_RING_VOLUME;
+       yld->ctl_data->size     = 1;
+       yld->ctl_data->data[0]  = buf[0];
+       yealink_cmd(yld, p);
+
+       buf++;
+       size--;
+
+       p->cmd = CMD_RING_NOTE;
+       ix = 0;
+       while (size != ix) {
+               len = size - ix;
+               if (len > sizeof(p->data))
+                       len = sizeof(p->data);
+               p->size   = len;
+               p->offset = cpu_to_be16(ix);
+               memcpy(p->data, &buf[ix], len);
+               yealink_cmd(yld, p);
+               ix += len;
+       }
+       return 0;
+}
+
+/* keep stat_master & stat_copy in sync.
+ */
+static int yealink_do_idle_tasks(struct yealink_dev *yld)
+{
+       u8 val;
+       int i, ix, len;
+
+       ix = yld->stat_ix;
+
+       memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+       yld->ctl_data->cmd  = CMD_KEYPRESS;
+       yld->ctl_data->size = 1;
+       yld->ctl_data->sum  = 0xff - CMD_KEYPRESS;
+
+       /* If state update pointer wraps do a KEYPRESS first. */
+       if (ix >= sizeof(yld->master)) {
+               yld->stat_ix = 0;
+               return 0;
+       }
+
+       /* find update candidates: copy != master */
+       do {
+               val = yld->master.b[ix];
+               if (val != yld->copy.b[ix])
+                       goto send_update;
+       } while (++ix < sizeof(yld->master));
+
+       /* nothing todo, wait a bit and poll for a KEYPRESS */
+       yld->stat_ix = 0;
+       /* TODO how can we wait abit. ??
+        * msleep_interruptible(1000 / YEALINK_POLLING_FREQUENCY);
+        */
+       return 0;
+
+send_update:
+
+       /* Setup an appropriate update request */
+       yld->copy.b[ix] = val;
+       yld->ctl_data->data[0] = val;
+
+       switch(ix) {
+       case offsetof(struct yld_status, led):
+               yld->ctl_data->cmd      = CMD_LED;
+               yld->ctl_data->sum      = -1 - CMD_LED - val;
+               break;
+       case offsetof(struct yld_status, dialtone):
+               yld->ctl_data->cmd      = CMD_DIALTONE;
+               yld->ctl_data->sum      = -1 - CMD_DIALTONE - val;
+               break;
+       case offsetof(struct yld_status, ringtone):
+               yld->ctl_data->cmd      = CMD_RINGTONE;
+               yld->ctl_data->sum      = -1 - CMD_RINGTONE - val;
+               break;
+       case offsetof(struct yld_status, keynum):
+               val--;
+               val &= 0x1f;
+               yld->ctl_data->cmd      = CMD_SCANCODE;
+               yld->ctl_data->offset   = cpu_to_be16(val);
+               yld->ctl_data->data[0]  = 0;
+               yld->ctl_data->sum      = -1 - CMD_SCANCODE - val;
+               break;
+       default:
+               len = sizeof(yld->master.s.lcd) - ix;
+               if (len > sizeof(yld->ctl_data->data))
+                       len = sizeof(yld->ctl_data->data);
+
+               /* Combine up to <len> consecutive LCD bytes in a singe request
+                */
+               yld->ctl_data->cmd      = CMD_LCD;
+               yld->ctl_data->offset   = cpu_to_be16(ix);
+               yld->ctl_data->size     = len;
+               yld->ctl_data->sum      = -CMD_LCD - ix - val - len;
+               for(i=1; i<len; i++) {
+                       ix++;
+                       val = yld->master.b[ix];
+                       yld->copy.b[ix]         = val;
+                       yld->ctl_data->data[i]  = val;
+                       yld->ctl_data->sum     -= val;
+               }
+       }
+       yld->stat_ix = ix + 1;
+       return 1;
+}
+
+/* Decide on how to handle responses
+ *
+ * The state transition diagram is somethhing like:
+ *
+ *          syncState<--+
+ *               |      |
+ *               |    idle
+ *              \|/     |
+ * init --ok--> waitForKey --ok--> getKey
+ *  ^               ^                |
+ *  |               +-------ok-------+
+ * error,start
+ *
+ */
+static void urb_irq_callback(struct urb *urb)
+{
+       struct yealink_dev *yld = urb->context;
+       int ret;
+
+       if (urb->status)
+               err("%s - urb status %d", __FUNCTION__, urb->status);
+
+       switch (yld->irq_data->cmd) {
+       case CMD_KEYPRESS:
+
+               yld->master.s.keynum = yld->irq_data->data[0];
+               break;
+
+       case CMD_SCANCODE:
+               dbg("get scancode %x", yld->irq_data->data[0]);
+
+               report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
+               break;
+
+       default:
+               err("unexpected response %x", yld->irq_data->cmd);
+       }
+
+       yealink_do_idle_tasks(yld);
+
+       ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+       if (ret)
+               err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+static void urb_ctl_callback(struct urb *urb)
+{
+       struct yealink_dev *yld = urb->context;
+       int ret;
+
+       if (urb->status)
+               err("%s - urb status %d", __FUNCTION__, urb->status);
+
+       switch (yld->ctl_data->cmd) {
+       case CMD_KEYPRESS:
+       case CMD_SCANCODE:
+               /* ask for a response */
+               ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
+               break;
+       default:
+               /* send new command */
+               yealink_do_idle_tasks(yld);
+               ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+       }
+
+       if (ret)
+               err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+/*******************************************************************************
+ * input event interface
+ ******************************************************************************/
+
+/* TODO should we issue a ringtone on a SND_BELL event?
+static int input_ev(struct input_dev *dev, unsigned int type,
+               unsigned int code, int value)
+{
+
+       if (type != EV_SND)
+               return -EINVAL;
+
+       switch (code) {
+       case SND_BELL:
+       case SND_TONE:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+*/
+
+static int input_open(struct input_dev *dev)
+{
+       struct yealink_dev *yld = input_get_drvdata(dev);
+       int i, ret;
+
+       dbg("%s", __FUNCTION__);
+
+       /* force updates to device */
+       for (i = 0; i<sizeof(yld->master); i++)
+               yld->copy.b[i] = ~yld->master.b[i];
+       yld->key_code = -1;     /* no keys pressed */
+
+        yealink_set_ringtone(yld, default_ringtone, sizeof(default_ringtone));
+
+       /* issue INIT */
+       memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+       yld->ctl_data->cmd      = CMD_INIT;
+       yld->ctl_data->size     = 10;
+       yld->ctl_data->sum      = 0x100-CMD_INIT-10;
+       if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
+               dbg("%s - usb_submit_urb failed with result %d",
+                    __FUNCTION__, ret);
+               return ret;
+       }
+       return 0;
+}
+
+static void input_close(struct input_dev *dev)
+{
+       struct yealink_dev *yld = input_get_drvdata(dev);
+
+       usb_kill_urb(yld->urb_ctl);
+       usb_kill_urb(yld->urb_irq);
+}
+
+/*******************************************************************************
+ * sysfs interface
+ ******************************************************************************/
+
+static DECLARE_RWSEM(sysfs_rwsema);
+
+/* Interface to the 7-segments translation table aka. char set.
+ */
+static ssize_t show_map(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       memcpy(buf, &map_seg7, sizeof(map_seg7));
+       return sizeof(map_seg7);
+}
+
+static ssize_t store_map(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t cnt)
+{
+       if (cnt != sizeof(map_seg7))
+               return -EINVAL;
+       memcpy(&map_seg7, buf, sizeof(map_seg7));
+       return sizeof(map_seg7);
+}
+
+/* Interface to the LCD.
+ */
+
+/* Reading /sys/../lineX will return the format string with its settings:
+ *
+ * Example:
+ * cat ./line3
+ * 888888888888
+ * Linux Rocks!
+ */
+static ssize_t show_line(struct device *dev, char *buf, int a, int b)
+{
+       struct yealink_dev *yld;
+       int i;
+
+       down_read(&sysfs_rwsema);
+       yld = dev_get_drvdata(dev);
+       if (yld == NULL) {
+               up_read(&sysfs_rwsema);
+               return -ENODEV;
+       }
+
+       for (i = a; i < b; i++)
+               *buf++ = lcdMap[i].type;
+       *buf++ = '\n';
+       for (i = a; i < b; i++)
+               *buf++ = yld->lcdMap[i];
+       *buf++ = '\n';
+       *buf = 0;
+
+       up_read(&sysfs_rwsema);
+       return 3 + ((b - a) << 1);
+}
+
+static ssize_t show_line1(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       return show_line(dev, buf, LCD_LINE1_OFFSET, LCD_LINE2_OFFSET);
+}
+
+static ssize_t show_line2(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       return show_line(dev, buf, LCD_LINE2_OFFSET, LCD_LINE3_OFFSET);
+}
+
+static ssize_t show_line3(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET);
+}
+
+/* Writing to /sys/../lineX will set the coresponding LCD line.
+ * - Excess characters are ignored.
+ * - If less characters are written than allowed, the remaining digits are
+ *   unchanged.
+ * - The '\n' or '\t' char is a placeholder, it does not overwrite the
+ *   original content.
+ */
+static ssize_t store_line(struct device *dev, const char *buf, size_t count,
+               int el, size_t len)
+{
+       struct yealink_dev *yld;
+       int i;
+
+       down_write(&sysfs_rwsema);
+       yld = dev_get_drvdata(dev);
+       if (yld == NULL) {
+               up_write(&sysfs_rwsema);
+               return -ENODEV;
+       }
+
+       if (len > count)
+               len = count;
+       for (i = 0; i < len; i++)
+               setChar(yld, el++, buf[i]);
+
+       up_write(&sysfs_rwsema);
+       return count;
+}
+
+static ssize_t store_line1(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       return store_line(dev, buf, count, LCD_LINE1_OFFSET, LCD_LINE1_SIZE);
+}
+
+static ssize_t store_line2(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       return store_line(dev, buf, count, LCD_LINE2_OFFSET, LCD_LINE2_SIZE);
+}
+
+static ssize_t store_line3(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       return store_line(dev, buf, count, LCD_LINE3_OFFSET, LCD_LINE3_SIZE);
+}
+
+/* Interface to visible and audible "icons", these include:
+ * pictures on the LCD, the LED, and the dialtone signal.
+ */
+
+/* Get a list of "switchable elements" with their current state. */
+static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct yealink_dev *yld;
+       int i, ret = 1;
+
+       down_read(&sysfs_rwsema);
+       yld = dev_get_drvdata(dev);
+       if (yld == NULL) {
+               up_read(&sysfs_rwsema);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
+               if (lcdMap[i].type != '.')
+                       continue;
+               ret += sprintf(&buf[ret], "%s %s\n",
+                               yld->lcdMap[i] == ' ' ? "  " : "on",
+                               lcdMap[i].u.p.name);
+       }
+       up_read(&sysfs_rwsema);
+       return ret;
+}
+
+/* Change the visibility of a particular element. */
+static ssize_t set_icon(struct device *dev, const char *buf, size_t count,
+                       int chr)
+{
+       struct yealink_dev *yld;
+       int i;
+
+       down_write(&sysfs_rwsema);
+       yld = dev_get_drvdata(dev);
+       if (yld == NULL) {
+               up_write(&sysfs_rwsema);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
+               if (lcdMap[i].type != '.')
+                       continue;
+               if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) {
+                       setChar(yld, i, chr);
+                       break;
+               }
+       }
+
+       up_write(&sysfs_rwsema);
+       return count;
+}
+
+static ssize_t show_icon(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       return set_icon(dev, buf, count, buf[0]);
+}
+
+static ssize_t hide_icon(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       return set_icon(dev, buf, count, ' ');
+}
+
+/* Upload a ringtone to the device.
+ */
+
+/* Stores raw ringtone data in the phone */
+static ssize_t store_ringtone(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct yealink_dev *yld;
+
+       down_write(&sysfs_rwsema);
+       yld = dev_get_drvdata(dev);
+       if (yld == NULL) {
+               up_write(&sysfs_rwsema);
+               return -ENODEV;
+       }
+
+       /* TODO locking with async usb control interface??? */
+       yealink_set_ringtone(yld, (char *)buf, count);
+       up_write(&sysfs_rwsema);
+       return count;
+}
+
+#define _M444  S_IRUGO
+#define _M664  S_IRUGO|S_IWUSR|S_IWGRP
+#define _M220  S_IWUSR|S_IWGRP
+
+static DEVICE_ATTR(map_seg7    , _M664, show_map       , store_map     );
+static DEVICE_ATTR(line1       , _M664, show_line1     , store_line1   );
+static DEVICE_ATTR(line2       , _M664, show_line2     , store_line2   );
+static DEVICE_ATTR(line3       , _M664, show_line3     , store_line3   );
+static DEVICE_ATTR(get_icons   , _M444, get_icons      , NULL          );
+static DEVICE_ATTR(show_icon   , _M220, NULL           , show_icon     );
+static DEVICE_ATTR(hide_icon   , _M220, NULL           , hide_icon     );
+static DEVICE_ATTR(ringtone    , _M220, NULL           , store_ringtone);
+
+static struct attribute *yld_attributes[] = {
+       &dev_attr_line1.attr,
+       &dev_attr_line2.attr,
+       &dev_attr_line3.attr,
+       &dev_attr_get_icons.attr,
+       &dev_attr_show_icon.attr,
+       &dev_attr_hide_icon.attr,
+       &dev_attr_map_seg7.attr,
+       &dev_attr_ringtone.attr,
+       NULL
+};
+
+static struct attribute_group yld_attr_group = {
+       .attrs = yld_attributes
+};
+
+/*******************************************************************************
+ * Linux interface and usb initialisation
+ ******************************************************************************/
+
+struct driver_info {
+       char *name;
+};
+
+static const struct driver_info info_P1K = {
+       .name   = "Yealink usb-p1k",
+};
+
+static const struct usb_device_id usb_table [] = {
+       {
+               .match_flags            = USB_DEVICE_ID_MATCH_DEVICE |
+                                               USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor               = 0x6993,
+               .idProduct              = 0xb001,
+               .bInterfaceClass        = USB_CLASS_HID,
+               .bInterfaceSubClass     = 0,
+               .bInterfaceProtocol     = 0,
+               .driver_info            = (kernel_ulong_t)&info_P1K
+       },
+       { }
+};
+
+static int usb_cleanup(struct yealink_dev *yld, int err)
+{
+       if (yld == NULL)
+               return err;
+
+       usb_kill_urb(yld->urb_irq);     /* parameter validation in core/urb */
+       usb_kill_urb(yld->urb_ctl);     /* parameter validation in core/urb */
+
+        if (yld->idev) {
+               if (err)
+                       input_free_device(yld->idev);
+               else
+                       input_unregister_device(yld->idev);
+       }
+
+       usb_free_urb(yld->urb_irq);
+       usb_free_urb(yld->urb_ctl);
+
+       usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
+                       yld->ctl_req, yld->ctl_req_dma);
+       usb_buffer_free(yld->udev, USB_PKT_LEN,
+                       yld->ctl_data, yld->ctl_dma);
+       usb_buffer_free(yld->udev, USB_PKT_LEN,
+                       yld->irq_data, yld->irq_dma);
+
+       kfree(yld);
+       return err;
+}
+
+static void usb_disconnect(struct usb_interface *intf)
+{
+       struct yealink_dev *yld;
+
+       down_write(&sysfs_rwsema);
+       yld = usb_get_intfdata(intf);
+       sysfs_remove_group(&intf->dev.kobj, &yld_attr_group);
+       usb_set_intfdata(intf, NULL);
+       up_write(&sysfs_rwsema);
+
+       usb_cleanup(yld, 0);
+}
+
+static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev (intf);
+       struct driver_info *nfo = (struct driver_info *)id->driver_info;
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct yealink_dev *yld;
+       struct input_dev *input_dev;
+       int ret, pipe, i;
+
+       interface = intf->cur_altsetting;
+       endpoint = &interface->endpoint[0].desc;
+       if (!usb_endpoint_is_int_in(endpoint))
+               return -ENODEV;
+
+       yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL);
+       if (!yld)
+               return -ENOMEM;
+
+       yld->udev = udev;
+
+       yld->idev = input_dev = input_allocate_device();
+       if (!input_dev)
+               return usb_cleanup(yld, -ENOMEM);
+
+       /* allocate usb buffers */
+       yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+                                       GFP_ATOMIC, &yld->irq_dma);
+       if (yld->irq_data == NULL)
+               return usb_cleanup(yld, -ENOMEM);
+
+       yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+                                       GFP_ATOMIC, &yld->ctl_dma);
+       if (!yld->ctl_data)
+               return usb_cleanup(yld, -ENOMEM);
+
+       yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)),
+                                       GFP_ATOMIC, &yld->ctl_req_dma);
+       if (yld->ctl_req == NULL)
+               return usb_cleanup(yld, -ENOMEM);
+
+       /* allocate urb structures */
+       yld->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
+        if (yld->urb_irq == NULL)
+               return usb_cleanup(yld, -ENOMEM);
+
+       yld->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
+        if (yld->urb_ctl == NULL)
+               return usb_cleanup(yld, -ENOMEM);
+
+       /* get a handle to the interrupt data pipe */
+       pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+       ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+       if (ret != USB_PKT_LEN)
+               err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
+
+       /* initialise irq urb */
+       usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
+                       USB_PKT_LEN,
+                       urb_irq_callback,
+                       yld, endpoint->bInterval);
+       yld->urb_irq->transfer_dma = yld->irq_dma;
+       yld->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+       yld->urb_irq->dev = udev;
+
+       /* initialise ctl urb */
+       yld->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+                                     USB_DIR_OUT;
+       yld->ctl_req->bRequest  = USB_REQ_SET_CONFIGURATION;
+       yld->ctl_req->wValue    = cpu_to_le16(0x200);
+       yld->ctl_req->wIndex    = cpu_to_le16(interface->desc.bInterfaceNumber);
+       yld->ctl_req->wLength   = cpu_to_le16(USB_PKT_LEN);
+
+       usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
+                       (void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
+                       urb_ctl_callback, yld);
+       yld->urb_ctl->setup_dma = yld->ctl_req_dma;
+       yld->urb_ctl->transfer_dma      = yld->ctl_dma;
+       yld->urb_ctl->transfer_flags    |= URB_NO_SETUP_DMA_MAP |
+                                       URB_NO_TRANSFER_DMA_MAP;
+       yld->urb_ctl->dev = udev;
+
+       /* find out the physical bus location */
+       usb_make_path(udev, yld->phys, sizeof(yld->phys));
+       strlcat(yld->phys,  "/input0", sizeof(yld->phys));
+
+       /* register settings for the input device */
+       input_dev->name = nfo->name;
+       input_dev->phys = yld->phys;
+       usb_to_input_id(udev, &input_dev->id);
+       input_dev->dev.parent = &intf->dev;
+
+       input_set_drvdata(input_dev, yld);
+
+       input_dev->open = input_open;
+       input_dev->close = input_close;
+       /* input_dev->event = input_ev; TODO */
+
+       /* register available key events */
+       input_dev->evbit[0] = BIT(EV_KEY);
+       for (i = 0; i < 256; i++) {
+               int k = map_p1k_to_key(i);
+               if (k >= 0) {
+                       set_bit(k & 0xff, input_dev->keybit);
+                       if (k >> 8)
+                               set_bit(k >> 8, input_dev->keybit);
+               }
+       }
+
+       ret = input_register_device(yld->idev);
+       if (ret)
+               return usb_cleanup(yld, ret);
+
+       usb_set_intfdata(intf, yld);
+
+       /* clear visible elements */
+       for (i = 0; i < ARRAY_SIZE(lcdMap); i++)
+               setChar(yld, i, ' ');
+
+       /* display driver version on LCD line 3 */
+       store_line3(&intf->dev, NULL,
+                       DRIVER_VERSION, sizeof(DRIVER_VERSION));
+
+       /* Register sysfs hooks (don't care about failure) */
+       ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
+       return 0;
+}
+
+static struct usb_driver yealink_driver = {
+       .name           = "yealink",
+       .probe          = usb_probe,
+       .disconnect     = usb_disconnect,
+       .id_table       = usb_table,
+};
+
+static int __init yealink_dev_init(void)
+{
+       int ret = usb_register(&yealink_driver);
+       if (ret == 0)
+               info(DRIVER_DESC ":" DRIVER_VERSION);
+       return ret;
+}
+
+static void __exit yealink_dev_exit(void)
+{
+       usb_deregister(&yealink_driver);
+}
+
+module_init(yealink_dev_init);
+module_exit(yealink_dev_exit);
+
+MODULE_DEVICE_TABLE (usb, usb_table);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/yealink.h b/drivers/input/misc/yealink.h
new file mode 100644 (file)
index 0000000..48af0be
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * drivers/usb/input/yealink.h
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef INPUT_YEALINK_H
+#define INPUT_YEALINK_H
+
+/* Using the control channel on interface 3 various aspects of the phone
+ * can be controlled like LCD, LED, dialtone and the ringtone.
+ */
+
+struct yld_ctl_packet {
+       u8      cmd;            /* command code, see below */
+       u8      size;           /* 1-11, size of used data bytes. */
+       u16     offset;         /* internal packet offset */
+       u8      data[11];
+       s8      sum;            /* negative sum of 15 preceding bytes */
+} __attribute__ ((packed));
+
+#define USB_PKT_LEN    sizeof(struct yld_ctl_packet)
+
+/* The following yld_ctl_packet's are available: */
+
+/* Init registers
+ *
+ * cmd         0x8e
+ * size                10
+ * offset      0
+ * data                0,0,0,0....
+ */
+#define CMD_INIT               0x8e
+
+/* Request key scan
+ *
+ * cmd         0x80
+ * size                1
+ * offset      0
+ * data[0]     on return returns the key number, if it changes there's a new
+ *             key pressed.
+ */
+#define CMD_KEYPRESS           0x80
+
+/* Request scancode
+ *
+ * cmd         0x81
+ * size                1
+ * offset      key number [0-1f]
+ * data[0]     on return returns the scancode
+ */
+#define CMD_SCANCODE           0x81
+
+/* Set LCD
+ *
+ * cmd         0x04
+ * size                1-11
+ * offset      0-23
+ * data                segment bits
+ */
+#define CMD_LCD                        0x04
+
+/* Set led
+ *
+ * cmd         0x05
+ * size                1
+ * offset      0
+ * data[0]     0 OFF / 1 ON
+ */
+#define CMD_LED                        0x05
+
+/* Set ringtone volume
+ *
+ * cmd         0x11
+ * size                1
+ * offset      0
+ * data[0]     0-0xff  volume
+ */
+#define CMD_RING_VOLUME                0x11
+
+/* Set ringtone notes
+ *
+ * cmd         0x02
+ * size                1-11
+ * offset      0->
+ * data                binary representation LE16(-freq), LE16(duration) ....
+ */
+#define CMD_RING_NOTE          0x02
+
+/* Sound ringtone via the speaker on the back
+ *
+ * cmd         0x03
+ * size                1
+ * offset      0
+ * data[0]     0 OFF / 0x24 ON
+ */
+#define CMD_RINGTONE           0x03
+
+/* Sound dial tone via the ear speaker
+ *
+ * cmd         0x09
+ * size                1
+ * offset      0
+ * data[0]     0 OFF / 1 ON
+ */
+#define CMD_DIALTONE           0x09
+
+#endif /* INPUT_YEALINK_H */
+
+
+#if defined(_SEG) && defined(_PIC)
+/* This table maps the LCD segments onto individual bit positions in the
+ * yld_status struct.
+ */
+
+/* LCD, each segment must be driven seperately.
+ *
+ * Layout:
+ *
+ *   |[]   [][]   [][]   [][]   in   |[][]
+ *   |[] M [][] D [][] : [][]   out  |[][]
+ *                             store
+ *
+ *    NEW REP         SU MO TU WE TH FR SA
+ *
+ *    [] [] [] [] [] [] [] [] [] [] [] []
+ *    [] [] [] [] [] [] [] [] [] [] [] []
+ */
+
+/* Line 1
+ *     Format          : 18.e8.M8.88...188
+ *     Icon names      : M D : IN OUT STORE
+ */
+#define LCD_LINE1_OFFSET       0
+#define LCD_LINE1_SIZE         17
+
+/* Note: first g then f =>                            !      !      */
+/* _SEG(    type    a      b      c      d      e      g      f   )  */
+       _SEG('1',  0,0 , 22,2 , 22,2 ,  0,0 ,  0,0 ,  0,0 ,  0,0        ),
+       _SEG('8', 20,1 , 20,2 , 20,4 , 20,8 , 21,4 , 21,2 , 21,1        ),
+       _PIC('.', 22,1 , "M"                                            ),
+       _SEG('e', 18,1 , 18,2 , 18,4 , 18,1 , 19,2 , 18,1 , 19,1        ),
+       _SEG('8', 16,1 , 16,2 , 16,4 , 16,8 , 17,4 , 17,2 , 17,1        ),
+       _PIC('.', 15,8 , "D"                                            ),
+       _SEG('M', 14,1 , 14,2 , 14,4 , 14,1 , 15,4 , 15,2 , 15,1        ),
+       _SEG('8', 12,1 , 12,2 , 12,4 , 12,8 , 13,4 , 13,2 , 13,1        ),
+       _PIC('.', 11,8 , ":"                                            ),
+       _SEG('8', 10,1 , 10,2 , 10,4 , 10,8 , 11,4 , 11,2 , 11,1        ),
+       _SEG('8',  8,1 ,  8,2 ,  8,4 ,  8,8 ,  9,4 ,  9,2 ,  9,1        ),
+       _PIC('.',  7,1 , "IN"                                           ),
+       _PIC('.',  7,2 , "OUT"                                          ),
+       _PIC('.',  7,4 , "STORE"                                        ),
+       _SEG('1',  0,0 ,  5,1 ,  5,1 ,  0,0 ,  0,0 ,  0,0 ,  0,0        ),
+       _SEG('8',  4,1 ,  4,2 ,  4,4 ,  4,8 ,  5,8 ,  5,4 ,  5,2        ),
+       _SEG('8',  2,1 ,  2,2 ,  2,4 ,  2,8 ,  3,4 ,  3,2 ,  3,1        ),
+
+/* Line 2
+ *     Format          : .........
+ *     Pict. name      : NEW REP SU MO TU WE TH FR SA
+ */
+#define LCD_LINE2_OFFSET       LCD_LINE1_OFFSET + LCD_LINE1_SIZE
+#define LCD_LINE2_SIZE         9
+
+       _PIC('.', 23,2 , "NEW"  ),
+       _PIC('.', 23,4 , "REP"  ),
+       _PIC('.',  1,8 , "SU"   ),
+       _PIC('.',  1,4 , "MO"   ),
+       _PIC('.',  1,2 , "TU"   ),
+       _PIC('.',  1,1 , "WE"   ),
+       _PIC('.',  0,1 , "TH"   ),
+       _PIC('.',  0,2 , "FR"   ),
+       _PIC('.',  0,4 , "SA"   ),
+
+/* Line 3
+ *     Format          : 888888888888
+ */
+#define LCD_LINE3_OFFSET       LCD_LINE2_OFFSET + LCD_LINE2_SIZE
+#define LCD_LINE3_SIZE         12
+
+       _SEG('8', 22,16, 22,32, 22,64, 22,128, 23,128, 23,64, 23,32  ),
+       _SEG('8', 20,16, 20,32, 20,64, 20,128, 21,128, 21,64, 21,32  ),
+       _SEG('8', 18,16, 18,32, 18,64, 18,128, 19,128, 19,64, 19,32  ),
+       _SEG('8', 16,16, 16,32, 16,64, 16,128, 17,128, 17,64, 17,32  ),
+       _SEG('8', 14,16, 14,32, 14,64, 14,128, 15,128, 15,64, 15,32  ),
+       _SEG('8', 12,16, 12,32, 12,64, 12,128, 13,128, 13,64, 13,32  ),
+       _SEG('8', 10,16, 10,32, 10,64, 10,128, 11,128, 11,64, 11,32  ),
+       _SEG('8',  8,16,  8,32,  8,64,  8,128,  9,128,  9,64,  9,32  ),
+       _SEG('8',  6,16,  6,32,  6,64,  6,128,  7,128,  7,64,  7,32  ),
+       _SEG('8',  4,16,  4,32,  4,64,  4,128,  5,128,  5,64,  5,32  ),
+       _SEG('8',  2,16,  2,32,  2,64,  2,128,  3,128,  3,64,  3,32  ),
+       _SEG('8',  0,16,  0,32,  0,64,  0,128,  1,128,  1,64,  1,32  ),
+
+/* Line 4
+ *
+ * The LED, DIALTONE and RINGTONE are implemented as icons and use the same
+ * sysfs interface.
+ */
+#define LCD_LINE4_OFFSET       LCD_LINE3_OFFSET + LCD_LINE3_SIZE
+
+       _PIC('.', offsetof(struct yld_status, led)      , 0x01, "LED" ),
+       _PIC('.', offsetof(struct yld_status, dialtone) , 0x01, "DIALTONE" ),
+       _PIC('.', offsetof(struct yld_status, ringtone) , 0x24, "RINGTONE" ),
+
+#undef _SEG
+#undef _PIC
+#endif /* _SEG && _PIC */
index 9980a4ddfed934617a7726c6c612a24edebb4d27..b847bbc8b0e1a5730bb493ed5644d2a2a278cfe0 100644 (file)
@@ -85,8 +85,6 @@ source "drivers/usb/class/Kconfig"
 
 source "drivers/usb/storage/Kconfig"
 
-source "drivers/usb/input/Kconfig"
-
 source "drivers/usb/image/Kconfig"
 
 source "drivers/usb/net/Kconfig"
index 7059a64637a8fbd4099cd1e8e84e573eb0b56709..0ef090b1b37c31f761520c1c25fbfad7ac68e0b7 100644 (file)
@@ -23,9 +23,6 @@ obj-$(CONFIG_USB_PRINTER)     += class/
 obj-$(CONFIG_USB_STORAGE)      += storage/
 obj-$(CONFIG_USB)              += storage/
 
-obj-$(CONFIG_USB_ATI_REMOTE)   += input/
-obj-$(CONFIG_USB_POWERMATE)    += input/
-
 obj-$(CONFIG_USB_CATC)         += net/
 obj-$(CONFIG_USB_KAWETH)       += net/
 obj-$(CONFIG_USB_PEGASUS)      += net/
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
deleted file mode 100644 (file)
index 4959dcf..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#
-# USB Input driver configuration
-#
-comment "USB Input Devices"
-       depends on USB
-
-config USB_POWERMATE
-       tristate "Griffin PowerMate and Contour Jog support"
-       depends on USB && INPUT
-       ---help---
-         Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
-         These are aluminum dials which can measure clockwise and anticlockwise
-         rotation.  The dial also acts as a pushbutton.  The base contains an LED
-         which can be instructed to pulse or to switch to a particular intensity.
-
-         You can download userspace tools from
-         <http://sowerbutts.com/powermate/>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called powermate.
-
-config USB_YEALINK
-       tristate "Yealink usb-p1k voip phone"
-       depends on USB && INPUT && EXPERIMENTAL
-       ---help---
-         Say Y here if you want to enable keyboard and LCD functions of the
-         Yealink usb-p1k usb phones. The audio part is enabled by the generic
-         usb sound driver, so you might want to enable that as well.
-
-         For information about how to use these additional functions, see
-         <file:Documentation/input/yealink.txt>.
-
-         To compile this driver as a module, choose M here: the module will be
-         called yealink.
-
-config USB_ATI_REMOTE
-       tristate "ATI / X10 USB RF remote control"
-       depends on USB && INPUT
-       ---help---
-         Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
-         These are RF remotes with USB receivers. 
-         The ATI remote comes with many of ATI's All-In-Wonder video cards.
-         The X10 "Lola" remote is available at:
-            <http://www.x10.com/products/lola_sg1.htm>
-         This driver provides mouse pointer, left and right mouse buttons, 
-         and maps all the other remote buttons to keypress events.
-         
-         To compile this driver as a module, choose M here: the module will be
-         called ati_remote.
-
-config USB_ATI_REMOTE2
-       tristate "ATI / Philips USB RF remote control"
-       depends on USB && INPUT
-       ---help---
-         Say Y here if you want to use an ATI or Philips USB RF remote control.
-         These are RF remotes with USB receivers.
-         ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards
-         and is also available as a separate product.
-         This driver provides mouse pointer, left and right mouse buttons,
-         and maps all the other remote buttons to keypress events.
-
-         To compile this driver as a module, choose M here: the module will be
-         called ati_remote2.
-
-config USB_KEYSPAN_REMOTE
-       tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
-       depends on USB && INPUT && EXPERIMENTAL
-       ---help---
-         Say Y here if you want to use a Keyspan DMR USB remote control.
-         Currently only the UIA-11 type of receiver has been tested.  The tag
-         on the receiver that connects to the USB port should have a P/N that
-         will tell you what type of DMR you have.  The UIA-10 type is not
-         supported at this time.  This driver maps all buttons to keypress
-         events.
-
-         To compile this driver as a module, choose M here: the module will
-         be called keyspan_remote.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
deleted file mode 100644 (file)
index 91df130..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Makefile for the USB input drivers
-#
-
-obj-$(CONFIG_USB_ATI_REMOTE)   += ati_remote.o
-obj-$(CONFIG_USB_ATI_REMOTE2)  += ati_remote2.o
-obj-$(CONFIG_USB_KEYSPAN_REMOTE)       += keyspan_remote.o
-obj-$(CONFIG_USB_POWERMATE)    += powermate.o
-obj-$(CONFIG_USB_YEALINK)      += yealink.o
-
-ifeq ($(CONFIG_USB_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
deleted file mode 100644 (file)
index 471aab2..0000000
+++ /dev/null
@@ -1,862 +0,0 @@
-/*
- *  USB ATI Remote support
- *
- *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
- *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
- *
- *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
- *  porting to the 2.6 kernel interfaces, along with other modification
- *  to better match the style of the existing usb/input drivers.  However, the
- *  protocol and hardware handling is essentially unchanged from 2.1.1.
- *
- *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
- *  Vojtech Pavlik.
- *
- *  Changes:
- *
- *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
- *            Version 2.2.0
- *  Jun 2004: Torrey Hoffman <thoffman@arnor.net>
- *            Version 2.2.1
- *            Added key repeat support contributed by:
- *                Vincent Vanackere <vanackere@lif.univ-mrs.fr>
- *            Added support for the "Lola" remote contributed by:
- *                Seth Cohn <sethcohn@yahoo.com>
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Hardware & software notes
- *
- * These remote controls are distributed by ATI as part of their
- * "All-In-Wonder" video card packages.  The receiver self-identifies as a
- * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
- *
- * The "Lola" remote is available from X10.  See:
- *    http://www.x10.com/products/lola_sg1.htm
- * The Lola is similar to the ATI remote but has no mouse support, and slightly
- * different keys.
- *
- * It is possible to use multiple receivers and remotes on multiple computers
- * simultaneously by configuring them to use specific channels.
- *
- * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
- * Actually, it may even support more, at least in some revisions of the
- * hardware.
- *
- * Each remote can be configured to transmit on one channel as follows:
- *   - Press and hold the "hand icon" button.
- *   - When the red LED starts to blink, let go of the "hand icon" button.
- *   - When it stops blinking, input the channel code as two digits, from 01
- *     to 16, and press the hand icon again.
- *
- * The timing can be a little tricky.  Try loading the module with debug=1
- * to have the kernel print out messages about the remote control number
- * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
- *
- * The driver has a "channel_mask" parameter. This bitmask specifies which
- * channels will be ignored by the module.  To mask out channels, just add
- * all the 2^channel_number values together.
- *
- * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
- * ignore signals coming from remote controls transmitting on channel 4, but
- * accept all other channels.
- *
- * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
- * ignored.
- *
- * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
- * parameter are unused.
- *
- */
-
-#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/usb/input.h>
-#include <linux/wait.h>
-#include <linux/jiffies.h>
-
-/*
- * Module and Version Information, Module Parameters
- */
-
-#define ATI_REMOTE_VENDOR_ID   0x0bc7
-#define ATI_REMOTE_PRODUCT_ID  0x004
-#define LOLA_REMOTE_PRODUCT_ID 0x002
-#define MEDION_REMOTE_PRODUCT_ID 0x006
-
-#define DRIVER_VERSION         "2.2.1"
-#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
-#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
-
-#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 */
-#define REPEAT_DELAY   500 /* msec */
-
-static unsigned long channel_mask;
-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, 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");
-
-static int repeat_delay = REPEAT_DELAY;
-module_param(repeat_delay, int, 0644);
-MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 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 struct usb_device_id ati_remote_table[] = {
-       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
-       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
-       { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
-       {}      /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ati_remote_table);
-
-/* Get hi and low bytes of a 16-bits int */
-#define HI(a)  ((unsigned char)((a) >> 8))
-#define LO(a)  ((unsigned char)((a) & 0xff))
-
-#define SEND_FLAG_IN_PROGRESS  1
-#define SEND_FLAG_COMPLETE     2
-
-/* Device initialization strings */
-static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
-static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
-
-struct ati_remote {
-       struct input_dev *idev;
-       struct usb_device *udev;
-       struct usb_interface *interface;
-
-       struct urb *irq_urb;
-       struct urb *out_urb;
-       struct usb_endpoint_descriptor *endpoint_in;
-       struct usb_endpoint_descriptor *endpoint_out;
-       unsigned char *inbuf;
-       unsigned char *outbuf;
-       dma_addr_t inbuf_dma;
-       dma_addr_t outbuf_dma;
-
-       unsigned char old_data[2];  /* Detect duplicate events */
-       unsigned long old_jiffies;
-       unsigned long acc_jiffies;  /* handle acceleration */
-       unsigned long first_jiffies;
-
-       unsigned int repeat_count;
-
-       char name[NAME_BUFSIZE];
-       char phys[NAME_BUFSIZE];
-
-       wait_queue_head_t wait;
-       int send_flags;
-};
-
-/* "Kinds" of messages sent from the hardware to the driver. */
-#define KIND_END        0
-#define KIND_LITERAL    1   /* Simply pass to input system */
-#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
-#define KIND_LU         3   /* Directional keypad diagonals - left up, */
-#define KIND_RU         4   /*   right up,  */
-#define KIND_LD         5   /*   left down, */
-#define KIND_RD         6   /*   right down */
-#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
-
-/* Translation table from hardware messages to input events. */
-static const struct {
-       short kind;
-       unsigned char data1, data2;
-       int type;
-       unsigned int code;
-       int value;
-}  ati_remote_tbl[] = {
-       /* Directional control pad axes */
-       {KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},   /* left */
-       {KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
-       {KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},   /* up */
-       {KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
-       /* Directional control pad diagonals */
-       {KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
-       {KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
-       {KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
-       {KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
-
-       /* "Mouse button" buttons */
-       {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
-       {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
-       {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
-       {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
-
-       /* Artificial "doubleclick" events are generated by the hardware.
-        * They are mapped to the "side" and "extra" mouse buttons here. */
-       {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
-       {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
-
-       /* keyboard. */
-       {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
-       {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
-       {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
-       {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
-       {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
-       {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
-       {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
-       {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
-       {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
-       {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
-       {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
-       {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
-       {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
-       {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
-       {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
-       {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
-
-       /* "special" keys */
-       {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
-       {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
-       {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
-       {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
-       {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
-       {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
-       {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
-       {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
-       {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
-       {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
-       {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
-       {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
-       {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
-       {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
-       {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
-       {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
-       {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
-       {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
-       {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
-       {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
-       {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
-       {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
-       {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
-       {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
-       {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
-       {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
-       {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
-       {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
-       {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
-       {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
-       {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
-       {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
-
-       {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
-};
-
-/* Local function prototypes */
-static void ati_remote_dump            (unsigned char *data, unsigned int actual_length);
-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);
-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);
-
-/* usb specific object to register with the usb subsystem */
-static struct usb_driver ati_remote_driver = {
-       .name         = "ati_remote",
-       .probe        = ati_remote_probe,
-       .disconnect   = ati_remote_disconnect,
-       .id_table     = ati_remote_table,
-};
-
-/*
- *     ati_remote_dump_input
- */
-static void ati_remote_dump(unsigned char *data, unsigned int len)
-{
-       if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
-               warn("Weird byte 0x%02x", data[0]);
-       else if (len == 4)
-               warn("Weird key %02x %02x %02x %02x",
-                    data[0], data[1], data[2], data[3]);
-       else
-               warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
-                    len, data[0], data[1], data[2], data[3], data[4], data[5]);
-}
-
-/*
- *     ati_remote_open
- */
-static int ati_remote_open(struct input_dev *inputdev)
-{
-       struct ati_remote *ati_remote = input_get_drvdata(inputdev);
-
-       /* On first open, submit the read urb which was set up previously. */
-       ati_remote->irq_urb->dev = ati_remote->udev;
-       if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
-               dev_err(&ati_remote->interface->dev,
-                       "%s: usb_submit_urb failed!\n", __FUNCTION__);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*
- *     ati_remote_close
- */
-static void ati_remote_close(struct input_dev *inputdev)
-{
-       struct ati_remote *ati_remote = input_get_drvdata(inputdev);
-
-       usb_kill_urb(ati_remote->irq_urb);
-}
-
-/*
- *             ati_remote_irq_out
- */
-static void ati_remote_irq_out(struct urb *urb)
-{
-       struct ati_remote *ati_remote = urb->context;
-
-       if (urb->status) {
-               dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
-                       __FUNCTION__, urb->status);
-               return;
-       }
-
-       ati_remote->send_flags |= SEND_FLAG_COMPLETE;
-       wmb();
-       wake_up(&ati_remote->wait);
-}
-
-/*
- *     ati_remote_sendpacket
- *
- *     Used to send device initialization strings
- */
-static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
-{
-       int retval = 0;
-
-       /* Set up out_urb */
-       memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
-       ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
-
-       ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
-       ati_remote->out_urb->dev = ati_remote->udev;
-       ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
-
-       retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
-       if (retval) {
-               dev_dbg(&ati_remote->interface->dev,
-                        "sendpacket: usb_submit_urb failed: %d\n", retval);
-               return retval;
-       }
-
-       wait_event_timeout(ati_remote->wait,
-               ((ati_remote->out_urb->status != -EINPROGRESS) ||
-                       (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
-               HZ);
-       usb_kill_urb(ati_remote->out_urb);
-
-       return retval;
-}
-
-/*
- *     ati_remote_event_lookup
- */
-static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
-{
-       int i;
-
-       for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
-               /*
-                * Decide if the table entry matches the remote input.
-                */
-               if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
-                   ((((ati_remote_tbl[i].data1 >> 4) -
-                      (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
-                   (ati_remote_tbl[i].data2 == d2))
-                       return i;
-
-       }
-       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 ati_remote *ati_remote = urb->context;
-       unsigned char *data= ati_remote->inbuf;
-       struct input_dev *dev = ati_remote->idev;
-       int index, acc;
-       int remote_num;
-
-       /* Deal with strange looking inputs */
-       if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
-               ((data[3] & 0x0f) != 0x00) ) {
-               ati_remote_dump(data, urb->actual_length);
-               return;
-       }
-
-       /* Mask unwanted remote channels.  */
-       /* note: remote_num is 0-based, channel 1 on remote == 0 here */
-       remote_num = (data[3] >> 4) & 0x0f;
-        if (channel_mask & (1 << (remote_num + 1))) {
-               dbginfo(&ati_remote->interface->dev,
-                       "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
-                       remote_num, data[1], data[2], channel_mask);
-               return;
-       }
-
-       /* Look up event code index in translation table */
-       index = ati_remote_event_lookup(remote_num, data[1], data[2]);
-       if (index < 0) {
-               dev_warn(&ati_remote->interface->dev,
-                        "Unknown input from channel 0x%02x: data %02x,%02x\n",
-                        remote_num, data[1], data[2]);
-               return;
-       }
-       dbginfo(&ati_remote->interface->dev,
-               "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
-               remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
-
-       if (ati_remote_tbl[index].kind == KIND_LITERAL) {
-               input_event(dev, ati_remote_tbl[index].type,
-                       ati_remote_tbl[index].code,
-                       ati_remote_tbl[index].value);
-               input_sync(dev);
-
-               ati_remote->old_jiffies = jiffies;
-               return;
-       }
-
-       if (ati_remote_tbl[index].kind == KIND_FILTERED) {
-               unsigned long now = jiffies;
-
-               /* 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(now, ati_remote->old_jiffies +
-                                    msecs_to_jiffies(repeat_filter))) {
-                       ati_remote->repeat_count++;
-               } else {
-                       ati_remote->repeat_count = 0;
-                       ati_remote->first_jiffies = now;
-               }
-
-               ati_remote->old_data[0] = data[1];
-               ati_remote->old_data[1] = data[2];
-               ati_remote->old_jiffies = now;
-
-               /* Ensure we skip at least the 4 first duplicate events (generated
-                * by a single keypress), and continue skipping until repeat_delay
-                * msecs have passed
-                */
-               if (ati_remote->repeat_count > 0 &&
-                   (ati_remote->repeat_count < 5 ||
-                    time_before(now, ati_remote->first_jiffies +
-                                     msecs_to_jiffies(repeat_delay))))
-                       return;
-
-
-               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);
-
-       } 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.
-                */
-               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_irq_in
- */
-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);
-               break;
-       case -ECONNRESET:       /* unlink */
-       case -ENOENT:
-       case -ESHUTDOWN:
-               dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
-                       __FUNCTION__);
-               return;
-       default:                /* error */
-               dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
-                       __FUNCTION__, urb->status);
-       }
-
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-       if (retval)
-               dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
-                       __FUNCTION__, retval);
-}
-
-/*
- *     ati_remote_alloc_buffers
- */
-static int ati_remote_alloc_buffers(struct usb_device *udev,
-                                   struct ati_remote *ati_remote)
-{
-       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, GFP_ATOMIC,
-                                             &ati_remote->outbuf_dma);
-       if (!ati_remote->outbuf)
-               return -1;
-
-       ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!ati_remote->irq_urb)
-               return -1;
-
-       ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!ati_remote->out_urb)
-               return -1;
-
-       return 0;
-}
-
-/*
- *     ati_remote_free_buffers
- */
-static void ati_remote_free_buffers(struct ati_remote *ati_remote)
-{
-       usb_free_urb(ati_remote->irq_urb);
-       usb_free_urb(ati_remote->out_urb);
-
-       usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
-               ati_remote->inbuf, ati_remote->inbuf_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)
-{
-       struct input_dev *idev = ati_remote->idev;
-       int i;
-
-       idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-       idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
-                                         BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
-       idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-       for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
-               if (ati_remote_tbl[i].type == EV_KEY)
-                       set_bit(ati_remote_tbl[i].code, idev->keybit);
-
-       input_set_drvdata(idev, ati_remote);
-
-       idev->open = ati_remote_open;
-       idev->close = ati_remote_close;
-
-       idev->name = ati_remote->name;
-       idev->phys = ati_remote->phys;
-
-       usb_to_input_id(ati_remote->udev, &idev->id);
-       idev->dev.parent = &ati_remote->udev->dev;
-}
-
-static int ati_remote_initialize(struct ati_remote *ati_remote)
-{
-       struct usb_device *udev = ati_remote->udev;
-       int pipe, maxp;
-
-       init_waitqueue_head(&ati_remote->wait);
-
-       /* Set up irq_urb */
-       pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
-       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
-       usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
-                        maxp, ati_remote_irq_in, ati_remote,
-                        ati_remote->endpoint_in->bInterval);
-       ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
-       ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       /* Set up out_urb */
-       pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
-       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
-       usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
-                        maxp, ati_remote_irq_out, ati_remote,
-                        ati_remote->endpoint_out->bInterval);
-       ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
-       ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       /* send initialization strings */
-       if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
-           (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
-               dev_err(&ati_remote->interface->dev,
-                        "Initializing ati_remote hardware failed.\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*
- *     ati_remote_probe
- */
-static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct usb_host_interface *iface_host = interface->cur_altsetting;
-       struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
-       struct ati_remote *ati_remote;
-       struct input_dev *input_dev;
-       int err = -ENOMEM;
-
-       if (iface_host->desc.bNumEndpoints != 2) {
-               err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__);
-               return -ENODEV;
-       }
-
-       endpoint_in = &iface_host->endpoint[0].desc;
-       endpoint_out = &iface_host->endpoint[1].desc;
-
-       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) {
-               err("%s: endpoint_in message size==0? \n", __FUNCTION__);
-               return -ENODEV;
-       }
-
-       ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ati_remote || !input_dev)
-               goto fail1;
-
-       /* Allocate URB buffers, URBs */
-       if (ati_remote_alloc_buffers(udev, ati_remote))
-               goto fail2;
-
-       ati_remote->endpoint_in = endpoint_in;
-       ati_remote->endpoint_out = endpoint_out;
-       ati_remote->udev = udev;
-       ati_remote->idev = input_dev;
-       ati_remote->interface = interface;
-
-       usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys));
-       strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys));
-
-       if (udev->manufacturer)
-               strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
-
-       if (udev->product)
-               snprintf(ati_remote->name, sizeof(ati_remote->name),
-                        "%s %s", ati_remote->name, udev->product);
-
-       if (!strlen(ati_remote->name))
-               snprintf(ati_remote->name, sizeof(ati_remote->name),
-                       DRIVER_DESC "(%04x,%04x)",
-                       le16_to_cpu(ati_remote->udev->descriptor.idVendor),
-                       le16_to_cpu(ati_remote->udev->descriptor.idProduct));
-
-       ati_remote_input_init(ati_remote);
-
-       /* Device Hardware Initialization - fills in ati_remote->idev from udev. */
-       err = ati_remote_initialize(ati_remote);
-       if (err)
-               goto fail3;
-
-       /* Set up and register input device */
-       err = input_register_device(ati_remote->idev);
-       if (err)
-               goto fail3;
-
-       usb_set_intfdata(interface, ati_remote);
-       return 0;
-
- fail3:        usb_kill_urb(ati_remote->irq_urb);
-       usb_kill_urb(ati_remote->out_urb);
- fail2:        ati_remote_free_buffers(ati_remote);
- fail1:        input_free_device(input_dev);
-       kfree(ati_remote);
-       return err;
-}
-
-/*
- *     ati_remote_disconnect
- */
-static void ati_remote_disconnect(struct usb_interface *interface)
-{
-       struct ati_remote *ati_remote;
-
-       ati_remote = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-       if (!ati_remote) {
-               warn("%s - null device?\n", __FUNCTION__);
-               return;
-       }
-
-       usb_kill_urb(ati_remote->irq_urb);
-       usb_kill_urb(ati_remote->out_urb);
-       input_unregister_device(ati_remote->idev);
-       ati_remote_free_buffers(ati_remote);
-       kfree(ati_remote);
-}
-
-/*
- *     ati_remote_init
- */
-static int __init ati_remote_init(void)
-{
-       int result;
-
-       result = usb_register(&ati_remote_driver);
-       if (result)
-               err("usb_register error #%d\n", result);
-       else
-               info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION);
-
-       return result;
-}
-
-/*
- *     ati_remote_exit
- */
-static void __exit ati_remote_exit(void)
-{
-       usb_deregister(&ati_remote_driver);
-}
-
-/*
- *     module specification
- */
-
-module_init(ati_remote_init);
-module_exit(ati_remote_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/ati_remote2.c b/drivers/usb/input/ati_remote2.c
deleted file mode 100644 (file)
index 1031543..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * ati_remote2 - ATI/Philips USB RF remote driver
- *
- * Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi>
- * Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- */
-
-#include <linux/usb/input.h>
-
-#define DRIVER_DESC    "ATI/Philips USB RF remote driver"
-#define DRIVER_VERSION "0.2"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
-MODULE_LICENSE("GPL");
-
-/*
- * ATI Remote Wonder II Channel Configuration
- *
- * The remote control can by assigned one of sixteen "channels" in order to facilitate
- * the use of multiple remote controls within range of each other.
- * A remote's "channel" may be altered by pressing and holding the "PC" button for
- * approximately 3 seconds, after which the button will slowly flash the count of the
- * currently configured "channel", using the numeric keypad enter a number between 1 and
- * 16 and then the "PC" button again, the button will slowly flash the count of the
- * newly configured "channel".
- */
-
-static unsigned int channel_mask = 0xFFFF;
-module_param(channel_mask, uint, 0644);
-MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
-
-static unsigned int mode_mask = 0x1F;
-module_param(mode_mask, uint, 0644);
-MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
-
-static struct usb_device_id ati_remote2_id_table[] = {
-       { USB_DEVICE(0x0471, 0x0602) }, /* ATI Remote Wonder II */
-       { }
-};
-MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
-
-static struct {
-       int hw_code;
-       int key_code;
-} ati_remote2_key_table[] = {
-       { 0x00, KEY_0 },
-       { 0x01, KEY_1 },
-       { 0x02, KEY_2 },
-       { 0x03, KEY_3 },
-       { 0x04, KEY_4 },
-       { 0x05, KEY_5 },
-       { 0x06, KEY_6 },
-       { 0x07, KEY_7 },
-       { 0x08, KEY_8 },
-       { 0x09, KEY_9 },
-       { 0x0c, KEY_POWER },
-       { 0x0d, KEY_MUTE },
-       { 0x10, KEY_VOLUMEUP },
-       { 0x11, KEY_VOLUMEDOWN },
-       { 0x20, KEY_CHANNELUP },
-       { 0x21, KEY_CHANNELDOWN },
-       { 0x28, KEY_FORWARD },
-       { 0x29, KEY_REWIND },
-       { 0x2c, KEY_PLAY },
-       { 0x30, KEY_PAUSE },
-       { 0x31, KEY_STOP },
-       { 0x37, KEY_RECORD },
-       { 0x38, KEY_DVD },
-       { 0x39, KEY_TV },
-       { 0x54, KEY_MENU },
-       { 0x58, KEY_UP },
-       { 0x59, KEY_DOWN },
-       { 0x5a, KEY_LEFT },
-       { 0x5b, KEY_RIGHT },
-       { 0x5c, KEY_OK },
-       { 0x78, KEY_A },
-       { 0x79, KEY_B },
-       { 0x7a, KEY_C },
-       { 0x7b, KEY_D },
-       { 0x7c, KEY_E },
-       { 0x7d, KEY_F },
-       { 0x82, KEY_ENTER },
-       { 0x8e, KEY_VENDOR },
-       { 0x96, KEY_COFFEE },
-       { 0xa9, BTN_LEFT },
-       { 0xaa, BTN_RIGHT },
-       { 0xbe, KEY_QUESTION },
-       { 0xd5, KEY_FRONT },
-       { 0xd0, KEY_EDIT },
-       { 0xf9, KEY_INFO },
-       { (0x00 << 8) | 0x3f, KEY_PROG1 },
-       { (0x01 << 8) | 0x3f, KEY_PROG2 },
-       { (0x02 << 8) | 0x3f, KEY_PROG3 },
-       { (0x03 << 8) | 0x3f, KEY_PROG4 },
-       { (0x04 << 8) | 0x3f, KEY_PC },
-       { 0, KEY_RESERVED }
-};
-
-struct ati_remote2 {
-       struct input_dev *idev;
-       struct usb_device *udev;
-
-       struct usb_interface *intf[2];
-       struct usb_endpoint_descriptor *ep[2];
-       struct urb *urb[2];
-       void *buf[2];
-       dma_addr_t buf_dma[2];
-
-       unsigned long jiffies;
-       int mode;
-
-       char name[64];
-       char phys[64];
-};
-
-static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
-static void ati_remote2_disconnect(struct usb_interface *interface);
-
-static struct usb_driver ati_remote2_driver = {
-       .name       = "ati_remote2",
-       .probe      = ati_remote2_probe,
-       .disconnect = ati_remote2_disconnect,
-       .id_table   = ati_remote2_id_table,
-};
-
-static int ati_remote2_open(struct input_dev *idev)
-{
-       struct ati_remote2 *ar2 = input_get_drvdata(idev);
-       int r;
-
-       r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
-       if (r) {
-               dev_err(&ar2->intf[0]->dev,
-                       "%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
-               return r;
-       }
-       r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
-       if (r) {
-               usb_kill_urb(ar2->urb[0]);
-               dev_err(&ar2->intf[1]->dev,
-                       "%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
-               return r;
-       }
-
-       return 0;
-}
-
-static void ati_remote2_close(struct input_dev *idev)
-{
-       struct ati_remote2 *ar2 = input_get_drvdata(idev);
-
-       usb_kill_urb(ar2->urb[0]);
-       usb_kill_urb(ar2->urb[1]);
-}
-
-static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
-{
-       struct input_dev *idev = ar2->idev;
-       u8 *data = ar2->buf[0];
-       int channel, mode;
-
-       channel = data[0] >> 4;
-
-       if (!((1 << channel) & channel_mask))
-               return;
-
-       mode = data[0] & 0x0F;
-
-       if (mode > 4) {
-               dev_err(&ar2->intf[0]->dev,
-                       "Unknown mode byte (%02x %02x %02x %02x)\n",
-                       data[3], data[2], data[1], data[0]);
-               return;
-       }
-
-       if (!((1 << mode) & mode_mask))
-               return;
-
-       input_event(idev, EV_REL, REL_X, (s8) data[1]);
-       input_event(idev, EV_REL, REL_Y, (s8) data[2]);
-       input_sync(idev);
-}
-
-static int ati_remote2_lookup(unsigned int hw_code)
-{
-       int i;
-
-       for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
-               if (ati_remote2_key_table[i].hw_code == hw_code)
-                       return i;
-
-       return -1;
-}
-
-static void ati_remote2_input_key(struct ati_remote2 *ar2)
-{
-       struct input_dev *idev = ar2->idev;
-       u8 *data = ar2->buf[1];
-       int channel, mode, hw_code, index;
-
-       channel = data[0] >> 4;
-
-       if (!((1 << channel) & channel_mask))
-               return;
-
-       mode = data[0] & 0x0F;
-
-       if (mode > 4) {
-               dev_err(&ar2->intf[1]->dev,
-                       "Unknown mode byte (%02x %02x %02x %02x)\n",
-                       data[3], data[2], data[1], data[0]);
-               return;
-       }
-
-       hw_code = data[2];
-       /*
-        * Mode keys (AUX1-AUX4, PC) all generate the same code byte.
-        * Use the mode byte to figure out which one was pressed.
-        */
-       if (hw_code == 0x3f) {
-               /*
-                * For some incomprehensible reason the mouse pad generates
-                * events which look identical to the events from the last
-                * pressed mode key. Naturally we don't want to generate key
-                * events for the mouse pad so we filter out any subsequent
-                * events from the same mode key.
-                */
-               if (ar2->mode == mode)
-                       return;
-
-               if (data[1] == 0)
-                       ar2->mode = mode;
-
-               hw_code |= mode << 8;
-       }
-
-       if (!((1 << mode) & mode_mask))
-               return;
-
-       index = ati_remote2_lookup(hw_code);
-       if (index < 0) {
-               dev_err(&ar2->intf[1]->dev,
-                       "Unknown code byte (%02x %02x %02x %02x)\n",
-                       data[3], data[2], data[1], data[0]);
-               return;
-       }
-
-       switch (data[1]) {
-       case 0: /* release */
-               break;
-       case 1: /* press */
-               ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]);
-               break;
-       case 2: /* repeat */
-
-               /* No repeat for mouse buttons. */
-               if (ati_remote2_key_table[index].key_code == BTN_LEFT ||
-                   ati_remote2_key_table[index].key_code == BTN_RIGHT)
-                       return;
-
-               if (!time_after_eq(jiffies, ar2->jiffies))
-                       return;
-
-               ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]);
-               break;
-       default:
-               dev_err(&ar2->intf[1]->dev,
-                       "Unknown state byte (%02x %02x %02x %02x)\n",
-                       data[3], data[2], data[1], data[0]);
-               return;
-       }
-
-       input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]);
-       input_sync(idev);
-}
-
-static void ati_remote2_complete_mouse(struct urb *urb)
-{
-       struct ati_remote2 *ar2 = urb->context;
-       int r;
-
-       switch (urb->status) {
-       case 0:
-               ati_remote2_input_mouse(ar2);
-               break;
-       case -ENOENT:
-       case -EILSEQ:
-       case -ECONNRESET:
-       case -ESHUTDOWN:
-               dev_dbg(&ar2->intf[0]->dev,
-                       "%s(): urb status = %d\n", __FUNCTION__, urb->status);
-               return;
-       default:
-               dev_err(&ar2->intf[0]->dev,
-                       "%s(): urb status = %d\n", __FUNCTION__, urb->status);
-       }
-
-       r = usb_submit_urb(urb, GFP_ATOMIC);
-       if (r)
-               dev_err(&ar2->intf[0]->dev,
-                       "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
-}
-
-static void ati_remote2_complete_key(struct urb *urb)
-{
-       struct ati_remote2 *ar2 = urb->context;
-       int r;
-
-       switch (urb->status) {
-       case 0:
-               ati_remote2_input_key(ar2);
-               break;
-       case -ENOENT:
-       case -EILSEQ:
-       case -ECONNRESET:
-       case -ESHUTDOWN:
-               dev_dbg(&ar2->intf[1]->dev,
-                       "%s(): urb status = %d\n", __FUNCTION__, urb->status);
-               return;
-       default:
-               dev_err(&ar2->intf[1]->dev,
-                       "%s(): urb status = %d\n", __FUNCTION__, urb->status);
-       }
-
-       r = usb_submit_urb(urb, GFP_ATOMIC);
-       if (r)
-               dev_err(&ar2->intf[1]->dev,
-                       "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
-}
-
-static int ati_remote2_input_init(struct ati_remote2 *ar2)
-{
-       struct input_dev *idev;
-       int i, retval;
-
-       idev = input_allocate_device();
-       if (!idev)
-               return -ENOMEM;
-
-       ar2->idev = idev;
-       input_set_drvdata(idev, ar2);
-
-       idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
-       idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
-       idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-       for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
-               set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
-
-       idev->rep[REP_DELAY]  = 250;
-       idev->rep[REP_PERIOD] = 33;
-
-       idev->open = ati_remote2_open;
-       idev->close = ati_remote2_close;
-
-       idev->name = ar2->name;
-       idev->phys = ar2->phys;
-
-       usb_to_input_id(ar2->udev, &idev->id);
-       idev->dev.parent = &ar2->udev->dev;
-
-       retval = input_register_device(idev);
-       if (retval)
-               input_free_device(idev);
-
-       return retval;
-}
-
-static int ati_remote2_urb_init(struct ati_remote2 *ar2)
-{
-       struct usb_device *udev = ar2->udev;
-       int i, pipe, maxp;
-
-       for (i = 0; i < 2; i++) {
-               ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
-               if (!ar2->buf[i])
-                       return -ENOMEM;
-
-               ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
-               if (!ar2->urb[i])
-                       return -ENOMEM;
-
-               pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
-               maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-               maxp = maxp > 4 ? 4 : maxp;
-
-               usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
-                                i ? ati_remote2_complete_key : ati_remote2_complete_mouse,
-                                ar2, ar2->ep[i]->bInterval);
-               ar2->urb[i]->transfer_dma = ar2->buf_dma[i];
-               ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-       }
-
-       return 0;
-}
-
-static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
-{
-       int i;
-
-       for (i = 0; i < 2; i++) {
-               usb_free_urb(ar2->urb[i]);
-               usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
-       }
-}
-
-static int ati_remote2_setup(struct ati_remote2 *ar2)
-{
-       int r, i, channel;
-
-       /*
-        * Configure receiver to only accept input from remote "channel"
-        *  channel == 0  -> Accept input from any remote channel
-        *  channel == 1  -> Only accept input from remote channel 1
-        *  channel == 2  -> Only accept input from remote channel 2
-        *  ...
-        *  channel == 16 -> Only accept input from remote channel 16
-        */
-
-       channel = 0;
-       for (i = 0; i < 16; i++) {
-               if ((1 << i) & channel_mask) {
-                       if (!(~(1 << i) & 0xFFFF & channel_mask))
-                               channel = i + 1;
-                       break;
-               }
-       }
-
-       r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0),
-                           0x20,
-                           USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-                           channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (r) {
-               dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n",
-                       __FUNCTION__, r);
-               return r;
-       }
-
-       return 0;
-}
-
-static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct usb_host_interface *alt = interface->cur_altsetting;
-       struct ati_remote2 *ar2;
-       int r;
-
-       if (alt->desc.bInterfaceNumber)
-               return -ENODEV;
-
-       ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL);
-       if (!ar2)
-               return -ENOMEM;
-
-       ar2->udev = udev;
-
-       ar2->intf[0] = interface;
-       ar2->ep[0] = &alt->endpoint[0].desc;
-
-       ar2->intf[1] = usb_ifnum_to_if(udev, 1);
-       r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
-       if (r)
-               goto fail1;
-       alt = ar2->intf[1]->cur_altsetting;
-       ar2->ep[1] = &alt->endpoint[0].desc;
-
-       r = ati_remote2_urb_init(ar2);
-       if (r)
-               goto fail2;
-
-       r = ati_remote2_setup(ar2);
-       if (r)
-               goto fail2;
-
-       usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
-       strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
-
-       strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
-
-       r = ati_remote2_input_init(ar2);
-       if (r)
-               goto fail2;
-
-       usb_set_intfdata(interface, ar2);
-
-       return 0;
-
- fail2:
-       ati_remote2_urb_cleanup(ar2);
-
-       usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
- fail1:
-       kfree(ar2);
-
-       return r;
-}
-
-static void ati_remote2_disconnect(struct usb_interface *interface)
-{
-       struct ati_remote2 *ar2;
-       struct usb_host_interface *alt = interface->cur_altsetting;
-
-       if (alt->desc.bInterfaceNumber)
-               return;
-
-       ar2 = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-
-       input_unregister_device(ar2->idev);
-
-       ati_remote2_urb_cleanup(ar2);
-
-       usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
-
-       kfree(ar2);
-}
-
-static int __init ati_remote2_init(void)
-{
-       int r;
-
-       r = usb_register(&ati_remote2_driver);
-       if (r)
-               printk(KERN_ERR "ati_remote2: usb_register() = %d\n", r);
-       else
-               printk(KERN_INFO "ati_remote2: " DRIVER_DESC " " DRIVER_VERSION "\n");
-
-       return r;
-}
-
-static void __exit ati_remote2_exit(void)
-{
-       usb_deregister(&ati_remote2_driver);
-}
-
-module_init(ati_remote2_init);
-module_exit(ati_remote2_exit);
diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c
deleted file mode 100644 (file)
index 1bffc9f..0000000
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * keyspan_remote: USB driver for the Keyspan DMR
- *
- * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com)
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation, version 2.
- *
- * This driver has been put together with the support of Innosys, Inc.
- * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product.
- */
-
-#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/usb/input.h>
-
-#define DRIVER_VERSION "v0.1"
-#define DRIVER_AUTHOR  "Michael Downey <downey@zymeta.com>"
-#define DRIVER_DESC    "Driver for the USB Keyspan remote control."
-#define DRIVER_LICENSE "GPL"
-
-/* Parameters that can be passed to the driver. */
-static int debug;
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
-
-/* Vendor and product ids */
-#define USB_KEYSPAN_VENDOR_ID          0x06CD
-#define USB_KEYSPAN_PRODUCT_UIA11      0x0202
-
-/* Defines for converting the data from the remote. */
-#define ZERO           0x18
-#define ZERO_MASK      0x1F    /* 5 bits for a 0 */
-#define ONE            0x3C
-#define ONE_MASK       0x3F    /* 6 bits for a 1 */
-#define SYNC           0x3F80
-#define SYNC_MASK      0x3FFF  /* 14 bits for a SYNC sequence */
-#define STOP           0x00
-#define STOP_MASK      0x1F    /* 5 bits for the STOP sequence */
-#define GAP            0xFF
-
-#define RECV_SIZE      8       /* The UIA-11 type have a 8 byte limit. */
-
-/* table of devices that work with this driver */
-static struct usb_device_id keyspan_table[] = {
-       { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) },
-       { }                                     /* Terminating entry */
-};
-
-/* Structure to store all the real stuff that a remote sends to us. */
-struct keyspan_message {
-       u16     system;
-       u8      button;
-       u8      toggle;
-};
-
-/* Structure used for all the bit testing magic needed to be done. */
-struct bit_tester {
-       u32     tester;
-       int     len;
-       int     pos;
-       int     bits_left;
-       u8      buffer[32];
-};
-
-/* Structure to hold all of our driver specific stuff */
-struct usb_keyspan {
-       char                            name[128];
-       char                            phys[64];
-       struct usb_device*              udev;
-       struct input_dev                *input;
-       struct usb_interface*           interface;
-       struct usb_endpoint_descriptor* in_endpoint;
-       struct urb*                     irq_urb;
-       int                             open;
-       dma_addr_t                      in_dma;
-       unsigned char*                  in_buffer;
-
-       /* variables used to parse messages from remote. */
-       struct bit_tester               data;
-       int                             stage;
-       int                             toggle;
-};
-
-/*
- * Table that maps the 31 possible keycodes to input keys.
- * Currently there are 15 and 17 button models so RESERVED codes
- * are blank areas in the mapping.
- */
-static const int keyspan_key_table[] = {
-       KEY_RESERVED,           /* 0 is just a place holder. */
-       KEY_RESERVED,
-       KEY_STOP,
-       KEY_PLAYCD,
-       KEY_RESERVED,
-       KEY_PREVIOUSSONG,
-       KEY_REWIND,
-       KEY_FORWARD,
-       KEY_NEXTSONG,
-       KEY_RESERVED,
-       KEY_RESERVED,
-       KEY_RESERVED,
-       KEY_PAUSE,
-       KEY_VOLUMEUP,
-       KEY_RESERVED,
-       KEY_RESERVED,
-       KEY_RESERVED,
-       KEY_VOLUMEDOWN,
-       KEY_RESERVED,
-       KEY_UP,
-       KEY_RESERVED,
-       KEY_MUTE,
-       KEY_LEFT,
-       KEY_ENTER,
-       KEY_RIGHT,
-       KEY_RESERVED,
-       KEY_RESERVED,
-       KEY_DOWN,
-       KEY_RESERVED,
-       KEY_KPASTERISK,
-       KEY_RESERVED,
-       KEY_MENU
-};
-
-static struct usb_driver keyspan_driver;
-
-/*
- * Debug routine that prints out what we've received from the remote.
- */
-static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/
-{
-       char codes[4 * RECV_SIZE];
-       int i;
-
-       for (i = 0; i < RECV_SIZE; i++)
-               snprintf(codes + i * 3, 4, "%02x ", dev->in_buffer[i]);
-
-       dev_info(&dev->udev->dev, "%s\n", codes);
-}
-
-/*
- * Routine that manages the bit_tester structure.  It makes sure that there are
- * at least bits_needed bits loaded into the tester.
- */
-static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
-{
-       if (dev->data.bits_left >= bits_needed)
-               return 0;
-
-       /*
-        * Somehow we've missed the last message. The message will be repeated
-        * though so it's not too big a deal
-        */
-       if (dev->data.pos >= dev->data.len) {
-               dev_dbg(&dev->udev->dev,
-                       "%s - Error ran out of data. pos: %d, len: %d\n",
-                       __FUNCTION__, dev->data.pos, dev->data.len);
-               return -1;
-       }
-
-       /* Load as much as we can into the tester. */
-       while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) &&
-              (dev->data.pos < dev->data.len)) {
-               dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left);
-               dev->data.bits_left += 8;
-       }
-
-       return 0;
-}
-
-/*
- * Routine that handles all the logic needed to parse out the message from the remote.
- */
-static void keyspan_check_data(struct usb_keyspan *remote)
-{
-       int i;
-       int found = 0;
-       struct keyspan_message message;
-
-       switch(remote->stage) {
-       case 0:
-               /*
-                * In stage 0 we want to find the start of a message.  The remote sends a 0xFF as filler.
-                * So the first byte that isn't a FF should be the start of a new message.
-                */
-               for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i);
-
-               if (i < RECV_SIZE) {
-                       memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE);
-                       remote->data.len = RECV_SIZE;
-                       remote->data.pos = 0;
-                       remote->data.tester = 0;
-                       remote->data.bits_left = 0;
-                       remote->stage = 1;
-               }
-               break;
-
-       case 1:
-               /*
-                * Stage 1 we should have 16 bytes and should be able to detect a
-                * SYNC.  The SYNC is 14 bits, 7 0's and then 7 1's.
-                */
-               memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
-               remote->data.len += RECV_SIZE;
-
-               found = 0;
-               while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) {
-                       for (i = 0; i < 8; ++i) {
-                               if (keyspan_load_tester(remote, 14) != 0) {
-                                       remote->stage = 0;
-                                       return;
-                               }
-
-                               if ((remote->data.tester & SYNC_MASK) == SYNC) {
-                                       remote->data.tester = remote->data.tester >> 14;
-                                       remote->data.bits_left -= 14;
-                                       found = 1;
-                                       break;
-                               } else {
-                                       remote->data.tester = remote->data.tester >> 1;
-                                       --remote->data.bits_left;
-                               }
-                       }
-               }
-
-               if (!found) {
-                       remote->stage = 0;
-                       remote->data.len = 0;
-               } else {
-                       remote->stage = 2;
-               }
-               break;
-
-       case 2:
-               /*
-                * Stage 2 we should have 24 bytes which will be enough for a full
-                * message.  We need to parse out the system code, button code,
-                * toggle code, and stop.
-                */
-               memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
-               remote->data.len += RECV_SIZE;
-
-               message.system = 0;
-               for (i = 0; i < 9; i++) {
-                       keyspan_load_tester(remote, 6);
-
-                       if ((remote->data.tester & ZERO_MASK) == ZERO) {
-                               message.system = message.system << 1;
-                               remote->data.tester = remote->data.tester >> 5;
-                               remote->data.bits_left -= 5;
-                       } else if ((remote->data.tester & ONE_MASK) == ONE) {
-                               message.system = (message.system << 1) + 1;
-                               remote->data.tester = remote->data.tester >> 6;
-                               remote->data.bits_left -= 6;
-                       } else {
-                               err("%s - Unknown sequence found in system data.\n", __FUNCTION__);
-                               remote->stage = 0;
-                               return;
-                       }
-               }
-
-               message.button = 0;
-               for (i = 0; i < 5; i++) {
-                       keyspan_load_tester(remote, 6);
-
-                       if ((remote->data.tester & ZERO_MASK) == ZERO) {
-                               message.button = message.button << 1;
-                               remote->data.tester = remote->data.tester >> 5;
-                               remote->data.bits_left -= 5;
-                       } else if ((remote->data.tester & ONE_MASK) == ONE) {
-                               message.button = (message.button << 1) + 1;
-                               remote->data.tester = remote->data.tester >> 6;
-                               remote->data.bits_left -= 6;
-                       } else {
-                               err("%s - Unknown sequence found in button data.\n", __FUNCTION__);
-                               remote->stage = 0;
-                               return;
-                       }
-               }
-
-               keyspan_load_tester(remote, 6);
-               if ((remote->data.tester & ZERO_MASK) == ZERO) {
-                       message.toggle = 0;
-                       remote->data.tester = remote->data.tester >> 5;
-                       remote->data.bits_left -= 5;
-               } else if ((remote->data.tester & ONE_MASK) == ONE) {
-                       message.toggle = 1;
-                       remote->data.tester = remote->data.tester >> 6;
-                       remote->data.bits_left -= 6;
-               } else {
-                       err("%s - Error in message, invalid toggle.\n", __FUNCTION__);
-                       remote->stage = 0;
-                       return;
-               }
-
-               keyspan_load_tester(remote, 5);
-               if ((remote->data.tester & STOP_MASK) == STOP) {
-                       remote->data.tester = remote->data.tester >> 5;
-                       remote->data.bits_left -= 5;
-               } else {
-                       err("Bad message recieved, no stop bit found.\n");
-               }
-
-               dev_dbg(&remote->udev->dev,
-                       "%s found valid message: system: %d, button: %d, toggle: %d\n",
-                       __FUNCTION__, message.system, message.button, message.toggle);
-
-               if (message.toggle != remote->toggle) {
-                       input_report_key(remote->input, keyspan_key_table[message.button], 1);
-                       input_report_key(remote->input, keyspan_key_table[message.button], 0);
-                       input_sync(remote->input);
-                       remote->toggle = message.toggle;
-               }
-
-               remote->stage = 0;
-               break;
-       }
-}
-
-/*
- * Routine for sending all the initialization messages to the remote.
- */
-static int keyspan_setup(struct usb_device* dev)
-{
-       int retval = 0;
-
-       retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                                0x11, 0x40, 0x5601, 0x0, NULL, 0, 0);
-       if (retval) {
-               dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n",
-                       __FUNCTION__, retval);
-               return(retval);
-       }
-
-       retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                                0x44, 0x40, 0x0, 0x0, NULL, 0, 0);
-       if (retval) {
-               dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n",
-                       __FUNCTION__, retval);
-               return(retval);
-       }
-
-       retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                                0x22, 0x40, 0x0, 0x0, NULL, 0, 0);
-       if (retval) {
-               dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n",
-                       __FUNCTION__, retval);
-               return(retval);
-       }
-
-       dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__);
-       return(retval);
-}
-
-/*
- * Routine used to handle a new message that has come in.
- */
-static void keyspan_irq_recv(struct urb *urb)
-{
-       struct usb_keyspan *dev = urb->context;
-       int retval;
-
-       /* Check our status in case we need to bail out early. */
-       switch (urb->status) {
-       case 0:
-               break;
-
-       /* Device went away so don't keep trying to read from it. */
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               return;
-
-       default:
-               goto resubmit;
-               break;
-       }
-
-       if (debug)
-               keyspan_print(dev);
-
-       keyspan_check_data(dev);
-
-resubmit:
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-       if (retval)
-               err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval);
-}
-
-static int keyspan_open(struct input_dev *dev)
-{
-       struct usb_keyspan *remote = input_get_drvdata(dev);
-
-       remote->irq_urb->dev = remote->udev;
-       if (usb_submit_urb(remote->irq_urb, GFP_KERNEL))
-               return -EIO;
-
-       return 0;
-}
-
-static void keyspan_close(struct input_dev *dev)
-{
-       struct usb_keyspan *remote = input_get_drvdata(dev);
-
-       usb_kill_urb(remote->irq_urb);
-}
-
-static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface)
-{
-
-       struct usb_endpoint_descriptor *endpoint;
-       int i;
-
-       for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
-               endpoint = &iface->endpoint[i].desc;
-
-               if (usb_endpoint_is_int_in(endpoint)) {
-                       /* we found our interrupt in endpoint */
-                       return endpoint;
-               }
-       }
-
-       return NULL;
-}
-
-/*
- * Routine that sets up the driver to handle a specific USB device detected on the bus.
- */
-static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct usb_endpoint_descriptor *endpoint;
-       struct usb_keyspan *remote;
-       struct input_dev *input_dev;
-       int i, error;
-
-       endpoint = keyspan_get_in_endpoint(interface->cur_altsetting);
-       if (!endpoint)
-               return -ENODEV;
-
-       remote = kzalloc(sizeof(*remote), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!remote || !input_dev) {
-               error = -ENOMEM;
-               goto fail1;
-       }
-
-       remote->udev = udev;
-       remote->input = input_dev;
-       remote->interface = interface;
-       remote->in_endpoint = endpoint;
-       remote->toggle = -1;    /* Set to -1 so we will always not match the toggle from the first remote message. */
-
-       remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
-       if (!remote->in_buffer) {
-               error = -ENOMEM;
-               goto fail1;
-       }
-
-       remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!remote->irq_urb) {
-               error = -ENOMEM;
-               goto fail2;
-       }
-
-       error = keyspan_setup(udev);
-       if (error) {
-               error = -ENODEV;
-               goto fail3;
-       }
-
-       if (udev->manufacturer)
-               strlcpy(remote->name, udev->manufacturer, sizeof(remote->name));
-
-       if (udev->product) {
-               if (udev->manufacturer)
-                       strlcat(remote->name, " ", sizeof(remote->name));
-               strlcat(remote->name, udev->product, sizeof(remote->name));
-       }
-
-       if (!strlen(remote->name))
-               snprintf(remote->name, sizeof(remote->name),
-                        "USB Keyspan Remote %04x:%04x",
-                        le16_to_cpu(udev->descriptor.idVendor),
-                        le16_to_cpu(udev->descriptor.idProduct));
-
-       usb_make_path(udev, remote->phys, sizeof(remote->phys));
-       strlcat(remote->phys, "/input0", sizeof(remote->phys));
-
-       input_dev->name = remote->name;
-       input_dev->phys = remote->phys;
-       usb_to_input_id(udev, &input_dev->id);
-       input_dev->dev.parent = &interface->dev;
-
-       input_dev->evbit[0] = BIT(EV_KEY);              /* We will only report KEY events. */
-       for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++)
-               if (keyspan_key_table[i] != KEY_RESERVED)
-                       set_bit(keyspan_key_table[i], input_dev->keybit);
-
-       input_set_drvdata(input_dev, remote);
-
-       input_dev->open = keyspan_open;
-       input_dev->close = keyspan_close;
-
-       /*
-        * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open()
-        */
-       usb_fill_int_urb(remote->irq_urb,
-                        remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress),
-                        remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote,
-                        remote->in_endpoint->bInterval);
-       remote->irq_urb->transfer_dma = remote->in_dma;
-       remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       /* we can register the device now, as it is ready */
-       error = input_register_device(remote->input);
-       if (error)
-               goto fail3;
-
-       /* save our data pointer in this interface device */
-       usb_set_intfdata(interface, remote);
-
-       return 0;
-
- fail3:        usb_free_urb(remote->irq_urb);
- fail2:        usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
- fail1:        kfree(remote);
-       input_free_device(input_dev);
-
-       return error;
-}
-
-/*
- * Routine called when a device is disconnected from the USB.
- */
-static void keyspan_disconnect(struct usb_interface *interface)
-{
-       struct usb_keyspan *remote;
-
-       remote = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-
-       if (remote) {   /* We have a valid driver structure so clean up everything we allocated. */
-               input_unregister_device(remote->input);
-               usb_kill_urb(remote->irq_urb);
-               usb_free_urb(remote->irq_urb);
-               usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
-               kfree(remote);
-       }
-}
-
-/*
- * Standard driver set up sections
- */
-static struct usb_driver keyspan_driver =
-{
-       .name =         "keyspan_remote",
-       .probe =        keyspan_probe,
-       .disconnect =   keyspan_disconnect,
-       .id_table =     keyspan_table
-};
-
-static int __init usb_keyspan_init(void)
-{
-       int result;
-
-       /* register this driver with the USB subsystem */
-       result = usb_register(&keyspan_driver);
-       if (result)
-               err("usb_register failed. Error number %d\n", result);
-
-       return result;
-}
-
-static void __exit usb_keyspan_exit(void)
-{
-       /* deregister this driver with the USB subsystem */
-       usb_deregister(&keyspan_driver);
-}
-
-module_init(usb_keyspan_init);
-module_exit(usb_keyspan_exit);
-
-MODULE_DEVICE_TABLE(usb, keyspan_table);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/usb/input/map_to_7segment.h b/drivers/usb/input/map_to_7segment.h
deleted file mode 100644 (file)
index a424094..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * drivers/usb/input/map_to_7segment.h
- *
- * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef MAP_TO_7SEGMENT_H
-#define MAP_TO_7SEGMENT_H
-
-/* This file provides translation primitives and tables for the conversion
- * of (ASCII) characters to a 7-segments notation.
- *
- * The 7 segment's wikipedia notation below is used as standard.
- * See: http://en.wikipedia.org/wiki/Seven_segment_display
- *
- * Notation:   +-a-+
- *             f   b
- *             +-g-+
- *             e   c
- *             +-d-+
- *
- * Usage:
- *
- *   Register a map variable, and fill it with a character set:
- *     static SEG7_DEFAULT_MAP(map_seg7);
- *
- *
- *   Then use for conversion:
- *     seg7 = map_to_seg7(&map_seg7, some_char);
- *     ...
- *
- * In device drivers it is recommended, if required, to make the char map
- * accessible via the sysfs interface using the following scheme:
- *
- * static ssize_t show_map(struct device *dev, char *buf) {
- *     memcpy(buf, &map_seg7, sizeof(map_seg7));
- *     return sizeof(map_seg7);
- * }
- * static ssize_t store_map(struct device *dev, const char *buf, size_t cnt) {
- *     if(cnt != sizeof(map_seg7))
- *             return -EINVAL;
- *     memcpy(&map_seg7, buf, cnt);
- *     return cnt;
- * }
- * static DEVICE_ATTR(map_seg7, PERMS_RW, show_map, store_map);
- *
- * History:
- * 2005-05-31  RFC linux-kernel@vger.kernel.org
- */
-#include <linux/errno.h>
-
-
-#define BIT_SEG7_A             0
-#define BIT_SEG7_B             1
-#define BIT_SEG7_C             2
-#define BIT_SEG7_D             3
-#define BIT_SEG7_E             4
-#define BIT_SEG7_F             5
-#define BIT_SEG7_G             6
-#define BIT_SEG7_RESERVED      7
-
-struct seg7_conversion_map {
-       unsigned char   table[128];
-};
-
-static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
-{
-       return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL;
-}
-
-#define SEG7_CONVERSION_MAP(_name, _map)       \
-       struct seg7_conversion_map _name = { .table = { _map } }
-
-/*
- * It is recommended to use a facility that allows user space to redefine
- * custom character sets for LCD devices. Please use a sysfs interface
- * as described above.
- */
-#define MAP_TO_SEG7_SYSFS_FILE "map_seg7"
-
-/*******************************************************************************
- * ASCII conversion table
- ******************************************************************************/
-
-#define _SEG7(l,a,b,c,d,e,f,g) \
-      (        a<<BIT_SEG7_A | b<<BIT_SEG7_B | c<<BIT_SEG7_C | d<<BIT_SEG7_D | \
-       e<<BIT_SEG7_E | f<<BIT_SEG7_F | g<<BIT_SEG7_G )
-
-#define _MAP_0_32_ASCII_SEG7_NON_PRINTABLE     \
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-
-#define _MAP_33_47_ASCII_SEG7_SYMBOL           \
- _SEG7('!',0,0,0,0,1,1,0), _SEG7('"',0,1,0,0,0,1,0), _SEG7('#',0,1,1,0,1,1,0),\
- _SEG7('$',1,0,1,1,0,1,1), _SEG7('%',0,0,1,0,0,1,0), _SEG7('&',1,0,1,1,1,1,1),\
- _SEG7('\'',0,0,0,0,0,1,0),_SEG7('(',1,0,0,1,1,1,0), _SEG7(')',1,1,1,1,0,0,0),\
- _SEG7('*',0,1,1,0,1,1,1), _SEG7('+',0,1,1,0,0,0,1), _SEG7(',',0,0,0,0,1,0,0),\
- _SEG7('-',0,0,0,0,0,0,1), _SEG7('.',0,0,0,0,1,0,0), _SEG7('/',0,1,0,0,1,0,1),
-
-#define _MAP_48_57_ASCII_SEG7_NUMERIC          \
- _SEG7('0',1,1,1,1,1,1,0), _SEG7('1',0,1,1,0,0,0,0), _SEG7('2',1,1,0,1,1,0,1),\
- _SEG7('3',1,1,1,1,0,0,1), _SEG7('4',0,1,1,0,0,1,1), _SEG7('5',1,0,1,1,0,1,1),\
- _SEG7('6',1,0,1,1,1,1,1), _SEG7('7',1,1,1,0,0,0,0), _SEG7('8',1,1,1,1,1,1,1),\
- _SEG7('9',1,1,1,1,0,1,1),
-
-#define _MAP_58_64_ASCII_SEG7_SYMBOL           \
- _SEG7(':',0,0,0,1,0,0,1), _SEG7(';',0,0,0,1,0,0,1), _SEG7('<',1,0,0,0,0,1,1),\
- _SEG7('=',0,0,0,1,0,0,1), _SEG7('>',1,1,0,0,0,0,1), _SEG7('?',1,1,1,0,0,1,0),\
- _SEG7('@',1,1,0,1,1,1,1),
-
-#define _MAP_65_90_ASCII_SEG7_ALPHA_UPPR       \
- _SEG7('A',1,1,1,0,1,1,1), _SEG7('B',1,1,1,1,1,1,1), _SEG7('C',1,0,0,1,1,1,0),\
- _SEG7('D',1,1,1,1,1,1,0), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
- _SEG7('G',1,1,1,1,0,1,1), _SEG7('H',0,1,1,0,1,1,1), _SEG7('I',0,1,1,0,0,0,0),\
- _SEG7('J',0,1,1,1,0,0,0), _SEG7('K',0,1,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
- _SEG7('M',1,1,1,0,1,1,0), _SEG7('N',1,1,1,0,1,1,0), _SEG7('O',1,1,1,1,1,1,0),\
- _SEG7('P',1,1,0,0,1,1,1), _SEG7('Q',1,1,1,1,1,1,0), _SEG7('R',1,1,1,0,1,1,1),\
- _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('U',0,1,1,1,1,1,0),\
- _SEG7('V',0,1,1,1,1,1,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
- _SEG7('Y',0,1,1,0,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
-
-#define _MAP_91_96_ASCII_SEG7_SYMBOL           \
- _SEG7('[',1,0,0,1,1,1,0), _SEG7('\\',0,0,1,0,0,1,1),_SEG7(']',1,1,1,1,0,0,0),\
- _SEG7('^',1,1,0,0,0,1,0), _SEG7('_',0,0,0,1,0,0,0), _SEG7('`',0,1,0,0,0,0,0),
-
-#define _MAP_97_122_ASCII_SEG7_ALPHA_LOWER     \
- _SEG7('A',1,1,1,0,1,1,1), _SEG7('b',0,0,1,1,1,1,1), _SEG7('c',0,0,0,1,1,0,1),\
- _SEG7('d',0,1,1,1,1,0,1), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
- _SEG7('G',1,1,1,1,0,1,1), _SEG7('h',0,0,1,0,1,1,1), _SEG7('i',0,0,1,0,0,0,0),\
- _SEG7('j',0,0,1,1,0,0,0), _SEG7('k',0,0,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
- _SEG7('M',1,1,1,0,1,1,0), _SEG7('n',0,0,1,0,1,0,1), _SEG7('o',0,0,1,1,1,0,1),\
- _SEG7('P',1,1,0,0,1,1,1), _SEG7('q',1,1,1,0,0,1,1), _SEG7('r',0,0,0,0,1,0,1),\
- _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('u',0,0,1,1,1,0,0),\
- _SEG7('v',0,0,1,1,1,0,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
- _SEG7('y',0,1,1,1,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
-
-#define _MAP_123_126_ASCII_SEG7_SYMBOL         \
- _SEG7('{',1,0,0,1,1,1,0), _SEG7('|',0,0,0,0,1,1,0), _SEG7('}',1,1,1,1,0,0,0),\
- _SEG7('~',1,0,0,0,0,0,0),
-
-/* Maps */
-
-/* This set tries to map as close as possible to the visible characteristics
- * of the ASCII symbol, lowercase and uppercase letters may differ in
- * presentation on the display.
- */
-#define MAP_ASCII7SEG_ALPHANUM                 \
-       _MAP_0_32_ASCII_SEG7_NON_PRINTABLE      \
-       _MAP_33_47_ASCII_SEG7_SYMBOL            \
-       _MAP_48_57_ASCII_SEG7_NUMERIC           \
-       _MAP_58_64_ASCII_SEG7_SYMBOL            \
-       _MAP_65_90_ASCII_SEG7_ALPHA_UPPR        \
-       _MAP_91_96_ASCII_SEG7_SYMBOL            \
-       _MAP_97_122_ASCII_SEG7_ALPHA_LOWER      \
-       _MAP_123_126_ASCII_SEG7_SYMBOL
-
-/* This set tries to map as close as possible to the symbolic characteristics
- * of the ASCII character for maximum discrimination.
- * For now this means all alpha chars are in lower case representations.
- * (This for example facilitates the use of hex numbers with uppercase input.)
- */
-#define MAP_ASCII7SEG_ALPHANUM_LC                      \
-       _MAP_0_32_ASCII_SEG7_NON_PRINTABLE      \
-       _MAP_33_47_ASCII_SEG7_SYMBOL            \
-       _MAP_48_57_ASCII_SEG7_NUMERIC           \
-       _MAP_58_64_ASCII_SEG7_SYMBOL            \
-       _MAP_97_122_ASCII_SEG7_ALPHA_LOWER      \
-       _MAP_91_96_ASCII_SEG7_SYMBOL            \
-       _MAP_97_122_ASCII_SEG7_ALPHA_LOWER      \
-       _MAP_123_126_ASCII_SEG7_SYMBOL
-
-#define SEG7_DEFAULT_MAP(_name)                \
-       SEG7_CONVERSION_MAP(_name,MAP_ASCII7SEG_ALPHANUM)
-
-#endif /* MAP_TO_7SEGMENT_H */
-
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
deleted file mode 100644 (file)
index 448a470..0000000
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
- *
- * v1.1, (c)2002 William R Sowerbutts <will@sowerbutts.com>
- *
- * This device is a anodised aluminium knob which connects over USB. It can measure
- * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
- * a spring for automatic release. The base contains a pair of LEDs which illuminate
- * the translucent base. It rotates without limit and reports its relative rotation
- * back to the host when polled by the USB controller.
- *
- * Testing with the knob I have has shown that it measures approximately 94 "clicks"
- * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
- * a variable speed cordless electric drill) has shown that the device can measure
- * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
- * the host. If it counts more than 7 clicks before it is polled, it will wrap back
- * to zero and start counting again. This was at quite high speed, however, almost
- * certainly faster than the human hand could turn it. Griffin say that it loses a
- * pulse or two on a direction change; the granularity is so fine that I never
- * noticed this in practice.
- *
- * The device's microcontroller can be programmed to set the LED to either a constant
- * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
- *
- * Griffin were very happy to provide documentation and free hardware for development.
- *
- * Some userspace tools are available on the web: http://sowerbutts.com/powermate/
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/usb/input.h>
-
-#define POWERMATE_VENDOR       0x077d  /* Griffin Technology, Inc. */
-#define POWERMATE_PRODUCT_NEW  0x0410  /* Griffin PowerMate */
-#define POWERMATE_PRODUCT_OLD  0x04AA  /* Griffin soundKnob */
-
-#define CONTOUR_VENDOR         0x05f3  /* Contour Design, Inc. */
-#define CONTOUR_JOG            0x0240  /* Jog and Shuttle */
-
-/* these are the command codes we send to the device */
-#define SET_STATIC_BRIGHTNESS  0x01
-#define SET_PULSE_ASLEEP       0x02
-#define SET_PULSE_AWAKE        0x03
-#define SET_PULSE_MODE         0x04
-
-/* these refer to bits in the powermate_device's requires_update field. */
-#define UPDATE_STATIC_BRIGHTNESS (1<<0)
-#define UPDATE_PULSE_ASLEEP      (1<<1)
-#define UPDATE_PULSE_AWAKE       (1<<2)
-#define UPDATE_PULSE_MODE        (1<<3)
-
-/* at least two versions of the hardware exist, with differing payload
-   sizes. the first three bytes always contain the "interesting" data in
-   the relevant format. */
-#define POWERMATE_PAYLOAD_SIZE_MAX 6
-#define POWERMATE_PAYLOAD_SIZE_MIN 3
-struct powermate_device {
-       signed char *data;
-       dma_addr_t data_dma;
-       struct urb *irq, *config;
-       struct usb_ctrlrequest *configcr;
-       dma_addr_t configcr_dma;
-       struct usb_device *udev;
-       struct input_dev *input;
-       spinlock_t lock;
-       int static_brightness;
-       int pulse_speed;
-       int pulse_table;
-       int pulse_asleep;
-       int pulse_awake;
-       int requires_update; // physical settings which are out of sync
-       char phys[64];
-};
-
-static char pm_name_powermate[] = "Griffin PowerMate";
-static char pm_name_soundknob[] = "Griffin SoundKnob";
-
-static void powermate_config_complete(struct urb *urb);
-
-/* Callback for data arriving from the PowerMate over the USB interrupt pipe */
-static void powermate_irq(struct urb *urb)
-{
-       struct powermate_device *pm = urb->context;
-       int retval;
-
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-               return;
-       default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-               goto exit;
-       }
-
-       /* handle updates to device state */
-       input_report_key(pm->input, BTN_0, pm->data[0] & 0x01);
-       input_report_rel(pm->input, REL_DIAL, pm->data[1]);
-       input_sync(pm->input);
-
-exit:
-       retval = usb_submit_urb (urb, GFP_ATOMIC);
-       if (retval)
-               err ("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, retval);
-}
-
-/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
-static void powermate_sync_state(struct powermate_device *pm)
-{
-       if (pm->requires_update == 0)
-               return; /* no updates are required */
-       if (pm->config->status == -EINPROGRESS)
-               return; /* an update is already in progress; it'll issue this update when it completes */
-
-       if (pm->requires_update & UPDATE_PULSE_ASLEEP){
-               pm->configcr->wValue = cpu_to_le16( SET_PULSE_ASLEEP );
-               pm->configcr->wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
-               pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
-       }else if (pm->requires_update & UPDATE_PULSE_AWAKE){
-               pm->configcr->wValue = cpu_to_le16( SET_PULSE_AWAKE );
-               pm->configcr->wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
-               pm->requires_update &= ~UPDATE_PULSE_AWAKE;
-       }else if (pm->requires_update & UPDATE_PULSE_MODE){
-               int op, arg;
-               /* the powermate takes an operation and an argument for its pulse algorithm.
-                  the operation can be:
-                  0: divide the speed
-                  1: pulse at normal speed
-                  2: multiply the speed
-                  the argument only has an effect for operations 0 and 2, and ranges between
-                  1 (least effect) to 255 (maximum effect).
-
-                  thus, several states are equivalent and are coalesced into one state.
-
-                  we map this onto a range from 0 to 510, with:
-                  0 -- 254    -- use divide (0 = slowest)
-                  255         -- use normal speed
-                  256 -- 510  -- use multiple (510 = fastest).
-
-                  Only values of 'arg' quite close to 255 are particularly useful/spectacular.
-               */
-               if (pm->pulse_speed < 255) {
-                       op = 0;                   // divide
-                       arg = 255 - pm->pulse_speed;
-               } else if (pm->pulse_speed > 255) {
-                       op = 2;                   // multiply
-                       arg = pm->pulse_speed - 255;
-               } else {
-                       op = 1;                   // normal speed
-                       arg = 0;                  // can be any value
-               }
-               pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
-               pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op );
-               pm->requires_update &= ~UPDATE_PULSE_MODE;
-       } else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) {
-               pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
-               pm->configcr->wIndex = cpu_to_le16( pm->static_brightness );
-               pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
-       } else {
-               printk(KERN_ERR "powermate: unknown update required");
-               pm->requires_update = 0; /* fudge the bug */
-               return;
-       }
-
-/*     printk("powermate: %04x %04x\n", pm->configcr->wValue, pm->configcr->wIndex); */
-
-       pm->configcr->bRequestType = 0x41; /* vendor request */
-       pm->configcr->bRequest = 0x01;
-       pm->configcr->wLength = 0;
-
-       usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0),
-                            (void *) pm->configcr, NULL, 0,
-                            powermate_config_complete, pm);
-       pm->config->setup_dma = pm->configcr_dma;
-       pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP;
-
-       if (usb_submit_urb(pm->config, GFP_ATOMIC))
-               printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
-}
-
-/* Called when our asynchronous control message completes. We may need to issue another immediately */
-static void powermate_config_complete(struct urb *urb)
-{
-       struct powermate_device *pm = urb->context;
-       unsigned long flags;
-
-       if (urb->status)
-               printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
-
-       spin_lock_irqsave(&pm->lock, flags);
-       powermate_sync_state(pm);
-       spin_unlock_irqrestore(&pm->lock, flags);
-}
-
-/* Set the LED up as described and begin the sync with the hardware if required */
-static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
-                               int pulse_table, int pulse_asleep, int pulse_awake)
-{
-       unsigned long flags;
-
-       if (pulse_speed < 0)
-               pulse_speed = 0;
-       if (pulse_table < 0)
-               pulse_table = 0;
-       if (pulse_speed > 510)
-               pulse_speed = 510;
-       if (pulse_table > 2)
-               pulse_table = 2;
-
-       pulse_asleep = !!pulse_asleep;
-       pulse_awake = !!pulse_awake;
-
-
-       spin_lock_irqsave(&pm->lock, flags);
-
-       /* mark state updates which are required */
-       if (static_brightness != pm->static_brightness) {
-               pm->static_brightness = static_brightness;
-               pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
-       }
-       if (pulse_asleep != pm->pulse_asleep) {
-               pm->pulse_asleep = pulse_asleep;
-               pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS);
-       }
-       if (pulse_awake != pm->pulse_awake) {
-               pm->pulse_awake = pulse_awake;
-               pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS);
-       }
-       if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) {
-               pm->pulse_speed = pulse_speed;
-               pm->pulse_table = pulse_table;
-               pm->requires_update |= UPDATE_PULSE_MODE;
-       }
-
-       powermate_sync_state(pm);
-
-       spin_unlock_irqrestore(&pm->lock, flags);
-}
-
-/* Callback from the Input layer when an event arrives from userspace to configure the LED */
-static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
-{
-       unsigned int command = (unsigned int)_value;
-       struct powermate_device *pm = input_get_drvdata(dev);
-
-       if (type == EV_MSC && code == MSC_PULSELED){
-               /*
-                   bits  0- 7: 8 bits: LED brightness
-                   bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
-                   bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
-                   bit     19: 1 bit : pulse whilst asleep?
-                   bit     20: 1 bit : pulse constantly?
-               */
-               int static_brightness = command & 0xFF;   // bits 0-7
-               int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
-               int pulse_table = (command >> 17) & 0x3;  // bits 17-18
-               int pulse_asleep = (command >> 19) & 0x1; // bit 19
-               int pulse_awake  = (command >> 20) & 0x1; // bit 20
-
-               powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
-       }
-
-       return 0;
-}
-
-static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm)
-{
-       pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX,
-                                   GFP_ATOMIC, &pm->data_dma);
-       if (!pm->data)
-               return -1;
-
-       pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)),
-                                       GFP_ATOMIC, &pm->configcr_dma);
-       if (!pm->configcr)
-               return -1;
-
-       return 0;
-}
-
-static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm)
-{
-       usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX,
-                       pm->data, pm->data_dma);
-       usb_buffer_free(udev, sizeof(*(pm->configcr)),
-                       pm->configcr, pm->configcr_dma);
-}
-
-/* Called whenever a USB device matching one in our supported devices table is connected */
-static int powermate_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev (intf);
-       struct usb_host_interface *interface;
-       struct usb_endpoint_descriptor *endpoint;
-       struct powermate_device *pm;
-       struct input_dev *input_dev;
-       int pipe, maxp;
-       int error = -ENOMEM;
-
-       interface = intf->cur_altsetting;
-       endpoint = &interface->endpoint[0].desc;
-       if (!usb_endpoint_is_int_in(endpoint))
-               return -EIO;
-
-       usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-               0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, interface->desc.bInterfaceNumber, NULL, 0,
-               USB_CTRL_SET_TIMEOUT);
-
-       pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!pm || !input_dev)
-               goto fail1;
-
-       if (powermate_alloc_buffers(udev, pm))
-               goto fail2;
-
-       pm->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!pm->irq)
-               goto fail2;
-
-       pm->config = usb_alloc_urb(0, GFP_KERNEL);
-       if (!pm->config)
-               goto fail3;
-
-       pm->udev = udev;
-       pm->input = input_dev;
-
-       usb_make_path(udev, pm->phys, sizeof(pm->phys));
-       strlcpy(pm->phys, "/input0", sizeof(pm->phys));
-
-       spin_lock_init(&pm->lock);
-
-       switch (le16_to_cpu(udev->descriptor.idProduct)) {
-       case POWERMATE_PRODUCT_NEW:
-               input_dev->name = pm_name_powermate;
-               break;
-       case POWERMATE_PRODUCT_OLD:
-               input_dev->name = pm_name_soundknob;
-               break;
-       default:
-               input_dev->name = pm_name_soundknob;
-               printk(KERN_WARNING "powermate: unknown product id %04x\n",
-                      le16_to_cpu(udev->descriptor.idProduct));
-       }
-
-       input_dev->phys = pm->phys;
-       usb_to_input_id(udev, &input_dev->id);
-       input_dev->dev.parent = &intf->dev;
-
-       input_set_drvdata(input_dev, pm);
-
-       input_dev->event = powermate_input_event;
-
-       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
-       input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
-       input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
-       input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
-
-       /* get a handle to the interrupt data pipe */
-       pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
-       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-
-       if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) {
-               printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n",
-                       POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp);
-               maxp = POWERMATE_PAYLOAD_SIZE_MAX;
-       }
-
-       usb_fill_int_urb(pm->irq, udev, pipe, pm->data,
-                        maxp, powermate_irq,
-                        pm, endpoint->bInterval);
-       pm->irq->transfer_dma = pm->data_dma;
-       pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       /* register our interrupt URB with the USB system */
-       if (usb_submit_urb(pm->irq, GFP_KERNEL)) {
-               error = -EIO;
-               goto fail4;
-       }
-
-       error = input_register_device(pm->input);
-       if (error)
-               goto fail5;
-
-
-       /* force an update of everything */
-       pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
-       powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
-
-       usb_set_intfdata(intf, pm);
-       return 0;
-
- fail5:        usb_kill_urb(pm->irq);
- fail4:        usb_free_urb(pm->config);
- fail3:        usb_free_urb(pm->irq);
- fail2:        powermate_free_buffers(udev, pm);
- fail1:        input_free_device(input_dev);
-       kfree(pm);
-       return error;
-}
-
-/* Called when a USB device we've accepted ownership of is removed */
-static void powermate_disconnect(struct usb_interface *intf)
-{
-       struct powermate_device *pm = usb_get_intfdata (intf);
-
-       usb_set_intfdata(intf, NULL);
-       if (pm) {
-               pm->requires_update = 0;
-               usb_kill_urb(pm->irq);
-               input_unregister_device(pm->input);
-               usb_free_urb(pm->irq);
-               usb_free_urb(pm->config);
-               powermate_free_buffers(interface_to_usbdev(intf), pm);
-
-               kfree(pm);
-       }
-}
-
-static struct usb_device_id powermate_devices [] = {
-       { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
-       { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
-       { USB_DEVICE(CONTOUR_VENDOR, CONTOUR_JOG) },
-       { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, powermate_devices);
-
-static struct usb_driver powermate_driver = {
-        .name =         "powermate",
-        .probe =        powermate_probe,
-        .disconnect =   powermate_disconnect,
-        .id_table =     powermate_devices,
-};
-
-static int __init powermate_init(void)
-{
-       return usb_register(&powermate_driver);
-}
-
-static void __exit powermate_cleanup(void)
-{
-       usb_deregister(&powermate_driver);
-}
-
-module_init(powermate_init);
-module_exit(powermate_cleanup);
-
-MODULE_AUTHOR( "William R Sowerbutts" );
-MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c
deleted file mode 100644 (file)
index fc645b2..0000000
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * drivers/usb/input/yealink.c
- *
- * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-/*
- * Description:
- *   Driver for the USB-P1K voip usb phone.
- *   This device is produced by Yealink Network Technology Co Ltd
- *   but may be branded under several names:
- *     - Yealink usb-p1k
- *     - Tiptel 115
- *     - ...
- *
- * This driver is based on:
- *   - the usbb2k-api  http://savannah.nongnu.org/projects/usbb2k-api/
- *   - information from        http://memeteau.free.fr/usbb2k
- *   - the xpad-driver drivers/usb/input/xpad.c
- *
- * Thanks to:
- *   - Olivier Vandorpe, for providing the usbb2k-api.
- *   - Martin Diehl, for spotting my memory allocation bug.
- *
- * History:
- *   20050527 henk     First version, functional keyboard. Keyboard events
- *                     will pop-up on the ../input/eventX bus.
- *   20050531 henk     Added led, LCD, dialtone and sysfs interface.
- *   20050610 henk     Cleanups, make it ready for public consumption.
- *   20050630 henk     Cleanups, fixes in response to comments.
- *   20050701 henk     sysfs write serialisation, fix potential unload races
- *   20050801 henk     Added ringtone, restructure USB
- *   20050816 henk     Merge 2.6.13-rc6
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/rwsem.h>
-#include <linux/usb/input.h>
-
-#include "map_to_7segment.h"
-#include "yealink.h"
-
-#define DRIVER_VERSION "yld-20051230"
-#define DRIVER_AUTHOR "Henk Vergonet"
-#define DRIVER_DESC "Yealink phone driver"
-
-#define YEALINK_POLLING_FREQUENCY      10      /* in [Hz] */
-
-struct yld_status {
-       u8      lcd[24];
-       u8      led;
-       u8      dialtone;
-       u8      ringtone;
-       u8      keynum;
-} __attribute__ ((packed));
-
-/*
- * Register the LCD segment and icon map
- */
-#define _LOC(k,l)      { .a = (k), .m = (l) }
-#define _SEG(t, a, am, b, bm, c, cm, d, dm, e, em, f, fm, g, gm)       \
-       { .type = (t),                                                  \
-         .u = { .s = { _LOC(a, am), _LOC(b, bm), _LOC(c, cm),          \
-                       _LOC(d, dm), _LOC(e, em), _LOC(g, gm),          \
-                       _LOC(f, fm) } } }
-#define _PIC(t, h, hm, n)                                              \
-       { .type = (t),                                                  \
-         .u = { .p = { .name = (n), .a = (h), .m = (hm) } } }
-
-static const struct lcd_segment_map {
-       char    type;
-       union {
-               struct pictogram_map {
-                       u8      a,m;
-                       char    name[10];
-               }       p;
-               struct segment_map {
-                       u8      a,m;
-               } s[7];
-       } u;
-} lcdMap[] = {
-#include "yealink.h"
-};
-
-struct yealink_dev {
-       struct input_dev *idev;         /* input device */
-       struct usb_device *udev;        /* usb device */
-
-       /* irq input channel */
-       struct yld_ctl_packet   *irq_data;
-       dma_addr_t              irq_dma;
-       struct urb              *urb_irq;
-
-       /* control output channel */
-       struct yld_ctl_packet   *ctl_data;
-       dma_addr_t              ctl_dma;
-       struct usb_ctrlrequest  *ctl_req;
-       dma_addr_t              ctl_req_dma;
-       struct urb              *urb_ctl;
-
-       char phys[64];                  /* physical device path */
-
-       u8 lcdMap[ARRAY_SIZE(lcdMap)];  /* state of LCD, LED ... */
-       int key_code;                   /* last reported key     */
-
-       int     stat_ix;
-       union {
-               struct yld_status s;
-               u8                b[sizeof(struct yld_status)];
-       } master, copy;
-};
-
-
-/*******************************************************************************
- * Yealink lcd interface
- ******************************************************************************/
-
-/*
- * Register a default 7 segment character set
- */
-static SEG7_DEFAULT_MAP(map_seg7);
-
- /* Display a char,
-  * char '\9' and '\n' are placeholders and do not overwrite the original text.
-  * A space will always hide an icon.
-  */
-static int setChar(struct yealink_dev *yld, int el, int chr)
-{
-       int i, a, m, val;
-
-       if (el >= ARRAY_SIZE(lcdMap))
-               return -EINVAL;
-
-       if (chr == '\t' || chr == '\n')
-           return 0;
-
-       yld->lcdMap[el] = chr;
-
-       if (lcdMap[el].type == '.') {
-               a = lcdMap[el].u.p.a;
-               m = lcdMap[el].u.p.m;
-               if (chr != ' ')
-                       yld->master.b[a] |= m;
-               else
-                       yld->master.b[a] &= ~m;
-               return 0;
-       }
-
-       val = map_to_seg7(&map_seg7, chr);
-       for (i = 0; i < ARRAY_SIZE(lcdMap[0].u.s); i++) {
-               m = lcdMap[el].u.s[i].m;
-
-               if (m == 0)
-                       continue;
-
-               a = lcdMap[el].u.s[i].a;
-               if (val & 1)
-                       yld->master.b[a] |= m;
-               else
-                       yld->master.b[a] &= ~m;
-               val = val >> 1;
-       }
-       return 0;
-};
-
-/*******************************************************************************
- * Yealink key interface
- ******************************************************************************/
-
-/* Map device buttons to internal key events.
- *
- * USB-P1K button layout:
- *
- *             up
- *       IN           OUT
- *            down
- *
- *     pickup   C    hangup
- *       1      2      3
- *       4      5      6
- *       7      8      9
- *       *      0      #
- *
- * The "up" and "down" keys, are symbolised by arrows on the button.
- * The "pickup" and "hangup" keys are symbolised by a green and red phone
- * on the button.
- */
-static int map_p1k_to_key(int scancode)
-{
-       switch(scancode) {              /* phone key:   */
-       case 0x23: return KEY_LEFT;     /*   IN         */
-       case 0x33: return KEY_UP;       /*   up         */
-       case 0x04: return KEY_RIGHT;    /*   OUT        */
-       case 0x24: return KEY_DOWN;     /*   down       */
-       case 0x03: return KEY_ENTER;    /*   pickup     */
-       case 0x14: return KEY_BACKSPACE; /*  C          */
-       case 0x13: return KEY_ESC;      /*   hangup     */
-       case 0x00: return KEY_1;        /*   1          */
-       case 0x01: return KEY_2;        /*   2          */
-       case 0x02: return KEY_3;        /*   3          */
-       case 0x10: return KEY_4;        /*   4          */
-       case 0x11: return KEY_5;        /*   5          */
-       case 0x12: return KEY_6;        /*   6          */
-       case 0x20: return KEY_7;        /*   7          */
-       case 0x21: return KEY_8;        /*   8          */
-       case 0x22: return KEY_9;        /*   9          */
-       case 0x30: return KEY_KPASTERISK; /* *          */
-       case 0x31: return KEY_0;        /*   0          */
-       case 0x32: return KEY_LEFTSHIFT |
-                         KEY_3 << 8;   /*   #          */
-       }
-       return -EINVAL;
-}
-
-/* Completes a request by converting the data into events for the
- * input subsystem.
- *
- * The key parameter can be cascaded: key2 << 8 | key1
- */
-static void report_key(struct yealink_dev *yld, int key)
-{
-       struct input_dev *idev = yld->idev;
-
-       if (yld->key_code >= 0) {
-               /* old key up */
-               input_report_key(idev, yld->key_code & 0xff, 0);
-               if (yld->key_code >> 8)
-                       input_report_key(idev, yld->key_code >> 8, 0);
-       }
-
-       yld->key_code = key;
-       if (key >= 0) {
-               /* new valid key */
-               input_report_key(idev, key & 0xff, 1);
-               if (key >> 8)
-                       input_report_key(idev, key >> 8, 1);
-       }
-       input_sync(idev);
-}
-
-/*******************************************************************************
- * Yealink usb communication interface
- ******************************************************************************/
-
-static int yealink_cmd(struct yealink_dev *yld, struct yld_ctl_packet *p)
-{
-       u8      *buf = (u8 *)p;
-       int     i;
-       u8      sum = 0;
-
-       for(i=0; i<USB_PKT_LEN-1; i++)
-               sum -= buf[i];
-       p->sum = sum;
-       return usb_control_msg(yld->udev,
-                       usb_sndctrlpipe(yld->udev, 0),
-                       USB_REQ_SET_CONFIGURATION,
-                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-                       0x200, 3,
-                       p, sizeof(*p),
-                       USB_CTRL_SET_TIMEOUT);
-}
-
-static u8 default_ringtone[] = {
-       0xEF,                   /* volume [0-255] */
-       0xFB, 0x1E, 0x00, 0x0C, /* 1250 [hz], 12/100 [s] */
-       0xFC, 0x18, 0x00, 0x0C, /* 1000 [hz], 12/100 [s] */
-       0xFB, 0x1E, 0x00, 0x0C,
-       0xFC, 0x18, 0x00, 0x0C,
-       0xFB, 0x1E, 0x00, 0x0C,
-       0xFC, 0x18, 0x00, 0x0C,
-       0xFB, 0x1E, 0x00, 0x0C,
-       0xFC, 0x18, 0x00, 0x0C,
-       0xFF, 0xFF, 0x01, 0x90, /* silent, 400/100 [s] */
-       0x00, 0x00              /* end of sequence */
-};
-
-static int yealink_set_ringtone(struct yealink_dev *yld, u8 *buf, size_t size)
-{
-       struct yld_ctl_packet *p = yld->ctl_data;
-       int     ix, len;
-
-       if (size <= 0)
-               return -EINVAL;
-
-       /* Set the ringtone volume */
-       memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
-       yld->ctl_data->cmd      = CMD_RING_VOLUME;
-       yld->ctl_data->size     = 1;
-       yld->ctl_data->data[0]  = buf[0];
-       yealink_cmd(yld, p);
-
-       buf++;
-       size--;
-
-       p->cmd = CMD_RING_NOTE;
-       ix = 0;
-       while (size != ix) {
-               len = size - ix;
-               if (len > sizeof(p->data))
-                       len = sizeof(p->data);
-               p->size   = len;
-               p->offset = cpu_to_be16(ix);
-               memcpy(p->data, &buf[ix], len);
-               yealink_cmd(yld, p);
-               ix += len;
-       }
-       return 0;
-}
-
-/* keep stat_master & stat_copy in sync.
- */
-static int yealink_do_idle_tasks(struct yealink_dev *yld)
-{
-       u8 val;
-       int i, ix, len;
-
-       ix = yld->stat_ix;
-
-       memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
-       yld->ctl_data->cmd  = CMD_KEYPRESS;
-       yld->ctl_data->size = 1;
-       yld->ctl_data->sum  = 0xff - CMD_KEYPRESS;
-
-       /* If state update pointer wraps do a KEYPRESS first. */
-       if (ix >= sizeof(yld->master)) {
-               yld->stat_ix = 0;
-               return 0;
-       }
-
-       /* find update candidates: copy != master */
-       do {
-               val = yld->master.b[ix];
-               if (val != yld->copy.b[ix])
-                       goto send_update;
-       } while (++ix < sizeof(yld->master));
-
-       /* nothing todo, wait a bit and poll for a KEYPRESS */
-       yld->stat_ix = 0;
-       /* TODO how can we wait abit. ??
-        * msleep_interruptible(1000 / YEALINK_POLLING_FREQUENCY);
-        */
-       return 0;
-
-send_update:
-
-       /* Setup an appropriate update request */
-       yld->copy.b[ix] = val;
-       yld->ctl_data->data[0] = val;
-
-       switch(ix) {
-       case offsetof(struct yld_status, led):
-               yld->ctl_data->cmd      = CMD_LED;
-               yld->ctl_data->sum      = -1 - CMD_LED - val;
-               break;
-       case offsetof(struct yld_status, dialtone):
-               yld->ctl_data->cmd      = CMD_DIALTONE;
-               yld->ctl_data->sum      = -1 - CMD_DIALTONE - val;
-               break;
-       case offsetof(struct yld_status, ringtone):
-               yld->ctl_data->cmd      = CMD_RINGTONE;
-               yld->ctl_data->sum      = -1 - CMD_RINGTONE - val;
-               break;
-       case offsetof(struct yld_status, keynum):
-               val--;
-               val &= 0x1f;
-               yld->ctl_data->cmd      = CMD_SCANCODE;
-               yld->ctl_data->offset   = cpu_to_be16(val);
-               yld->ctl_data->data[0]  = 0;
-               yld->ctl_data->sum      = -1 - CMD_SCANCODE - val;
-               break;
-       default:
-               len = sizeof(yld->master.s.lcd) - ix;
-               if (len > sizeof(yld->ctl_data->data))
-                       len = sizeof(yld->ctl_data->data);
-
-               /* Combine up to <len> consecutive LCD bytes in a singe request
-                */
-               yld->ctl_data->cmd      = CMD_LCD;
-               yld->ctl_data->offset   = cpu_to_be16(ix);
-               yld->ctl_data->size     = len;
-               yld->ctl_data->sum      = -CMD_LCD - ix - val - len;
-               for(i=1; i<len; i++) {
-                       ix++;
-                       val = yld->master.b[ix];
-                       yld->copy.b[ix]         = val;
-                       yld->ctl_data->data[i]  = val;
-                       yld->ctl_data->sum     -= val;
-               }
-       }
-       yld->stat_ix = ix + 1;
-       return 1;
-}
-
-/* Decide on how to handle responses
- *
- * The state transition diagram is somethhing like:
- *
- *          syncState<--+
- *               |      |
- *               |    idle
- *              \|/     |
- * init --ok--> waitForKey --ok--> getKey
- *  ^               ^                |
- *  |               +-------ok-------+
- * error,start
- *
- */
-static void urb_irq_callback(struct urb *urb)
-{
-       struct yealink_dev *yld = urb->context;
-       int ret;
-
-       if (urb->status)
-               err("%s - urb status %d", __FUNCTION__, urb->status);
-
-       switch (yld->irq_data->cmd) {
-       case CMD_KEYPRESS:
-
-               yld->master.s.keynum = yld->irq_data->data[0];
-               break;
-
-       case CMD_SCANCODE:
-               dbg("get scancode %x", yld->irq_data->data[0]);
-
-               report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
-               break;
-
-       default:
-               err("unexpected response %x", yld->irq_data->cmd);
-       }
-
-       yealink_do_idle_tasks(yld);
-
-       ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
-       if (ret)
-               err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
-}
-
-static void urb_ctl_callback(struct urb *urb)
-{
-       struct yealink_dev *yld = urb->context;
-       int ret;
-
-       if (urb->status)
-               err("%s - urb status %d", __FUNCTION__, urb->status);
-
-       switch (yld->ctl_data->cmd) {
-       case CMD_KEYPRESS:
-       case CMD_SCANCODE:
-               /* ask for a response */
-               ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
-               break;
-       default:
-               /* send new command */
-               yealink_do_idle_tasks(yld);
-               ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
-       }
-
-       if (ret)
-               err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
-}
-
-/*******************************************************************************
- * input event interface
- ******************************************************************************/
-
-/* TODO should we issue a ringtone on a SND_BELL event?
-static int input_ev(struct input_dev *dev, unsigned int type,
-               unsigned int code, int value)
-{
-
-       if (type != EV_SND)
-               return -EINVAL;
-
-       switch (code) {
-       case SND_BELL:
-       case SND_TONE:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-*/
-
-static int input_open(struct input_dev *dev)
-{
-       struct yealink_dev *yld = input_get_drvdata(dev);
-       int i, ret;
-
-       dbg("%s", __FUNCTION__);
-
-       /* force updates to device */
-       for (i = 0; i<sizeof(yld->master); i++)
-               yld->copy.b[i] = ~yld->master.b[i];
-       yld->key_code = -1;     /* no keys pressed */
-
-        yealink_set_ringtone(yld, default_ringtone, sizeof(default_ringtone));
-
-       /* issue INIT */
-       memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
-       yld->ctl_data->cmd      = CMD_INIT;
-       yld->ctl_data->size     = 10;
-       yld->ctl_data->sum      = 0x100-CMD_INIT-10;
-       if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
-               dbg("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, ret);
-               return ret;
-       }
-       return 0;
-}
-
-static void input_close(struct input_dev *dev)
-{
-       struct yealink_dev *yld = input_get_drvdata(dev);
-
-       usb_kill_urb(yld->urb_ctl);
-       usb_kill_urb(yld->urb_irq);
-}
-
-/*******************************************************************************
- * sysfs interface
- ******************************************************************************/
-
-static DECLARE_RWSEM(sysfs_rwsema);
-
-/* Interface to the 7-segments translation table aka. char set.
- */
-static ssize_t show_map(struct device *dev, struct device_attribute *attr,
-                               char *buf)
-{
-       memcpy(buf, &map_seg7, sizeof(map_seg7));
-       return sizeof(map_seg7);
-}
-
-static ssize_t store_map(struct device *dev, struct device_attribute *attr,
-                               const char *buf, size_t cnt)
-{
-       if (cnt != sizeof(map_seg7))
-               return -EINVAL;
-       memcpy(&map_seg7, buf, sizeof(map_seg7));
-       return sizeof(map_seg7);
-}
-
-/* Interface to the LCD.
- */
-
-/* Reading /sys/../lineX will return the format string with its settings:
- *
- * Example:
- * cat ./line3
- * 888888888888
- * Linux Rocks!
- */
-static ssize_t show_line(struct device *dev, char *buf, int a, int b)
-{
-       struct yealink_dev *yld;
-       int i;
-
-       down_read(&sysfs_rwsema);
-       yld = dev_get_drvdata(dev);
-       if (yld == NULL) {
-               up_read(&sysfs_rwsema);
-               return -ENODEV;
-       }
-
-       for (i = a; i < b; i++)
-               *buf++ = lcdMap[i].type;
-       *buf++ = '\n';
-       for (i = a; i < b; i++)
-               *buf++ = yld->lcdMap[i];
-       *buf++ = '\n';
-       *buf = 0;
-
-       up_read(&sysfs_rwsema);
-       return 3 + ((b - a) << 1);
-}
-
-static ssize_t show_line1(struct device *dev, struct device_attribute *attr,
-                       char *buf)
-{
-       return show_line(dev, buf, LCD_LINE1_OFFSET, LCD_LINE2_OFFSET);
-}
-
-static ssize_t show_line2(struct device *dev, struct device_attribute *attr,
-                       char *buf)
-{
-       return show_line(dev, buf, LCD_LINE2_OFFSET, LCD_LINE3_OFFSET);
-}
-
-static ssize_t show_line3(struct device *dev, struct device_attribute *attr,
-                       char *buf)
-{
-       return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET);
-}
-
-/* Writing to /sys/../lineX will set the coresponding LCD line.
- * - Excess characters are ignored.
- * - If less characters are written than allowed, the remaining digits are
- *   unchanged.
- * - The '\n' or '\t' char is a placeholder, it does not overwrite the
- *   original content.
- */
-static ssize_t store_line(struct device *dev, const char *buf, size_t count,
-               int el, size_t len)
-{
-       struct yealink_dev *yld;
-       int i;
-
-       down_write(&sysfs_rwsema);
-       yld = dev_get_drvdata(dev);
-       if (yld == NULL) {
-               up_write(&sysfs_rwsema);
-               return -ENODEV;
-       }
-
-       if (len > count)
-               len = count;
-       for (i = 0; i < len; i++)
-               setChar(yld, el++, buf[i]);
-
-       up_write(&sysfs_rwsema);
-       return count;
-}
-
-static ssize_t store_line1(struct device *dev, struct device_attribute *attr,
-                               const char *buf, size_t count)
-{
-       return store_line(dev, buf, count, LCD_LINE1_OFFSET, LCD_LINE1_SIZE);
-}
-
-static ssize_t store_line2(struct device *dev, struct device_attribute *attr,
-                               const char *buf, size_t count)
-{
-       return store_line(dev, buf, count, LCD_LINE2_OFFSET, LCD_LINE2_SIZE);
-}
-
-static ssize_t store_line3(struct device *dev, struct device_attribute *attr,
-                               const char *buf, size_t count)
-{
-       return store_line(dev, buf, count, LCD_LINE3_OFFSET, LCD_LINE3_SIZE);
-}
-
-/* Interface to visible and audible "icons", these include:
- * pictures on the LCD, the LED, and the dialtone signal.
- */
-
-/* Get a list of "switchable elements" with their current state. */
-static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
-                       char *buf)
-{
-       struct yealink_dev *yld;
-       int i, ret = 1;
-
-       down_read(&sysfs_rwsema);
-       yld = dev_get_drvdata(dev);
-       if (yld == NULL) {
-               up_read(&sysfs_rwsema);
-               return -ENODEV;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
-               if (lcdMap[i].type != '.')
-                       continue;
-               ret += sprintf(&buf[ret], "%s %s\n",
-                               yld->lcdMap[i] == ' ' ? "  " : "on",
-                               lcdMap[i].u.p.name);
-       }
-       up_read(&sysfs_rwsema);
-       return ret;
-}
-
-/* Change the visibility of a particular element. */
-static ssize_t set_icon(struct device *dev, const char *buf, size_t count,
-                       int chr)
-{
-       struct yealink_dev *yld;
-       int i;
-
-       down_write(&sysfs_rwsema);
-       yld = dev_get_drvdata(dev);
-       if (yld == NULL) {
-               up_write(&sysfs_rwsema);
-               return -ENODEV;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
-               if (lcdMap[i].type != '.')
-                       continue;
-               if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) {
-                       setChar(yld, i, chr);
-                       break;
-               }
-       }
-
-       up_write(&sysfs_rwsema);
-       return count;
-}
-
-static ssize_t show_icon(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       return set_icon(dev, buf, count, buf[0]);
-}
-
-static ssize_t hide_icon(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       return set_icon(dev, buf, count, ' ');
-}
-
-/* Upload a ringtone to the device.
- */
-
-/* Stores raw ringtone data in the phone */
-static ssize_t store_ringtone(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct yealink_dev *yld;
-
-       down_write(&sysfs_rwsema);
-       yld = dev_get_drvdata(dev);
-       if (yld == NULL) {
-               up_write(&sysfs_rwsema);
-               return -ENODEV;
-       }
-
-       /* TODO locking with async usb control interface??? */
-       yealink_set_ringtone(yld, (char *)buf, count);
-       up_write(&sysfs_rwsema);
-       return count;
-}
-
-#define _M444  S_IRUGO
-#define _M664  S_IRUGO|S_IWUSR|S_IWGRP
-#define _M220  S_IWUSR|S_IWGRP
-
-static DEVICE_ATTR(map_seg7    , _M664, show_map       , store_map     );
-static DEVICE_ATTR(line1       , _M664, show_line1     , store_line1   );
-static DEVICE_ATTR(line2       , _M664, show_line2     , store_line2   );
-static DEVICE_ATTR(line3       , _M664, show_line3     , store_line3   );
-static DEVICE_ATTR(get_icons   , _M444, get_icons      , NULL          );
-static DEVICE_ATTR(show_icon   , _M220, NULL           , show_icon     );
-static DEVICE_ATTR(hide_icon   , _M220, NULL           , hide_icon     );
-static DEVICE_ATTR(ringtone    , _M220, NULL           , store_ringtone);
-
-static struct attribute *yld_attributes[] = {
-       &dev_attr_line1.attr,
-       &dev_attr_line2.attr,
-       &dev_attr_line3.attr,
-       &dev_attr_get_icons.attr,
-       &dev_attr_show_icon.attr,
-       &dev_attr_hide_icon.attr,
-       &dev_attr_map_seg7.attr,
-       &dev_attr_ringtone.attr,
-       NULL
-};
-
-static struct attribute_group yld_attr_group = {
-       .attrs = yld_attributes
-};
-
-/*******************************************************************************
- * Linux interface and usb initialisation
- ******************************************************************************/
-
-struct driver_info {
-       char *name;
-};
-
-static const struct driver_info info_P1K = {
-       .name   = "Yealink usb-p1k",
-};
-
-static const struct usb_device_id usb_table [] = {
-       {
-               .match_flags            = USB_DEVICE_ID_MATCH_DEVICE |
-                                               USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor               = 0x6993,
-               .idProduct              = 0xb001,
-               .bInterfaceClass        = USB_CLASS_HID,
-               .bInterfaceSubClass     = 0,
-               .bInterfaceProtocol     = 0,
-               .driver_info            = (kernel_ulong_t)&info_P1K
-       },
-       { }
-};
-
-static int usb_cleanup(struct yealink_dev *yld, int err)
-{
-       if (yld == NULL)
-               return err;
-
-       usb_kill_urb(yld->urb_irq);     /* parameter validation in core/urb */
-       usb_kill_urb(yld->urb_ctl);     /* parameter validation in core/urb */
-
-        if (yld->idev) {
-               if (err)
-                       input_free_device(yld->idev);
-               else
-                       input_unregister_device(yld->idev);
-       }
-
-       usb_free_urb(yld->urb_irq);
-       usb_free_urb(yld->urb_ctl);
-
-       usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
-                       yld->ctl_req, yld->ctl_req_dma);
-       usb_buffer_free(yld->udev, USB_PKT_LEN,
-                       yld->ctl_data, yld->ctl_dma);
-       usb_buffer_free(yld->udev, USB_PKT_LEN,
-                       yld->irq_data, yld->irq_dma);
-
-       kfree(yld);
-       return err;
-}
-
-static void usb_disconnect(struct usb_interface *intf)
-{
-       struct yealink_dev *yld;
-
-       down_write(&sysfs_rwsema);
-       yld = usb_get_intfdata(intf);
-       sysfs_remove_group(&intf->dev.kobj, &yld_attr_group);
-       usb_set_intfdata(intf, NULL);
-       up_write(&sysfs_rwsema);
-
-       usb_cleanup(yld, 0);
-}
-
-static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev (intf);
-       struct driver_info *nfo = (struct driver_info *)id->driver_info;
-       struct usb_host_interface *interface;
-       struct usb_endpoint_descriptor *endpoint;
-       struct yealink_dev *yld;
-       struct input_dev *input_dev;
-       int ret, pipe, i;
-
-       interface = intf->cur_altsetting;
-       endpoint = &interface->endpoint[0].desc;
-       if (!usb_endpoint_is_int_in(endpoint))
-               return -ENODEV;
-
-       yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL);
-       if (!yld)
-               return -ENOMEM;
-
-       yld->udev = udev;
-
-       yld->idev = input_dev = input_allocate_device();
-       if (!input_dev)
-               return usb_cleanup(yld, -ENOMEM);
-
-       /* allocate usb buffers */
-       yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
-                                       GFP_ATOMIC, &yld->irq_dma);
-       if (yld->irq_data == NULL)
-               return usb_cleanup(yld, -ENOMEM);
-
-       yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
-                                       GFP_ATOMIC, &yld->ctl_dma);
-       if (!yld->ctl_data)
-               return usb_cleanup(yld, -ENOMEM);
-
-       yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)),
-                                       GFP_ATOMIC, &yld->ctl_req_dma);
-       if (yld->ctl_req == NULL)
-               return usb_cleanup(yld, -ENOMEM);
-
-       /* allocate urb structures */
-       yld->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
-        if (yld->urb_irq == NULL)
-               return usb_cleanup(yld, -ENOMEM);
-
-       yld->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
-        if (yld->urb_ctl == NULL)
-               return usb_cleanup(yld, -ENOMEM);
-
-       /* get a handle to the interrupt data pipe */
-       pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
-       ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-       if (ret != USB_PKT_LEN)
-               err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
-
-       /* initialise irq urb */
-       usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
-                       USB_PKT_LEN,
-                       urb_irq_callback,
-                       yld, endpoint->bInterval);
-       yld->urb_irq->transfer_dma = yld->irq_dma;
-       yld->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-       yld->urb_irq->dev = udev;
-
-       /* initialise ctl urb */
-       yld->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
-                                     USB_DIR_OUT;
-       yld->ctl_req->bRequest  = USB_REQ_SET_CONFIGURATION;
-       yld->ctl_req->wValue    = cpu_to_le16(0x200);
-       yld->ctl_req->wIndex    = cpu_to_le16(interface->desc.bInterfaceNumber);
-       yld->ctl_req->wLength   = cpu_to_le16(USB_PKT_LEN);
-
-       usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
-                       (void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
-                       urb_ctl_callback, yld);
-       yld->urb_ctl->setup_dma = yld->ctl_req_dma;
-       yld->urb_ctl->transfer_dma      = yld->ctl_dma;
-       yld->urb_ctl->transfer_flags    |= URB_NO_SETUP_DMA_MAP |
-                                       URB_NO_TRANSFER_DMA_MAP;
-       yld->urb_ctl->dev = udev;
-
-       /* find out the physical bus location */
-       usb_make_path(udev, yld->phys, sizeof(yld->phys));
-       strlcat(yld->phys,  "/input0", sizeof(yld->phys));
-
-       /* register settings for the input device */
-       input_dev->name = nfo->name;
-       input_dev->phys = yld->phys;
-       usb_to_input_id(udev, &input_dev->id);
-       input_dev->dev.parent = &intf->dev;
-
-       input_set_drvdata(input_dev, yld);
-
-       input_dev->open = input_open;
-       input_dev->close = input_close;
-       /* input_dev->event = input_ev; TODO */
-
-       /* register available key events */
-       input_dev->evbit[0] = BIT(EV_KEY);
-       for (i = 0; i < 256; i++) {
-               int k = map_p1k_to_key(i);
-               if (k >= 0) {
-                       set_bit(k & 0xff, input_dev->keybit);
-                       if (k >> 8)
-                               set_bit(k >> 8, input_dev->keybit);
-               }
-       }
-
-       ret = input_register_device(yld->idev);
-       if (ret)
-               return usb_cleanup(yld, ret);
-
-       usb_set_intfdata(intf, yld);
-
-       /* clear visible elements */
-       for (i = 0; i < ARRAY_SIZE(lcdMap); i++)
-               setChar(yld, i, ' ');
-
-       /* display driver version on LCD line 3 */
-       store_line3(&intf->dev, NULL,
-                       DRIVER_VERSION, sizeof(DRIVER_VERSION));
-
-       /* Register sysfs hooks (don't care about failure) */
-       ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
-       return 0;
-}
-
-static struct usb_driver yealink_driver = {
-       .name           = "yealink",
-       .probe          = usb_probe,
-       .disconnect     = usb_disconnect,
-       .id_table       = usb_table,
-};
-
-static int __init yealink_dev_init(void)
-{
-       int ret = usb_register(&yealink_driver);
-       if (ret == 0)
-               info(DRIVER_DESC ":" DRIVER_VERSION);
-       return ret;
-}
-
-static void __exit yealink_dev_exit(void)
-{
-       usb_deregister(&yealink_driver);
-}
-
-module_init(yealink_dev_init);
-module_exit(yealink_dev_exit);
-
-MODULE_DEVICE_TABLE (usb, usb_table);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/yealink.h b/drivers/usb/input/yealink.h
deleted file mode 100644 (file)
index 48af0be..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * drivers/usb/input/yealink.h
- *
- * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef INPUT_YEALINK_H
-#define INPUT_YEALINK_H
-
-/* Using the control channel on interface 3 various aspects of the phone
- * can be controlled like LCD, LED, dialtone and the ringtone.
- */
-
-struct yld_ctl_packet {
-       u8      cmd;            /* command code, see below */
-       u8      size;           /* 1-11, size of used data bytes. */
-       u16     offset;         /* internal packet offset */
-       u8      data[11];
-       s8      sum;            /* negative sum of 15 preceding bytes */
-} __attribute__ ((packed));
-
-#define USB_PKT_LEN    sizeof(struct yld_ctl_packet)
-
-/* The following yld_ctl_packet's are available: */
-
-/* Init registers
- *
- * cmd         0x8e
- * size                10
- * offset      0
- * data                0,0,0,0....
- */
-#define CMD_INIT               0x8e
-
-/* Request key scan
- *
- * cmd         0x80
- * size                1
- * offset      0
- * data[0]     on return returns the key number, if it changes there's a new
- *             key pressed.
- */
-#define CMD_KEYPRESS           0x80
-
-/* Request scancode
- *
- * cmd         0x81
- * size                1
- * offset      key number [0-1f]
- * data[0]     on return returns the scancode
- */
-#define CMD_SCANCODE           0x81
-
-/* Set LCD
- *
- * cmd         0x04
- * size                1-11
- * offset      0-23
- * data                segment bits
- */
-#define CMD_LCD                        0x04
-
-/* Set led
- *
- * cmd         0x05
- * size                1
- * offset      0
- * data[0]     0 OFF / 1 ON
- */
-#define CMD_LED                        0x05
-
-/* Set ringtone volume
- *
- * cmd         0x11
- * size                1
- * offset      0
- * data[0]     0-0xff  volume
- */
-#define CMD_RING_VOLUME                0x11
-
-/* Set ringtone notes
- *
- * cmd         0x02
- * size                1-11
- * offset      0->
- * data                binary representation LE16(-freq), LE16(duration) ....
- */
-#define CMD_RING_NOTE          0x02
-
-/* Sound ringtone via the speaker on the back
- *
- * cmd         0x03
- * size                1
- * offset      0
- * data[0]     0 OFF / 0x24 ON
- */
-#define CMD_RINGTONE           0x03
-
-/* Sound dial tone via the ear speaker
- *
- * cmd         0x09
- * size                1
- * offset      0
- * data[0]     0 OFF / 1 ON
- */
-#define CMD_DIALTONE           0x09
-
-#endif /* INPUT_YEALINK_H */
-
-
-#if defined(_SEG) && defined(_PIC)
-/* This table maps the LCD segments onto individual bit positions in the
- * yld_status struct.
- */
-
-/* LCD, each segment must be driven seperately.
- *
- * Layout:
- *
- *   |[]   [][]   [][]   [][]   in   |[][]
- *   |[] M [][] D [][] : [][]   out  |[][]
- *                             store
- *
- *    NEW REP         SU MO TU WE TH FR SA
- *
- *    [] [] [] [] [] [] [] [] [] [] [] []
- *    [] [] [] [] [] [] [] [] [] [] [] []
- */
-
-/* Line 1
- *     Format          : 18.e8.M8.88...188
- *     Icon names      : M D : IN OUT STORE
- */
-#define LCD_LINE1_OFFSET       0
-#define LCD_LINE1_SIZE         17
-
-/* Note: first g then f =>                            !      !      */
-/* _SEG(    type    a      b      c      d      e      g      f   )  */
-       _SEG('1',  0,0 , 22,2 , 22,2 ,  0,0 ,  0,0 ,  0,0 ,  0,0        ),
-       _SEG('8', 20,1 , 20,2 , 20,4 , 20,8 , 21,4 , 21,2 , 21,1        ),
-       _PIC('.', 22,1 , "M"                                            ),
-       _SEG('e', 18,1 , 18,2 , 18,4 , 18,1 , 19,2 , 18,1 , 19,1        ),
-       _SEG('8', 16,1 , 16,2 , 16,4 , 16,8 , 17,4 , 17,2 , 17,1        ),
-       _PIC('.', 15,8 , "D"                                            ),
-       _SEG('M', 14,1 , 14,2 , 14,4 , 14,1 , 15,4 , 15,2 , 15,1        ),
-       _SEG('8', 12,1 , 12,2 , 12,4 , 12,8 , 13,4 , 13,2 , 13,1        ),
-       _PIC('.', 11,8 , ":"                                            ),
-       _SEG('8', 10,1 , 10,2 , 10,4 , 10,8 , 11,4 , 11,2 , 11,1        ),
-       _SEG('8',  8,1 ,  8,2 ,  8,4 ,  8,8 ,  9,4 ,  9,2 ,  9,1        ),
-       _PIC('.',  7,1 , "IN"                                           ),
-       _PIC('.',  7,2 , "OUT"                                          ),
-       _PIC('.',  7,4 , "STORE"                                        ),
-       _SEG('1',  0,0 ,  5,1 ,  5,1 ,  0,0 ,  0,0 ,  0,0 ,  0,0        ),
-       _SEG('8',  4,1 ,  4,2 ,  4,4 ,  4,8 ,  5,8 ,  5,4 ,  5,2        ),
-       _SEG('8',  2,1 ,  2,2 ,  2,4 ,  2,8 ,  3,4 ,  3,2 ,  3,1        ),
-
-/* Line 2
- *     Format          : .........
- *     Pict. name      : NEW REP SU MO TU WE TH FR SA
- */
-#define LCD_LINE2_OFFSET       LCD_LINE1_OFFSET + LCD_LINE1_SIZE
-#define LCD_LINE2_SIZE         9
-
-       _PIC('.', 23,2 , "NEW"  ),
-       _PIC('.', 23,4 , "REP"  ),
-       _PIC('.',  1,8 , "SU"   ),
-       _PIC('.',  1,4 , "MO"   ),
-       _PIC('.',  1,2 , "TU"   ),
-       _PIC('.',  1,1 , "WE"   ),
-       _PIC('.',  0,1 , "TH"   ),
-       _PIC('.',  0,2 , "FR"   ),
-       _PIC('.',  0,4 , "SA"   ),
-
-/* Line 3
- *     Format          : 888888888888
- */
-#define LCD_LINE3_OFFSET       LCD_LINE2_OFFSET + LCD_LINE2_SIZE
-#define LCD_LINE3_SIZE         12
-
-       _SEG('8', 22,16, 22,32, 22,64, 22,128, 23,128, 23,64, 23,32  ),
-       _SEG('8', 20,16, 20,32, 20,64, 20,128, 21,128, 21,64, 21,32  ),
-       _SEG('8', 18,16, 18,32, 18,64, 18,128, 19,128, 19,64, 19,32  ),
-       _SEG('8', 16,16, 16,32, 16,64, 16,128, 17,128, 17,64, 17,32  ),
-       _SEG('8', 14,16, 14,32, 14,64, 14,128, 15,128, 15,64, 15,32  ),
-       _SEG('8', 12,16, 12,32, 12,64, 12,128, 13,128, 13,64, 13,32  ),
-       _SEG('8', 10,16, 10,32, 10,64, 10,128, 11,128, 11,64, 11,32  ),
-       _SEG('8',  8,16,  8,32,  8,64,  8,128,  9,128,  9,64,  9,32  ),
-       _SEG('8',  6,16,  6,32,  6,64,  6,128,  7,128,  7,64,  7,32  ),
-       _SEG('8',  4,16,  4,32,  4,64,  4,128,  5,128,  5,64,  5,32  ),
-       _SEG('8',  2,16,  2,32,  2,64,  2,128,  3,128,  3,64,  3,32  ),
-       _SEG('8',  0,16,  0,32,  0,64,  0,128,  1,128,  1,64,  1,32  ),
-
-/* Line 4
- *
- * The LED, DIALTONE and RINGTONE are implemented as icons and use the same
- * sysfs interface.
- */
-#define LCD_LINE4_OFFSET       LCD_LINE3_OFFSET + LCD_LINE3_SIZE
-
-       _PIC('.', offsetof(struct yld_status, led)      , 0x01, "LED" ),
-       _PIC('.', offsetof(struct yld_status, dialtone) , 0x01, "DIALTONE" ),
-       _PIC('.', offsetof(struct yld_status, ringtone) , 0x24, "RINGTONE" ),
-
-#undef _SEG
-#undef _PIC
-#endif /* _SEG && _PIC */