Input: move USB miscellaneous devices under drivers/input/misc

This will allow concentrating all input devices in one place
in {menu|x|q}config.

Signed-off-by: Dmitry Torokhov <[email protected]>
Acked-by: Greg Kroah-Hartman <[email protected]>
This commit is contained in:
Dmitry Torokhov 2007-05-07 17:31:32 -04:00
commit ba0acb5ee3
13 changed files with 89 additions and 105 deletions

View 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"

View 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/

View file

@ -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.

View file

@ -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

View file

@ -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 <[email protected]>"
#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");

View file

@ -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 <[email protected]>");
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);

View file

@ -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 <[email protected]>"
#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);

View file

@ -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 */

View file

@ -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");

File diff suppressed because it is too large Load diff

View file

@ -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 */