mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (40 commits) Input: use full RCU API Input: remove tsdev interface Input: add support for Blackfin BF54x Keypad controller Input: appletouch - another fix for idle reset logic HWMON: hdaps - switch to using input-polldev Input: add support for SEGA Dreamcast keyboard Input: omap-keyboard - don't pretend we support changing keymap Input: lifebook - fix X and Y axis range Input: usbtouchscreen - add support for GeneralTouch devices Input: fix open count handling in input interfaces Input: keyboard - add CapsShift lock Input: adbhid - produce all CapsLock key events Input: ALPS - add signature for ThinkPad R61 Input: jornada720_kbd - send MSC_SCAN events Input: add support for the HP Jornada 7xx (710/720/728) touchscreen Input: add support for HP Jornada 7xx onboard keyboard Input: add support for HP Jornada onboard keyboard (HP6XX) Input: ucb1400_ts - use schedule_timeout_uninterruptible Input: xpad - fix dependancy on LEDS class Input: auto-select INPUT for MAC_EMUMOUSEBTN option ... Resolved conflicts manually in drivers/hwmon/applesmc.c: converting from a class device to a device and converting to use input-polldev created a few apparently trivial clashes..
This commit is contained in:
commit
f2e1d89f9b
@ -205,20 +205,6 @@ Who: Len Brown <len.brown@intel.com>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: Compaq touchscreen device emulation
|
||||
When: Oct 2007
|
||||
Files: drivers/input/tsdev.c
|
||||
Why: The code says it was obsolete when it was written in 2001.
|
||||
tslib is a userspace library which does anything tsdev can do and
|
||||
much more besides in userspace where this code belongs. There is no
|
||||
longer any need for tsdev and applications should have converted to
|
||||
use tslib by now.
|
||||
The name "tsdev" is also extremely confusing and lots of people have
|
||||
it loaded when they don't need/use it.
|
||||
Who: Richard Purdie <rpurdie@rpsys.net>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers
|
||||
When: September 2007
|
||||
Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific
|
||||
|
@ -1890,9 +1890,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
Format:
|
||||
<io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
|
||||
|
||||
tsdev.xres= [TS] Horizontal screen resolution.
|
||||
tsdev.yres= [TS] Vertical screen resolution.
|
||||
|
||||
turbografx.map[2|3]= [HW,JOY]
|
||||
TurboGraFX parallel port interface
|
||||
Format:
|
||||
|
@ -88,7 +88,7 @@ static struct platform_device bf54x_lq043_device = {
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_KEYBOARD_BFIN) || defined(CONFIG_KEYBOARD_BFIN_MODULE)
|
||||
static int bf548_keymap[] = {
|
||||
static const unsigned int bf548_keymap[] = {
|
||||
KEYVAL(0, 0, KEY_ENTER),
|
||||
KEYVAL(0, 1, KEY_HELP),
|
||||
KEYVAL(0, 2, KEY_0),
|
||||
@ -110,8 +110,8 @@ static int bf548_keymap[] = {
|
||||
static struct bfin_kpad_platform_data bf54x_kpad_data = {
|
||||
.rows = 4,
|
||||
.cols = 4,
|
||||
.keymap = bf548_keymap,
|
||||
.keymapsize = ARRAY_SIZE(bf548_keymap),
|
||||
.keymap = bf548_keymap,
|
||||
.keymapsize = ARRAY_SIZE(bf548_keymap),
|
||||
.repeat = 0,
|
||||
.debounce_time = 5000, /* ns (5ms) */
|
||||
.coldrive_time = 1000, /* ns (1ms) */
|
||||
|
@ -1,457 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/char/ec3104_keyb.c
|
||||
*
|
||||
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
|
||||
*
|
||||
* based on linux/drivers/char/pc_keyb.c, which had the following comments:
|
||||
*
|
||||
* Separation of the PC low-level part by Geert Uytterhoeven, May 1997
|
||||
* See keyboard.c for the whole history.
|
||||
*
|
||||
* Major cleanup by Martin Mares, May 1997
|
||||
*
|
||||
* Combined the keyboard and PS/2 mouse handling into one file,
|
||||
* because they share the same hardware.
|
||||
* Johan Myreen <jem@iki.fi> 1998-10-08.
|
||||
*
|
||||
* Code fixes to handle mouse ACKs properly.
|
||||
* C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
|
||||
*/
|
||||
/* EC3104 note:
|
||||
* This code was written without any documentation about the EC3104 chip. While
|
||||
* I hope I got most of the basic functionality right, the register names I use
|
||||
* are most likely completely different from those in the chip documentation.
|
||||
*
|
||||
* If you have any further information about the EC3104, please tell me
|
||||
* (prumpf@tux.org).
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kbd_ll.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kbd_kern.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/keyboard.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/ec3104.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
/* Some configuration switches are present in the include file... */
|
||||
|
||||
#include <linux/pc_keyb.h>
|
||||
|
||||
#define MSR_CTS 0x10
|
||||
#define MCR_RTS 0x02
|
||||
#define LSR_DR 0x01
|
||||
#define LSR_BOTH_EMPTY 0x60
|
||||
|
||||
static struct e5_struct {
|
||||
u8 packet[8];
|
||||
int pos;
|
||||
int length;
|
||||
|
||||
u8 cached_mcr;
|
||||
u8 last_msr;
|
||||
} ec3104_keyb;
|
||||
|
||||
/* Simple translation table for the SysRq keys */
|
||||
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
unsigned char ec3104_kbd_sysrq_xlate[128] =
|
||||
"\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
|
||||
"qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
|
||||
"dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
|
||||
"bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
|
||||
"\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
|
||||
"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
|
||||
"\r\000/"; /* 0x60 - 0x6f */
|
||||
#endif
|
||||
|
||||
static void kbd_write_command_w(int data);
|
||||
static void kbd_write_output_w(int data);
|
||||
#ifdef CONFIG_PSMOUSE
|
||||
static void aux_write_ack(int val);
|
||||
static void __aux_write_ack(int val);
|
||||
#endif
|
||||
|
||||
static DEFINE_SPINLOCK(kbd_controller_lock);
|
||||
static unsigned char handle_kbd_event(void);
|
||||
|
||||
/* used only by send_data - set by keyboard_interrupt */
|
||||
static volatile unsigned char reply_expected;
|
||||
static volatile unsigned char acknowledge;
|
||||
static volatile unsigned char resend;
|
||||
|
||||
|
||||
int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ec3104_kbd_getkeycode(unsigned int scancode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* yes, it probably would be faster to use an array. I don't care. */
|
||||
|
||||
static inline unsigned char ec3104_scan2key(unsigned char scancode)
|
||||
{
|
||||
switch (scancode) {
|
||||
case 1: /* '`' */
|
||||
return 41;
|
||||
|
||||
case 2 ... 27:
|
||||
return scancode;
|
||||
|
||||
case 28: /* '\\' */
|
||||
return 43;
|
||||
|
||||
case 29 ... 39:
|
||||
return scancode + 1;
|
||||
|
||||
case 40: /* '\r' */
|
||||
return 28;
|
||||
|
||||
case 41 ... 50:
|
||||
return scancode + 3;
|
||||
|
||||
case 51: /* ' ' */
|
||||
return 57;
|
||||
|
||||
case 52: /* escape */
|
||||
return 1;
|
||||
|
||||
case 54: /* insert/delete (labelled delete) */
|
||||
/* this should arguably be 110, but I'd like to have ctrl-alt-del
|
||||
* working with a standard keymap */
|
||||
return 111;
|
||||
|
||||
case 55: /* left */
|
||||
return 105;
|
||||
case 56: /* home */
|
||||
return 102;
|
||||
case 57: /* end */
|
||||
return 107;
|
||||
case 58: /* up */
|
||||
return 103;
|
||||
case 59: /* down */
|
||||
return 108;
|
||||
case 60: /* pgup */
|
||||
return 104;
|
||||
case 61: /* pgdown */
|
||||
return 109;
|
||||
case 62: /* right */
|
||||
return 106;
|
||||
|
||||
case 79 ... 88: /* f1 - f10 */
|
||||
return scancode - 20;
|
||||
|
||||
case 89 ... 90: /* f11 - f12 */
|
||||
return scancode - 2;
|
||||
|
||||
case 91: /* left shift */
|
||||
return 42;
|
||||
|
||||
case 92: /* right shift */
|
||||
return 54;
|
||||
|
||||
case 93: /* left alt */
|
||||
return 56;
|
||||
case 94: /* right alt */
|
||||
return 100;
|
||||
case 95: /* left ctrl */
|
||||
return 29;
|
||||
case 96: /* right ctrl */
|
||||
return 97;
|
||||
|
||||
case 97: /* caps lock */
|
||||
return 58;
|
||||
case 102: /* left windows */
|
||||
return 125;
|
||||
case 103: /* right windows */
|
||||
return 126;
|
||||
|
||||
case 106: /* Fn */
|
||||
/* this is wrong. */
|
||||
return 84;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode,
|
||||
char raw_mode)
|
||||
{
|
||||
scancode &= 0x7f;
|
||||
|
||||
*keycode = ec3104_scan2key(scancode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char ec3104_kbd_unexpected_up(unsigned char keycode)
|
||||
{
|
||||
return 0200;
|
||||
}
|
||||
|
||||
static inline void handle_keyboard_event(unsigned char scancode)
|
||||
{
|
||||
#ifdef CONFIG_VT
|
||||
handle_scancode(scancode, !(scancode & 0x80));
|
||||
#endif
|
||||
tasklet_schedule(&keyboard_tasklet);
|
||||
}
|
||||
|
||||
void ec3104_kbd_leds(unsigned char leds)
|
||||
{
|
||||
}
|
||||
|
||||
static u8 e5_checksum(u8 *packet, int count)
|
||||
{
|
||||
int i;
|
||||
u8 sum = 0;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
sum ^= packet[i];
|
||||
|
||||
if (sum & 0x80)
|
||||
sum ^= 0xc0;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static void e5_wait_for_cts(struct e5_struct *k)
|
||||
{
|
||||
u8 msr;
|
||||
|
||||
do {
|
||||
msr = ctrl_inb(EC3104_SER4_MSR);
|
||||
} while (!(msr & MSR_CTS));
|
||||
}
|
||||
|
||||
|
||||
static void e5_send_byte(u8 byte, struct e5_struct *k)
|
||||
{
|
||||
u8 status;
|
||||
|
||||
do {
|
||||
status = ctrl_inb(EC3104_SER4_LSR);
|
||||
} while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
|
||||
|
||||
printk("<%02x>", byte);
|
||||
|
||||
ctrl_outb(byte, EC3104_SER4_DATA);
|
||||
|
||||
do {
|
||||
status = ctrl_inb(EC3104_SER4_LSR);
|
||||
} while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
|
||||
|
||||
}
|
||||
|
||||
static int e5_send_packet(u8 *packet, int count, struct e5_struct *k)
|
||||
{
|
||||
int i;
|
||||
|
||||
disable_irq(EC3104_IRQ_SER4);
|
||||
|
||||
if (k->cached_mcr & MCR_RTS) {
|
||||
printk("e5_send_packet: too slow\n");
|
||||
enable_irq(EC3104_IRQ_SER4);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
k->cached_mcr |= MCR_RTS;
|
||||
ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
|
||||
|
||||
e5_wait_for_cts(k);
|
||||
|
||||
printk("p: ");
|
||||
|
||||
for(i=0; i<count; i++)
|
||||
e5_send_byte(packet[i], k);
|
||||
|
||||
e5_send_byte(e5_checksum(packet, count), k);
|
||||
|
||||
printk("\n");
|
||||
|
||||
udelay(1500);
|
||||
|
||||
k->cached_mcr &= ~MCR_RTS;
|
||||
ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
|
||||
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
|
||||
|
||||
|
||||
enable_irq(EC3104_IRQ_SER4);
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* E5 packets we know about:
|
||||
* E5->host 0x80 0x05 <checksum> - resend packet
|
||||
* host->E5 0x83 0x43 <contrast> - set LCD contrast
|
||||
* host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight
|
||||
* E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2
|
||||
* E5->host 0x88 <scancode> <checksum> - key press
|
||||
*/
|
||||
|
||||
static void e5_receive(struct e5_struct *k)
|
||||
{
|
||||
k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA);
|
||||
|
||||
if (k->pos == 1) {
|
||||
switch(k->packet[0]) {
|
||||
case 0x80:
|
||||
k->length = 3;
|
||||
break;
|
||||
|
||||
case 0x87: /* PS2 ext */
|
||||
k->length = 6;
|
||||
break;
|
||||
|
||||
case 0x88: /* keyboard */
|
||||
k->length = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
k->length = 1;
|
||||
printk(KERN_WARNING "unknown E5 packet %02x\n",
|
||||
k->packet[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (k->pos == k->length) {
|
||||
int i;
|
||||
|
||||
if (e5_checksum(k->packet, k->length) != 0)
|
||||
printk(KERN_WARNING "E5: wrong checksum\n");
|
||||
|
||||
#if 0
|
||||
printk("E5 packet [");
|
||||
for(i=0; i<k->length; i++) {
|
||||
printk("%02x ", k->packet[i]);
|
||||
}
|
||||
|
||||
printk("(%02x)]\n", e5_checksum(k->packet, k->length-1));
|
||||
#endif
|
||||
|
||||
switch(k->packet[0]) {
|
||||
case 0x80:
|
||||
case 0x88:
|
||||
handle_keyboard_event(k->packet[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
k->pos = k->length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ec3104_keyb_interrupt(int irq, void *data)
|
||||
{
|
||||
struct e5_struct *k = &ec3104_keyb;
|
||||
u8 msr, lsr;
|
||||
|
||||
msr = ctrl_inb(EC3104_SER4_MSR);
|
||||
|
||||
if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
|
||||
if (k->cached_mcr & MCR_RTS)
|
||||
printk("confused: RTS already high\n");
|
||||
/* CTS went high. Send RTS. */
|
||||
k->cached_mcr |= MCR_RTS;
|
||||
|
||||
ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
|
||||
} else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
|
||||
/* CTS went low. */
|
||||
if (!(k->cached_mcr & MCR_RTS))
|
||||
printk("confused: RTS already low\n");
|
||||
|
||||
k->cached_mcr &= ~MCR_RTS;
|
||||
|
||||
ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
|
||||
}
|
||||
|
||||
k->last_msr = msr;
|
||||
|
||||
lsr = ctrl_inb(EC3104_SER4_LSR);
|
||||
|
||||
if (lsr & LSR_DR)
|
||||
e5_receive(k);
|
||||
}
|
||||
|
||||
static void ec3104_keyb_clear_state(void)
|
||||
{
|
||||
struct e5_struct *k = &ec3104_keyb;
|
||||
u8 msr, lsr;
|
||||
|
||||
/* we want CTS to be low */
|
||||
k->last_msr = 0;
|
||||
|
||||
for (;;) {
|
||||
msleep(100);
|
||||
|
||||
msr = ctrl_inb(EC3104_SER4_MSR);
|
||||
|
||||
lsr = ctrl_inb(EC3104_SER4_LSR);
|
||||
|
||||
if (lsr & LSR_DR) {
|
||||
e5_receive(k);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
|
||||
if (k->cached_mcr & MCR_RTS)
|
||||
printk("confused: RTS already high\n");
|
||||
/* CTS went high. Send RTS. */
|
||||
k->cached_mcr |= MCR_RTS;
|
||||
|
||||
ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
|
||||
} else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
|
||||
/* CTS went low. */
|
||||
if (!(k->cached_mcr & MCR_RTS))
|
||||
printk("confused: RTS already low\n");
|
||||
|
||||
k->cached_mcr &= ~MCR_RTS;
|
||||
|
||||
ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
|
||||
} else
|
||||
break;
|
||||
|
||||
k->last_msr = msr;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
void __init ec3104_kbd_init_hw(void)
|
||||
{
|
||||
ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR);
|
||||
ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR);
|
||||
|
||||
ec3104_keyb_clear_state();
|
||||
|
||||
/* Ok, finally allocate the IRQ, and off we go.. */
|
||||
request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL);
|
||||
}
|
@ -158,6 +158,7 @@ config SENSORS_K8TEMP
|
||||
config SENSORS_AMS
|
||||
tristate "Apple Motion Sensor driver"
|
||||
depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
|
||||
select INPUT_POLLDEV
|
||||
help
|
||||
Support for the motion sensor included in PowerBooks. Includes
|
||||
implementations for PMU and I2C.
|
||||
@ -701,6 +702,7 @@ config SENSORS_W83627EHF
|
||||
config SENSORS_HDAPS
|
||||
tristate "IBM Hard Drive Active Protection System (hdaps)"
|
||||
depends on INPUT && X86
|
||||
select INPUT_POLLDEV
|
||||
default n
|
||||
help
|
||||
This driver provides support for the IBM Hard Drive Active Protection
|
||||
@ -722,6 +724,7 @@ config SENSORS_APPLESMC
|
||||
depends on INPUT && X86
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select INPUT_POLLDEV
|
||||
default n
|
||||
help
|
||||
This driver provides support for the Apple System Management
|
||||
|
@ -27,47 +27,32 @@ static unsigned int invert;
|
||||
module_param(invert, bool, 0644);
|
||||
MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
|
||||
|
||||
static int ams_input_kthread(void *data)
|
||||
static void ams_idev_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
struct input_dev *idev = dev->input;
|
||||
s8 x, y, z;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
mutex_lock(&ams_info.lock);
|
||||
mutex_lock(&ams_info.lock);
|
||||
|
||||
ams_sensors(&x, &y, &z);
|
||||
ams_sensors(&x, &y, &z);
|
||||
|
||||
x -= ams_info.xcalib;
|
||||
y -= ams_info.ycalib;
|
||||
z -= ams_info.zcalib;
|
||||
x -= ams_info.xcalib;
|
||||
y -= ams_info.ycalib;
|
||||
z -= ams_info.zcalib;
|
||||
|
||||
input_report_abs(ams_info.idev, ABS_X, invert ? -x : x);
|
||||
input_report_abs(ams_info.idev, ABS_Y, invert ? -y : y);
|
||||
input_report_abs(ams_info.idev, ABS_Z, z);
|
||||
input_report_abs(idev, ABS_X, invert ? -x : x);
|
||||
input_report_abs(idev, ABS_Y, invert ? -y : y);
|
||||
input_report_abs(idev, ABS_Z, z);
|
||||
|
||||
input_sync(ams_info.idev);
|
||||
input_sync(idev);
|
||||
|
||||
mutex_unlock(&ams_info.lock);
|
||||
|
||||
msleep(25);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ams_input_open(struct input_dev *dev)
|
||||
{
|
||||
ams_info.kthread = kthread_run(ams_input_kthread, NULL, "kams");
|
||||
return IS_ERR(ams_info.kthread) ? PTR_ERR(ams_info.kthread) : 0;
|
||||
}
|
||||
|
||||
static void ams_input_close(struct input_dev *dev)
|
||||
{
|
||||
kthread_stop(ams_info.kthread);
|
||||
mutex_unlock(&ams_info.lock);
|
||||
}
|
||||
|
||||
/* Call with ams_info.lock held! */
|
||||
static void ams_input_enable(void)
|
||||
{
|
||||
struct input_dev *input;
|
||||
s8 x, y, z;
|
||||
|
||||
if (ams_info.idev)
|
||||
@ -78,27 +63,29 @@ static void ams_input_enable(void)
|
||||
ams_info.ycalib = y;
|
||||
ams_info.zcalib = z;
|
||||
|
||||
ams_info.idev = input_allocate_device();
|
||||
ams_info.idev = input_allocate_polled_device();
|
||||
if (!ams_info.idev)
|
||||
return;
|
||||
|
||||
ams_info.idev->name = "Apple Motion Sensor";
|
||||
ams_info.idev->id.bustype = ams_info.bustype;
|
||||
ams_info.idev->id.vendor = 0;
|
||||
ams_info.idev->open = ams_input_open;
|
||||
ams_info.idev->close = ams_input_close;
|
||||
ams_info.idev->dev.parent = &ams_info.of_dev->dev;
|
||||
ams_info.idev->poll = ams_idev_poll;
|
||||
ams_info.idev->poll_interval = 25;
|
||||
|
||||
input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0);
|
||||
input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0);
|
||||
input_set_abs_params(ams_info.idev, ABS_Z, -50, 50, 3, 0);
|
||||
input = ams_info.idev->input;
|
||||
input->name = "Apple Motion Sensor";
|
||||
input->id.bustype = ams_info.bustype;
|
||||
input->id.vendor = 0;
|
||||
input->dev.parent = &ams_info.of_dev->dev;
|
||||
|
||||
set_bit(EV_ABS, ams_info.idev->evbit);
|
||||
set_bit(EV_KEY, ams_info.idev->evbit);
|
||||
set_bit(BTN_TOUCH, ams_info.idev->keybit);
|
||||
input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
|
||||
input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
|
||||
input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
|
||||
|
||||
if (input_register_device(ams_info.idev)) {
|
||||
input_free_device(ams_info.idev);
|
||||
set_bit(EV_ABS, input->evbit);
|
||||
set_bit(EV_KEY, input->evbit);
|
||||
set_bit(BTN_TOUCH, input->keybit);
|
||||
|
||||
if (input_register_polled_device(ams_info.idev)) {
|
||||
input_free_polled_device(ams_info.idev);
|
||||
ams_info.idev = NULL;
|
||||
return;
|
||||
}
|
||||
@ -108,7 +95,8 @@ static void ams_input_enable(void)
|
||||
static void ams_input_disable(void)
|
||||
{
|
||||
if (ams_info.idev) {
|
||||
input_unregister_device(ams_info.idev);
|
||||
input_unregister_polled_device(ams_info.idev);
|
||||
input_free_polled_device(ams_info.idev);
|
||||
ams_info.idev = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
@ -52,8 +52,7 @@ struct ams {
|
||||
#endif
|
||||
|
||||
/* Joystick emulation */
|
||||
struct task_struct *kthread;
|
||||
struct input_dev *idev;
|
||||
struct input_polled_dev *idev;
|
||||
__u16 bustype;
|
||||
|
||||
/* calibrated null values */
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
@ -59,9 +59,9 @@
|
||||
|
||||
#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */
|
||||
#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */
|
||||
#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
|
||||
#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
|
||||
|
||||
#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
|
||||
#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
|
||||
|
||||
#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
|
||||
#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
|
||||
@ -103,7 +103,7 @@ static const char* fan_speed_keys[] = {
|
||||
#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
|
||||
#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
|
||||
|
||||
#define APPLESMC_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
|
||||
#define APPLESMC_POLL_INTERVAL 50 /* msecs */
|
||||
#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
|
||||
#define APPLESMC_INPUT_FLAT 4
|
||||
|
||||
@ -125,9 +125,8 @@ static const int debug;
|
||||
static struct platform_device *pdev;
|
||||
static s16 rest_x;
|
||||
static s16 rest_y;
|
||||
static struct timer_list applesmc_timer;
|
||||
static struct input_dev *applesmc_idev;
|
||||
static struct device *hwmon_dev;
|
||||
static struct input_polled_dev *applesmc_idev;
|
||||
|
||||
/* Indicates whether this computer has an accelerometer. */
|
||||
static unsigned int applesmc_accelerometer;
|
||||
@ -138,7 +137,7 @@ static unsigned int applesmc_light;
|
||||
/* Indicates which temperature sensors set to use. */
|
||||
static unsigned int applesmc_temperature_set;
|
||||
|
||||
static struct mutex applesmc_lock;
|
||||
static DEFINE_MUTEX(applesmc_lock);
|
||||
|
||||
/*
|
||||
* Last index written to key_at_index sysfs file, and value to use for all other
|
||||
@ -455,27 +454,12 @@ static void applesmc_calibrate(void)
|
||||
rest_x = -rest_x;
|
||||
}
|
||||
|
||||
static int applesmc_idev_open(struct input_dev *dev)
|
||||
{
|
||||
add_timer(&applesmc_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void applesmc_idev_close(struct input_dev *dev)
|
||||
{
|
||||
del_timer_sync(&applesmc_timer);
|
||||
}
|
||||
|
||||
static void applesmc_idev_poll(unsigned long unused)
|
||||
static void applesmc_idev_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
struct input_dev *idev = dev->input;
|
||||
s16 x, y;
|
||||
|
||||
/* Cannot sleep. Try nonblockingly. If we fail, try again later. */
|
||||
if (!mutex_trylock(&applesmc_lock)) {
|
||||
mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
|
||||
return;
|
||||
}
|
||||
mutex_lock(&applesmc_lock);
|
||||
|
||||
if (applesmc_read_motion_sensor(SENSOR_X, &x))
|
||||
goto out;
|
||||
@ -483,13 +467,11 @@ static void applesmc_idev_poll(unsigned long unused)
|
||||
goto out;
|
||||
|
||||
x = -x;
|
||||
input_report_abs(applesmc_idev, ABS_X, x - rest_x);
|
||||
input_report_abs(applesmc_idev, ABS_Y, y - rest_y);
|
||||
input_sync(applesmc_idev);
|
||||
input_report_abs(idev, ABS_X, x - rest_x);
|
||||
input_report_abs(idev, ABS_Y, y - rest_y);
|
||||
input_sync(idev);
|
||||
|
||||
out:
|
||||
mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
|
||||
|
||||
mutex_unlock(&applesmc_lock);
|
||||
}
|
||||
|
||||
@ -821,8 +803,7 @@ static ssize_t applesmc_key_at_index_read_show(struct device *dev,
|
||||
|
||||
if (!ret) {
|
||||
return info[0];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -1093,6 +1074,7 @@ static int applesmc_dmi_match(const struct dmi_system_id *id)
|
||||
/* Create accelerometer ressources */
|
||||
static int applesmc_create_accelerometer(void)
|
||||
{
|
||||
struct input_dev *idev;
|
||||
int ret;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj,
|
||||
@ -1100,40 +1082,37 @@ static int applesmc_create_accelerometer(void)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
applesmc_idev = input_allocate_device();
|
||||
applesmc_idev = input_allocate_polled_device();
|
||||
if (!applesmc_idev) {
|
||||
ret = -ENOMEM;
|
||||
goto out_sysfs;
|
||||
}
|
||||
|
||||
applesmc_idev->poll = applesmc_idev_poll;
|
||||
applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
|
||||
|
||||
/* initial calibrate for the input device */
|
||||
applesmc_calibrate();
|
||||
|
||||
/* initialize the input class */
|
||||
applesmc_idev->name = "applesmc";
|
||||
applesmc_idev->id.bustype = BUS_HOST;
|
||||
applesmc_idev->dev.parent = &pdev->dev;
|
||||
applesmc_idev->evbit[0] = BIT(EV_ABS);
|
||||
applesmc_idev->open = applesmc_idev_open;
|
||||
applesmc_idev->close = applesmc_idev_close;
|
||||
input_set_abs_params(applesmc_idev, ABS_X,
|
||||
/* initialize the input device */
|
||||
idev = applesmc_idev->input;
|
||||
idev->name = "applesmc";
|
||||
idev->id.bustype = BUS_HOST;
|
||||
idev->dev.parent = &pdev->dev;
|
||||
idev->evbit[0] = BIT(EV_ABS);
|
||||
input_set_abs_params(idev, ABS_X,
|
||||
-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
|
||||
input_set_abs_params(applesmc_idev, ABS_Y,
|
||||
input_set_abs_params(idev, ABS_Y,
|
||||
-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
|
||||
|
||||
ret = input_register_device(applesmc_idev);
|
||||
ret = input_register_polled_device(applesmc_idev);
|
||||
if (ret)
|
||||
goto out_idev;
|
||||
|
||||
/* start up our timer for the input device */
|
||||
init_timer(&applesmc_timer);
|
||||
applesmc_timer.function = applesmc_idev_poll;
|
||||
applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD;
|
||||
|
||||
return 0;
|
||||
|
||||
out_idev:
|
||||
input_free_device(applesmc_idev);
|
||||
input_free_polled_device(applesmc_idev);
|
||||
|
||||
out_sysfs:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
|
||||
@ -1146,8 +1125,8 @@ out:
|
||||
/* Release all ressources used by the accelerometer */
|
||||
static void applesmc_release_accelerometer(void)
|
||||
{
|
||||
del_timer_sync(&applesmc_timer);
|
||||
input_unregister_device(applesmc_idev);
|
||||
input_unregister_polled_device(applesmc_idev);
|
||||
input_free_polled_device(applesmc_idev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
|
||||
}
|
||||
|
||||
@ -1184,8 +1163,6 @@ static int __init applesmc_init(void)
|
||||
int count;
|
||||
int i;
|
||||
|
||||
mutex_init(&applesmc_lock);
|
||||
|
||||
if (!dmi_check_system(applesmc_whitelist)) {
|
||||
printk(KERN_WARNING "applesmc: supported laptop not found!\n");
|
||||
ret = -ENODEV;
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
@ -61,13 +61,12 @@
|
||||
#define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */
|
||||
#define INIT_WAIT_MSECS 200 /* ... in 200ms increments */
|
||||
|
||||
#define HDAPS_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
|
||||
#define HDAPS_POLL_INTERVAL 50 /* poll for input every 1/20s (50 ms)*/
|
||||
#define HDAPS_INPUT_FUZZ 4 /* input event threshold */
|
||||
#define HDAPS_INPUT_FLAT 4
|
||||
|
||||
static struct timer_list hdaps_timer;
|
||||
static struct platform_device *pdev;
|
||||
static struct input_dev *hdaps_idev;
|
||||
static struct input_polled_dev *hdaps_idev;
|
||||
static unsigned int hdaps_invert;
|
||||
static u8 km_activity;
|
||||
static int rest_x;
|
||||
@ -323,24 +322,19 @@ static void hdaps_calibrate(void)
|
||||
__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y);
|
||||
}
|
||||
|
||||
static void hdaps_mousedev_poll(unsigned long unused)
|
||||
static void hdaps_mousedev_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
struct input_dev *input_dev = dev->input;
|
||||
int x, y;
|
||||
|
||||
/* Cannot sleep. Try nonblockingly. If we fail, try again later. */
|
||||
if (mutex_trylock(&hdaps_mtx)) {
|
||||
mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD);
|
||||
return;
|
||||
}
|
||||
mutex_lock(&hdaps_mtx);
|
||||
|
||||
if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
|
||||
goto out;
|
||||
|
||||
input_report_abs(hdaps_idev, ABS_X, x - rest_x);
|
||||
input_report_abs(hdaps_idev, ABS_Y, y - rest_y);
|
||||
input_sync(hdaps_idev);
|
||||
|
||||
mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
|
||||
input_report_abs(input_dev, ABS_X, x - rest_x);
|
||||
input_report_abs(input_dev, ABS_Y, y - rest_y);
|
||||
input_sync(input_dev);
|
||||
|
||||
out:
|
||||
mutex_unlock(&hdaps_mtx);
|
||||
@ -536,6 +530,7 @@ static struct dmi_system_id __initdata hdaps_whitelist[] = {
|
||||
|
||||
static int __init hdaps_init(void)
|
||||
{
|
||||
struct input_dev *idev;
|
||||
int ret;
|
||||
|
||||
if (!dmi_check_system(hdaps_whitelist)) {
|
||||
@ -563,39 +558,37 @@ static int __init hdaps_init(void)
|
||||
if (ret)
|
||||
goto out_device;
|
||||
|
||||
hdaps_idev = input_allocate_device();
|
||||
hdaps_idev = input_allocate_polled_device();
|
||||
if (!hdaps_idev) {
|
||||
ret = -ENOMEM;
|
||||
goto out_group;
|
||||
}
|
||||
|
||||
hdaps_idev->poll = hdaps_mousedev_poll;
|
||||
hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL;
|
||||
|
||||
/* initial calibrate for the input device */
|
||||
hdaps_calibrate();
|
||||
|
||||
/* initialize the input class */
|
||||
hdaps_idev->name = "hdaps";
|
||||
hdaps_idev->dev.parent = &pdev->dev;
|
||||
hdaps_idev->evbit[0] = BIT(EV_ABS);
|
||||
input_set_abs_params(hdaps_idev, ABS_X,
|
||||
idev = hdaps_idev->input;
|
||||
idev->name = "hdaps";
|
||||
idev->dev.parent = &pdev->dev;
|
||||
idev->evbit[0] = BIT(EV_ABS);
|
||||
input_set_abs_params(idev, ABS_X,
|
||||
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
|
||||
input_set_abs_params(hdaps_idev, ABS_Y,
|
||||
input_set_abs_params(idev, ABS_Y,
|
||||
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
|
||||
|
||||
ret = input_register_device(hdaps_idev);
|
||||
ret = input_register_polled_device(hdaps_idev);
|
||||
if (ret)
|
||||
goto out_idev;
|
||||
|
||||
/* start up our timer for the input device */
|
||||
init_timer(&hdaps_timer);
|
||||
hdaps_timer.function = hdaps_mousedev_poll;
|
||||
hdaps_timer.expires = jiffies + HDAPS_POLL_PERIOD;
|
||||
add_timer(&hdaps_timer);
|
||||
|
||||
printk(KERN_INFO "hdaps: driver successfully loaded.\n");
|
||||
return 0;
|
||||
|
||||
out_idev:
|
||||
input_free_device(hdaps_idev);
|
||||
input_free_polled_device(hdaps_idev);
|
||||
out_group:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
|
||||
out_device:
|
||||
@ -611,8 +604,8 @@ out:
|
||||
|
||||
static void __exit hdaps_exit(void)
|
||||
{
|
||||
del_timer_sync(&hdaps_timer);
|
||||
input_unregister_device(hdaps_idev);
|
||||
input_unregister_polled_device(hdaps_idev);
|
||||
input_free_polled_device(hdaps_idev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
|
||||
platform_device_unregister(pdev);
|
||||
platform_driver_unregister(&hdaps_driver);
|
||||
|
@ -114,28 +114,6 @@ config INPUT_JOYDEV
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called joydev.
|
||||
|
||||
config INPUT_TSDEV
|
||||
tristate "Touchscreen interface"
|
||||
---help---
|
||||
Say Y here if you have an application that only can understand the
|
||||
Compaq touchscreen protocol for absolute pointer data. This is
|
||||
useful namely for embedded configurations.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tsdev.
|
||||
|
||||
config INPUT_TSDEV_SCREEN_X
|
||||
int "Horizontal screen resolution"
|
||||
depends on INPUT_TSDEV
|
||||
default "240"
|
||||
|
||||
config INPUT_TSDEV_SCREEN_Y
|
||||
int "Vertical screen resolution"
|
||||
depends on INPUT_TSDEV
|
||||
default "320"
|
||||
|
||||
config INPUT_EVDEV
|
||||
tristate "Event interface"
|
||||
help
|
||||
|
@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
|
||||
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
|
||||
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
|
||||
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
|
||||
obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
|
||||
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
|
||||
|
||||
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -70,6 +70,7 @@ static int input_open_polled_device(struct input_dev *input)
|
||||
{
|
||||
struct input_polled_dev *dev = input->private;
|
||||
int error;
|
||||
unsigned long ticks;
|
||||
|
||||
error = input_polldev_start_workqueue();
|
||||
if (error)
|
||||
@ -78,8 +79,10 @@ static int input_open_polled_device(struct input_dev *input)
|
||||
if (dev->flush)
|
||||
dev->flush(dev);
|
||||
|
||||
queue_delayed_work(polldev_wq, &dev->work,
|
||||
msecs_to_jiffies(dev->poll_interval));
|
||||
ticks = msecs_to_jiffies(dev->poll_interval);
|
||||
if (ticks >= HZ)
|
||||
ticks = round_jiffies(ticks);
|
||||
queue_delayed_work(polldev_wq, &dev->work, ticks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -17,10 +17,10 @@
|
||||
#include <linux/major.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
|
||||
MODULE_DESCRIPTION("Input core");
|
||||
@ -31,8 +31,222 @@ MODULE_LICENSE("GPL");
|
||||
static LIST_HEAD(input_dev_list);
|
||||
static LIST_HEAD(input_handler_list);
|
||||
|
||||
/*
|
||||
* input_mutex protects access to both input_dev_list and input_handler_list.
|
||||
* This also causes input_[un]register_device and input_[un]register_handler
|
||||
* be mutually exclusive which simplifies locking in drivers implementing
|
||||
* input handlers.
|
||||
*/
|
||||
static DEFINE_MUTEX(input_mutex);
|
||||
|
||||
static struct input_handler *input_table[8];
|
||||
|
||||
static inline int is_event_supported(unsigned int code,
|
||||
unsigned long *bm, unsigned int max)
|
||||
{
|
||||
return code <= max && test_bit(code, bm);
|
||||
}
|
||||
|
||||
static int input_defuzz_abs_event(int value, int old_val, int fuzz)
|
||||
{
|
||||
if (fuzz) {
|
||||
if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
|
||||
return old_val;
|
||||
|
||||
if (value > old_val - fuzz && value < old_val + fuzz)
|
||||
return (old_val * 3 + value) / 4;
|
||||
|
||||
if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
|
||||
return (old_val + value) / 2;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass event through all open handles. This function is called with
|
||||
* dev->event_lock held and interrupts disabled.
|
||||
*/
|
||||
static void input_pass_event(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
handle = rcu_dereference(dev->grab);
|
||||
if (handle)
|
||||
handle->handler->event(handle, type, code, value);
|
||||
else
|
||||
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
|
||||
if (handle->open)
|
||||
handle->handler->event(handle,
|
||||
type, code, value);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate software autorepeat event. Note that we take
|
||||
* dev->event_lock here to avoid racing with input_event
|
||||
* which may cause keys get "stuck".
|
||||
*/
|
||||
static void input_repeat_key(unsigned long data)
|
||||
{
|
||||
struct input_dev *dev = (void *) data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
|
||||
if (test_bit(dev->repeat_key, dev->key) &&
|
||||
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
|
||||
|
||||
input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
|
||||
|
||||
if (dev->sync) {
|
||||
/*
|
||||
* Only send SYN_REPORT if we are not in a middle
|
||||
* of driver parsing a new hardware packet.
|
||||
* Otherwise assume that the driver will send
|
||||
* SYN_REPORT once it's done.
|
||||
*/
|
||||
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
|
||||
}
|
||||
|
||||
if (dev->rep[REP_PERIOD])
|
||||
mod_timer(&dev->timer, jiffies +
|
||||
msecs_to_jiffies(dev->rep[REP_PERIOD]));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
static void input_start_autorepeat(struct input_dev *dev, int code)
|
||||
{
|
||||
if (test_bit(EV_REP, dev->evbit) &&
|
||||
dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
|
||||
dev->timer.data) {
|
||||
dev->repeat_key = code;
|
||||
mod_timer(&dev->timer,
|
||||
jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
|
||||
}
|
||||
}
|
||||
|
||||
#define INPUT_IGNORE_EVENT 0
|
||||
#define INPUT_PASS_TO_HANDLERS 1
|
||||
#define INPUT_PASS_TO_DEVICE 2
|
||||
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
|
||||
|
||||
static void input_handle_event(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
int disposition = INPUT_IGNORE_EVENT;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case EV_SYN:
|
||||
switch (code) {
|
||||
case SYN_CONFIG:
|
||||
disposition = INPUT_PASS_TO_ALL;
|
||||
break;
|
||||
|
||||
case SYN_REPORT:
|
||||
if (!dev->sync) {
|
||||
dev->sync = 1;
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_KEY:
|
||||
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
|
||||
!!test_bit(code, dev->key) != value) {
|
||||
|
||||
if (value != 2) {
|
||||
__change_bit(code, dev->key);
|
||||
if (value)
|
||||
input_start_autorepeat(dev, code);
|
||||
}
|
||||
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_SW:
|
||||
if (is_event_supported(code, dev->swbit, SW_MAX) &&
|
||||
!!test_bit(code, dev->sw) != value) {
|
||||
|
||||
__change_bit(code, dev->sw);
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_ABS:
|
||||
if (is_event_supported(code, dev->absbit, ABS_MAX)) {
|
||||
|
||||
value = input_defuzz_abs_event(value,
|
||||
dev->abs[code], dev->absfuzz[code]);
|
||||
|
||||
if (dev->abs[code] != value) {
|
||||
dev->abs[code] = value;
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
|
||||
break;
|
||||
|
||||
case EV_MSC:
|
||||
if (is_event_supported(code, dev->mscbit, MSC_MAX))
|
||||
disposition = INPUT_PASS_TO_ALL;
|
||||
|
||||
break;
|
||||
|
||||
case EV_LED:
|
||||
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
|
||||
!!test_bit(code, dev->led) != value) {
|
||||
|
||||
__change_bit(code, dev->led);
|
||||
disposition = INPUT_PASS_TO_ALL;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_SND:
|
||||
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
|
||||
|
||||
if (!!test_bit(code, dev->snd) != !!value)
|
||||
__change_bit(code, dev->snd);
|
||||
disposition = INPUT_PASS_TO_ALL;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_REP:
|
||||
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
|
||||
dev->rep[code] = value;
|
||||
disposition = INPUT_PASS_TO_ALL;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_FF:
|
||||
if (value >= 0)
|
||||
disposition = INPUT_PASS_TO_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (type != EV_SYN)
|
||||
dev->sync = 0;
|
||||
|
||||
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
|
||||
dev->event(dev, type, code, value);
|
||||
|
||||
if (disposition & INPUT_PASS_TO_HANDLERS)
|
||||
input_pass_event(dev, type, code, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* input_event() - report new input event
|
||||
* @dev: device that generated the event
|
||||
@ -40,158 +254,22 @@ static struct input_handler *input_table[8];
|
||||
* @code: event code
|
||||
* @value: value of the event
|
||||
*
|
||||
* This function should be used by drivers implementing various input devices
|
||||
* See also input_inject_event()
|
||||
* This function should be used by drivers implementing various input
|
||||
* devices. See also input_inject_event().
|
||||
*/
|
||||
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
|
||||
void input_event(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
unsigned long flags;
|
||||
|
||||
if (type > EV_MAX || !test_bit(type, dev->evbit))
|
||||
return;
|
||||
if (is_event_supported(type, dev->evbit, EV_MAX)) {
|
||||
|
||||
add_input_randomness(type, code, value);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case EV_SYN:
|
||||
switch (code) {
|
||||
case SYN_CONFIG:
|
||||
if (dev->event)
|
||||
dev->event(dev, type, code, value);
|
||||
break;
|
||||
|
||||
case SYN_REPORT:
|
||||
if (dev->sync)
|
||||
return;
|
||||
dev->sync = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_KEY:
|
||||
|
||||
if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
|
||||
return;
|
||||
|
||||
if (value == 2)
|
||||
break;
|
||||
|
||||
change_bit(code, dev->key);
|
||||
|
||||
if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {
|
||||
dev->repeat_key = code;
|
||||
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EV_SW:
|
||||
|
||||
if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
|
||||
return;
|
||||
|
||||
change_bit(code, dev->sw);
|
||||
|
||||
break;
|
||||
|
||||
case EV_ABS:
|
||||
|
||||
if (code > ABS_MAX || !test_bit(code, dev->absbit))
|
||||
return;
|
||||
|
||||
if (dev->absfuzz[code]) {
|
||||
if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
|
||||
(value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
|
||||
return;
|
||||
|
||||
if ((value > dev->abs[code] - dev->absfuzz[code]) &&
|
||||
(value < dev->abs[code] + dev->absfuzz[code]))
|
||||
value = (dev->abs[code] * 3 + value) >> 2;
|
||||
|
||||
if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
|
||||
(value < dev->abs[code] + (dev->absfuzz[code] << 1)))
|
||||
value = (dev->abs[code] + value) >> 1;
|
||||
}
|
||||
|
||||
if (dev->abs[code] == value)
|
||||
return;
|
||||
|
||||
dev->abs[code] = value;
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
|
||||
if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
|
||||
return;
|
||||
|
||||
break;
|
||||
|
||||
case EV_MSC:
|
||||
|
||||
if (code > MSC_MAX || !test_bit(code, dev->mscbit))
|
||||
return;
|
||||
|
||||
if (dev->event)
|
||||
dev->event(dev, type, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_LED:
|
||||
|
||||
if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
|
||||
return;
|
||||
|
||||
change_bit(code, dev->led);
|
||||
|
||||
if (dev->event)
|
||||
dev->event(dev, type, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_SND:
|
||||
|
||||
if (code > SND_MAX || !test_bit(code, dev->sndbit))
|
||||
return;
|
||||
|
||||
if (!!test_bit(code, dev->snd) != !!value)
|
||||
change_bit(code, dev->snd);
|
||||
|
||||
if (dev->event)
|
||||
dev->event(dev, type, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_REP:
|
||||
|
||||
if (code > REP_MAX || value < 0 || dev->rep[code] == value)
|
||||
return;
|
||||
|
||||
dev->rep[code] = value;
|
||||
if (dev->event)
|
||||
dev->event(dev, type, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_FF:
|
||||
|
||||
if (value < 0)
|
||||
return;
|
||||
|
||||
if (dev->event)
|
||||
dev->event(dev, type, code, value);
|
||||
break;
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
add_input_randomness(type, code, value);
|
||||
input_handle_event(dev, type, code, value);
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
if (type != EV_SYN)
|
||||
dev->sync = 0;
|
||||
|
||||
if (dev->grab)
|
||||
dev->grab->handler->event(dev->grab, type, code, value);
|
||||
else
|
||||
list_for_each_entry(handle, &dev->h_list, d_node)
|
||||
if (handle->open)
|
||||
handle->handler->event(handle, type, code, value);
|
||||
}
|
||||
EXPORT_SYMBOL(input_event);
|
||||
|
||||
@ -202,102 +280,228 @@ EXPORT_SYMBOL(input_event);
|
||||
* @code: event code
|
||||
* @value: value of the event
|
||||
*
|
||||
* Similar to input_event() but will ignore event if device is "grabbed" and handle
|
||||
* injecting event is not the one that owns the device.
|
||||
* Similar to input_event() but will ignore event if device is
|
||||
* "grabbed" and handle injecting event is not the one that owns
|
||||
* the device.
|
||||
*/
|
||||
void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
||||
void input_inject_event(struct input_handle *handle,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
if (!handle->dev->grab || handle->dev->grab == handle)
|
||||
input_event(handle->dev, type, code, value);
|
||||
struct input_dev *dev = handle->dev;
|
||||
struct input_handle *grab;
|
||||
unsigned long flags;
|
||||
|
||||
if (is_event_supported(type, dev->evbit, EV_MAX)) {
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
|
||||
rcu_read_lock();
|
||||
grab = rcu_dereference(dev->grab);
|
||||
if (!grab || grab == handle)
|
||||
input_handle_event(dev, type, code, value);
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(input_inject_event);
|
||||
|
||||
static void input_repeat_key(unsigned long data)
|
||||
{
|
||||
struct input_dev *dev = (void *) data;
|
||||
|
||||
if (!test_bit(dev->repeat_key, dev->key))
|
||||
return;
|
||||
|
||||
input_event(dev, EV_KEY, dev->repeat_key, 2);
|
||||
input_sync(dev);
|
||||
|
||||
if (dev->rep[REP_PERIOD])
|
||||
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
|
||||
}
|
||||
|
||||
/**
|
||||
* input_grab_device - grabs device for exclusive use
|
||||
* @handle: input handle that wants to own the device
|
||||
*
|
||||
* When a device is grabbed by an input handle all events generated by
|
||||
* the device are delivered only to this handle. Also events injected
|
||||
* by other input handles are ignored while device is grabbed.
|
||||
*/
|
||||
int input_grab_device(struct input_handle *handle)
|
||||
{
|
||||
if (handle->dev->grab)
|
||||
return -EBUSY;
|
||||
struct input_dev *dev = handle->dev;
|
||||
int retval;
|
||||
|
||||
handle->dev->grab = handle;
|
||||
return 0;
|
||||
retval = mutex_lock_interruptible(&dev->mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (dev->grab) {
|
||||
retval = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(dev->grab, handle);
|
||||
synchronize_rcu();
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->mutex);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(input_grab_device);
|
||||
|
||||
void input_release_device(struct input_handle *handle)
|
||||
static void __input_release_device(struct input_handle *handle)
|
||||
{
|
||||
struct input_dev *dev = handle->dev;
|
||||
|
||||
if (dev->grab == handle) {
|
||||
dev->grab = NULL;
|
||||
rcu_assign_pointer(dev->grab, NULL);
|
||||
/* Make sure input_pass_event() notices that grab is gone */
|
||||
synchronize_rcu();
|
||||
|
||||
list_for_each_entry(handle, &dev->h_list, d_node)
|
||||
if (handle->handler->start)
|
||||
if (handle->open && handle->handler->start)
|
||||
handle->handler->start(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* input_release_device - release previously grabbed device
|
||||
* @handle: input handle that owns the device
|
||||
*
|
||||
* Releases previously grabbed device so that other input handles can
|
||||
* start receiving input events. Upon release all handlers attached
|
||||
* to the device have their start() method called so they have a change
|
||||
* to synchronize device state with the rest of the system.
|
||||
*/
|
||||
void input_release_device(struct input_handle *handle)
|
||||
{
|
||||
struct input_dev *dev = handle->dev;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
__input_release_device(handle);
|
||||
mutex_unlock(&dev->mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(input_release_device);
|
||||
|
||||
/**
|
||||
* input_open_device - open input device
|
||||
* @handle: handle through which device is being accessed
|
||||
*
|
||||
* This function should be called by input handlers when they
|
||||
* want to start receive events from given input device.
|
||||
*/
|
||||
int input_open_device(struct input_handle *handle)
|
||||
{
|
||||
struct input_dev *dev = handle->dev;
|
||||
int err;
|
||||
int retval;
|
||||
|
||||
err = mutex_lock_interruptible(&dev->mutex);
|
||||
if (err)
|
||||
return err;
|
||||
retval = mutex_lock_interruptible(&dev->mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (dev->going_away) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
handle->open++;
|
||||
|
||||
if (!dev->users++ && dev->open)
|
||||
err = dev->open(dev);
|
||||
retval = dev->open(dev);
|
||||
|
||||
if (err)
|
||||
handle->open--;
|
||||
if (retval) {
|
||||
dev->users--;
|
||||
if (!--handle->open) {
|
||||
/*
|
||||
* Make sure we are not delivering any more events
|
||||
* through this handle
|
||||
*/
|
||||
synchronize_rcu();
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
return err;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(input_open_device);
|
||||
|
||||
int input_flush_device(struct input_handle* handle, struct file* file)
|
||||
int input_flush_device(struct input_handle *handle, struct file *file)
|
||||
{
|
||||
if (handle->dev->flush)
|
||||
return handle->dev->flush(handle->dev, file);
|
||||
struct input_dev *dev = handle->dev;
|
||||
int retval;
|
||||
|
||||
return 0;
|
||||
retval = mutex_lock_interruptible(&dev->mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (dev->flush)
|
||||
retval = dev->flush(dev, file);
|
||||
|
||||
mutex_unlock(&dev->mutex);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(input_flush_device);
|
||||
|
||||
/**
|
||||
* input_close_device - close input device
|
||||
* @handle: handle through which device is being accessed
|
||||
*
|
||||
* This function should be called by input handlers when they
|
||||
* want to stop receive events from given input device.
|
||||
*/
|
||||
void input_close_device(struct input_handle *handle)
|
||||
{
|
||||
struct input_dev *dev = handle->dev;
|
||||
|
||||
input_release_device(handle);
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
__input_release_device(handle);
|
||||
|
||||
if (!--dev->users && dev->close)
|
||||
dev->close(dev);
|
||||
handle->open--;
|
||||
|
||||
if (!--handle->open) {
|
||||
/*
|
||||
* synchronize_rcu() makes sure that input_pass_event()
|
||||
* completed and that no more input events are delivered
|
||||
* through this handle
|
||||
*/
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(input_close_device);
|
||||
|
||||
/*
|
||||
* Prepare device for unregistering
|
||||
*/
|
||||
static void input_disconnect_device(struct input_dev *dev)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
int code;
|
||||
|
||||
/*
|
||||
* Mark device as going away. Note that we take dev->mutex here
|
||||
* not to protect access to dev->going_away but rather to ensure
|
||||
* that there are no threads in the middle of input_open_device()
|
||||
*/
|
||||
mutex_lock(&dev->mutex);
|
||||
dev->going_away = 1;
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
spin_lock_irq(&dev->event_lock);
|
||||
|
||||
/*
|
||||
* Simulate keyup events for all pressed keys so that handlers
|
||||
* are not left with "stuck" keys. The driver may continue
|
||||
* generate events even after we done here but they will not
|
||||
* reach any handlers.
|
||||
*/
|
||||
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
|
||||
for (code = 0; code <= KEY_MAX; code++) {
|
||||
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
|
||||
test_bit(code, dev->key)) {
|
||||
input_pass_event(dev, EV_KEY, code, 0);
|
||||
}
|
||||
}
|
||||
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
|
||||
}
|
||||
|
||||
list_for_each_entry(handle, &dev->h_list, d_node)
|
||||
handle->open = 0;
|
||||
|
||||
spin_unlock_irq(&dev->event_lock);
|
||||
}
|
||||
|
||||
static int input_fetch_keycode(struct input_dev *dev, int scancode)
|
||||
{
|
||||
switch (dev->keycodesize) {
|
||||
@ -473,7 +677,8 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
|
||||
|
||||
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
/* acquire lock here ... Yes, we do need locking, I knowi, I know... */
|
||||
if (mutex_lock_interruptible(&input_mutex))
|
||||
return NULL;
|
||||
|
||||
return seq_list_start(&input_dev_list, *pos);
|
||||
}
|
||||
@ -485,7 +690,7 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
|
||||
static void input_devices_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
/* release lock here */
|
||||
mutex_unlock(&input_mutex);
|
||||
}
|
||||
|
||||
static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
|
||||
@ -569,7 +774,9 @@ static const struct file_operations input_devices_fileops = {
|
||||
|
||||
static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
/* acquire lock here ... Yes, we do need locking, I knowi, I know... */
|
||||
if (mutex_lock_interruptible(&input_mutex))
|
||||
return NULL;
|
||||
|
||||
seq->private = (void *)(unsigned long)*pos;
|
||||
return seq_list_start(&input_handler_list, *pos);
|
||||
}
|
||||
@ -582,7 +789,7 @@ static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
|
||||
static void input_handlers_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
/* release lock here */
|
||||
mutex_unlock(&input_mutex);
|
||||
}
|
||||
|
||||
static int input_handlers_seq_show(struct seq_file *seq, void *v)
|
||||
@ -983,6 +1190,7 @@ struct input_dev *input_allocate_device(void)
|
||||
dev->dev.class = &input_class;
|
||||
device_initialize(&dev->dev);
|
||||
mutex_init(&dev->mutex);
|
||||
spin_lock_init(&dev->event_lock);
|
||||
INIT_LIST_HEAD(&dev->h_list);
|
||||
INIT_LIST_HEAD(&dev->node);
|
||||
|
||||
@ -1000,7 +1208,7 @@ EXPORT_SYMBOL(input_allocate_device);
|
||||
* This function should only be used if input_register_device()
|
||||
* was not called yet or if it failed. Once device was registered
|
||||
* use input_unregister_device() and memory will be freed once last
|
||||
* refrence to the device is dropped.
|
||||
* reference to the device is dropped.
|
||||
*
|
||||
* Device should be allocated by input_allocate_device().
|
||||
*
|
||||
@ -1070,6 +1278,18 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
|
||||
}
|
||||
EXPORT_SYMBOL(input_set_capability);
|
||||
|
||||
/**
|
||||
* input_register_device - register device with input core
|
||||
* @dev: device to be registered
|
||||
*
|
||||
* This function registers device with input core. The device must be
|
||||
* allocated with input_allocate_device() and all it's capabilities
|
||||
* set up before registering.
|
||||
* If function fails the device must be freed with input_free_device().
|
||||
* Once device has been successfully registered it can be unregistered
|
||||
* with input_unregister_device(); input_free_device() should not be
|
||||
* called in this case.
|
||||
*/
|
||||
int input_register_device(struct input_dev *dev)
|
||||
{
|
||||
static atomic_t input_no = ATOMIC_INIT(0);
|
||||
@ -1077,7 +1297,7 @@ int input_register_device(struct input_dev *dev)
|
||||
const char *path;
|
||||
int error;
|
||||
|
||||
set_bit(EV_SYN, dev->evbit);
|
||||
__set_bit(EV_SYN, dev->evbit);
|
||||
|
||||
/*
|
||||
* If delay and period are pre-set by the driver, then autorepeating
|
||||
@ -1098,8 +1318,6 @@ int input_register_device(struct input_dev *dev)
|
||||
if (!dev->setkeycode)
|
||||
dev->setkeycode = input_default_setkeycode;
|
||||
|
||||
list_add_tail(&dev->node, &input_dev_list);
|
||||
|
||||
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
|
||||
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
|
||||
|
||||
@ -1115,49 +1333,79 @@ int input_register_device(struct input_dev *dev)
|
||||
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
|
||||
kfree(path);
|
||||
|
||||
error = mutex_lock_interruptible(&input_mutex);
|
||||
if (error) {
|
||||
device_del(&dev->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
list_add_tail(&dev->node, &input_dev_list);
|
||||
|
||||
list_for_each_entry(handler, &input_handler_list, node)
|
||||
input_attach_handler(dev, handler);
|
||||
|
||||
input_wakeup_procfs_readers();
|
||||
|
||||
mutex_unlock(&input_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(input_register_device);
|
||||
|
||||
/**
|
||||
* input_unregister_device - unregister previously registered device
|
||||
* @dev: device to be unregistered
|
||||
*
|
||||
* This function unregisters an input device. Once device is unregistered
|
||||
* the caller should not try to access it as it may get freed at any moment.
|
||||
*/
|
||||
void input_unregister_device(struct input_dev *dev)
|
||||
{
|
||||
struct input_handle *handle, *next;
|
||||
int code;
|
||||
|
||||
for (code = 0; code <= KEY_MAX; code++)
|
||||
if (test_bit(code, dev->key))
|
||||
input_report_key(dev, code, 0);
|
||||
input_sync(dev);
|
||||
input_disconnect_device(dev);
|
||||
|
||||
del_timer_sync(&dev->timer);
|
||||
mutex_lock(&input_mutex);
|
||||
|
||||
list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
|
||||
handle->handler->disconnect(handle);
|
||||
WARN_ON(!list_empty(&dev->h_list));
|
||||
|
||||
del_timer_sync(&dev->timer);
|
||||
list_del_init(&dev->node);
|
||||
|
||||
device_unregister(&dev->dev);
|
||||
|
||||
input_wakeup_procfs_readers();
|
||||
|
||||
mutex_unlock(&input_mutex);
|
||||
|
||||
device_unregister(&dev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(input_unregister_device);
|
||||
|
||||
/**
|
||||
* input_register_handler - register a new input handler
|
||||
* @handler: handler to be registered
|
||||
*
|
||||
* This function registers a new input handler (interface) for input
|
||||
* devices in the system and attaches it to all input devices that
|
||||
* are compatible with the handler.
|
||||
*/
|
||||
int input_register_handler(struct input_handler *handler)
|
||||
{
|
||||
struct input_dev *dev;
|
||||
int retval;
|
||||
|
||||
retval = mutex_lock_interruptible(&input_mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
INIT_LIST_HEAD(&handler->h_list);
|
||||
|
||||
if (handler->fops != NULL) {
|
||||
if (input_table[handler->minor >> 5])
|
||||
return -EBUSY;
|
||||
|
||||
if (input_table[handler->minor >> 5]) {
|
||||
retval = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
input_table[handler->minor >> 5] = handler;
|
||||
}
|
||||
|
||||
@ -1167,14 +1415,26 @@ int input_register_handler(struct input_handler *handler)
|
||||
input_attach_handler(dev, handler);
|
||||
|
||||
input_wakeup_procfs_readers();
|
||||
return 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&input_mutex);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(input_register_handler);
|
||||
|
||||
/**
|
||||
* input_unregister_handler - unregisters an input handler
|
||||
* @handler: handler to be unregistered
|
||||
*
|
||||
* This function disconnects a handler from its input devices and
|
||||
* removes it from lists of known handlers.
|
||||
*/
|
||||
void input_unregister_handler(struct input_handler *handler)
|
||||
{
|
||||
struct input_handle *handle, *next;
|
||||
|
||||
mutex_lock(&input_mutex);
|
||||
|
||||
list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
|
||||
handler->disconnect(handle);
|
||||
WARN_ON(!list_empty(&handler->h_list));
|
||||
@ -1185,14 +1445,45 @@ void input_unregister_handler(struct input_handler *handler)
|
||||
input_table[handler->minor >> 5] = NULL;
|
||||
|
||||
input_wakeup_procfs_readers();
|
||||
|
||||
mutex_unlock(&input_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(input_unregister_handler);
|
||||
|
||||
/**
|
||||
* input_register_handle - register a new input handle
|
||||
* @handle: handle to register
|
||||
*
|
||||
* This function puts a new input handle onto device's
|
||||
* and handler's lists so that events can flow through
|
||||
* it once it is opened using input_open_device().
|
||||
*
|
||||
* This function is supposed to be called from handler's
|
||||
* connect() method.
|
||||
*/
|
||||
int input_register_handle(struct input_handle *handle)
|
||||
{
|
||||
struct input_handler *handler = handle->handler;
|
||||
struct input_dev *dev = handle->dev;
|
||||
int error;
|
||||
|
||||
list_add_tail(&handle->d_node, &handle->dev->h_list);
|
||||
/*
|
||||
* We take dev->mutex here to prevent race with
|
||||
* input_release_device().
|
||||
*/
|
||||
error = mutex_lock_interruptible(&dev->mutex);
|
||||
if (error)
|
||||
return error;
|
||||
list_add_tail_rcu(&handle->d_node, &dev->h_list);
|
||||
mutex_unlock(&dev->mutex);
|
||||
synchronize_rcu();
|
||||
|
||||
/*
|
||||
* Since we are supposed to be called from ->connect()
|
||||
* which is mutually exclusive with ->disconnect()
|
||||
* we can't be racing with input_unregister_handle()
|
||||
* and so separate lock is not needed here.
|
||||
*/
|
||||
list_add_tail(&handle->h_node, &handler->h_list);
|
||||
|
||||
if (handler->start)
|
||||
@ -1202,10 +1493,29 @@ int input_register_handle(struct input_handle *handle)
|
||||
}
|
||||
EXPORT_SYMBOL(input_register_handle);
|
||||
|
||||
/**
|
||||
* input_unregister_handle - unregister an input handle
|
||||
* @handle: handle to unregister
|
||||
*
|
||||
* This function removes input handle from device's
|
||||
* and handler's lists.
|
||||
*
|
||||
* This function is supposed to be called from handler's
|
||||
* disconnect() method.
|
||||
*/
|
||||
void input_unregister_handle(struct input_handle *handle)
|
||||
{
|
||||
struct input_dev *dev = handle->dev;
|
||||
|
||||
list_del_init(&handle->h_node);
|
||||
list_del_init(&handle->d_node);
|
||||
|
||||
/*
|
||||
* Take dev->mutex to prevent race with input_release_device().
|
||||
*/
|
||||
mutex_lock(&dev->mutex);
|
||||
list_del_rcu(&handle->d_node);
|
||||
mutex_unlock(&dev->mutex);
|
||||
synchronize_rcu();
|
||||
}
|
||||
EXPORT_SYMBOL(input_unregister_handle);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -223,12 +223,16 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
||||
struct input_dev *dev = xpad->dev;
|
||||
|
||||
/* left stick */
|
||||
input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
|
||||
input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
|
||||
input_report_abs(dev, ABS_X,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 12)));
|
||||
input_report_abs(dev, ABS_Y,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 14)));
|
||||
|
||||
/* right stick */
|
||||
input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
|
||||
input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
|
||||
input_report_abs(dev, ABS_RX,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 16)));
|
||||
input_report_abs(dev, ABS_RY,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 18)));
|
||||
|
||||
/* triggers left/right */
|
||||
input_report_abs(dev, ABS_Z, data[10]);
|
||||
@ -236,8 +240,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
||||
|
||||
/* digital pad */
|
||||
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
|
||||
input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||
input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
|
||||
input_report_abs(dev, ABS_HAT0X,
|
||||
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||
input_report_abs(dev, ABS_HAT0Y,
|
||||
!!(data[2] & 0x02) - !!(data[2] & 0x01));
|
||||
} else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
|
||||
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
|
||||
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
|
||||
@ -274,14 +280,17 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
||||
* http://www.free60.org/wiki/Gamepad
|
||||
*/
|
||||
|
||||
static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
|
||||
static void xpad360_process_packet(struct usb_xpad *xpad,
|
||||
u16 cmd, unsigned char *data)
|
||||
{
|
||||
struct input_dev *dev = xpad->dev;
|
||||
|
||||
/* digital pad */
|
||||
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
|
||||
input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||
input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
|
||||
input_report_abs(dev, ABS_HAT0X,
|
||||
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||
input_report_abs(dev, ABS_HAT0Y,
|
||||
!!(data[2] & 0x02) - !!(data[2] & 0x01));
|
||||
} else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {
|
||||
/* dpad as buttons (right, left, down, up) */
|
||||
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
|
||||
@ -308,12 +317,16 @@ static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
|
||||
input_report_key(dev, BTN_MODE, data[3] & 0x04);
|
||||
|
||||
/* left stick */
|
||||
input_report_abs(dev, ABS_X, (__s16) (((__s16)data[7] << 8) | (__s16)data[6]));
|
||||
input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[9] << 8) | (__s16)data[8]));
|
||||
input_report_abs(dev, ABS_X,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 6)));
|
||||
input_report_abs(dev, ABS_Y,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 8)));
|
||||
|
||||
/* right stick */
|
||||
input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10]));
|
||||
input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[13] << 8) | (__s16)data[12]));
|
||||
input_report_abs(dev, ABS_RX,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 10)));
|
||||
input_report_abs(dev, ABS_RY,
|
||||
(__s16) le16_to_cpup((__le16 *)(data + 12)));
|
||||
|
||||
/* triggers left/right */
|
||||
input_report_abs(dev, ABS_Z, data[4]);
|
||||
@ -335,10 +348,12 @@ static void xpad_irq_in(struct urb *urb)
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
|
||||
dbg("%s - urb shutting down with status: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
|
||||
dbg("%s - nonzero urb status received: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -367,10 +382,12 @@ static void xpad_irq_out(struct urb *urb)
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
|
||||
dbg("%s - urb shutting down with status: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
|
||||
dbg("%s - nonzero urb status received: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -378,7 +395,7 @@ exit:
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
err("%s - usb_submit_urb failed with result %d",
|
||||
__FUNCTION__, retval);
|
||||
__FUNCTION__, retval);
|
||||
}
|
||||
|
||||
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||
@ -595,7 +612,7 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
|
||||
|
||||
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev (intf);
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct usb_xpad *xpad;
|
||||
struct input_dev *input_dev;
|
||||
struct usb_endpoint_descriptor *ep_irq_in;
|
||||
|
@ -208,6 +208,27 @@ config KEYBOARD_HIL
|
||||
This driver implements support for HIL-keyboards attached
|
||||
to your machine, so normally you should say Y here.
|
||||
|
||||
config KEYBOARD_HP6XX
|
||||
tristate "HP Jornada 6XX Keyboard support"
|
||||
depends on SH_HP6XX
|
||||
select INPUT_POLLDEV
|
||||
help
|
||||
This adds support for the onboard keyboard found on
|
||||
HP Jornada 620/660/680/690.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called jornada680_kbd.
|
||||
|
||||
config KEYBOARD_HP7XX
|
||||
tristate "HP Jornada 7XX Keyboard Driver"
|
||||
depends on SA1100_JORNADA720_SSP && SA1100_SSP
|
||||
help
|
||||
Say Y here to add support for the HP Jornada 7xx (710/720/728)
|
||||
onboard keyboard.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called jornada720_kbd.
|
||||
|
||||
config KEYBOARD_OMAP
|
||||
tristate "TI OMAP keypad support"
|
||||
depends on (ARCH_OMAP1 || ARCH_OMAP2)
|
||||
@ -253,4 +274,23 @@ config KEYBOARD_GPIO
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gpio-keys.
|
||||
|
||||
config KEYBOARD_MAPLE
|
||||
tristate "Maple bus keyboard"
|
||||
depends on SH_DREAMCAST && MAPLE
|
||||
help
|
||||
Say Y here if you have a Dreamcast console running Linux and have
|
||||
a keyboard attached to its Maple bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called maple_keyb.
|
||||
|
||||
config KEYBOARD_BFIN
|
||||
tristate "Blackfin BF54x keypad support"
|
||||
depends on BF54x
|
||||
help
|
||||
Say Y here if you want to use the BF54x keypad.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bf54x-keys.
|
||||
|
||||
endif
|
||||
|
@ -21,4 +21,7 @@ obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o
|
||||
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
|
||||
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
|
||||
|
||||
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
|
||||
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
|
||||
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
|
||||
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
|
||||
|
382
drivers/input/keyboard/bf54x-keys.c
Normal file
382
drivers/input/keyboard/bf54x-keys.c
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
* File: drivers/input/keyboard/bf54x-keys.c
|
||||
* Based on:
|
||||
* Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
|
||||
*
|
||||
* Created:
|
||||
* Description: keypad driver for Analog Devices Blackfin BF54x Processors
|
||||
*
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2007 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/portmux.h>
|
||||
#include <asm/mach/bf54x_keys.h>
|
||||
|
||||
#define DRV_NAME "bf54x-keys"
|
||||
#define TIME_SCALE 100 /* 100 ns */
|
||||
#define MAX_MULT (0xFF * TIME_SCALE)
|
||||
#define MAX_RC 8 /* Max Row/Col */
|
||||
|
||||
static const u16 per_rows[] = {
|
||||
P_KEY_ROW7,
|
||||
P_KEY_ROW6,
|
||||
P_KEY_ROW5,
|
||||
P_KEY_ROW4,
|
||||
P_KEY_ROW3,
|
||||
P_KEY_ROW2,
|
||||
P_KEY_ROW1,
|
||||
P_KEY_ROW0,
|
||||
0
|
||||
};
|
||||
|
||||
static const u16 per_cols[] = {
|
||||
P_KEY_COL7,
|
||||
P_KEY_COL6,
|
||||
P_KEY_COL5,
|
||||
P_KEY_COL4,
|
||||
P_KEY_COL3,
|
||||
P_KEY_COL2,
|
||||
P_KEY_COL1,
|
||||
P_KEY_COL0,
|
||||
0
|
||||
};
|
||||
|
||||
struct bf54x_kpad {
|
||||
struct input_dev *input;
|
||||
int irq;
|
||||
unsigned short lastkey;
|
||||
unsigned short *keycode;
|
||||
struct timer_list timer;
|
||||
unsigned int keyup_test_jiffies;
|
||||
};
|
||||
|
||||
static inline int bfin_kpad_find_key(struct bf54x_kpad *bf54x_kpad,
|
||||
struct input_dev *input, u16 keyident)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
for (i = 0; i < input->keycodemax; i++)
|
||||
if (bf54x_kpad->keycode[i + input->keycodemax] == keyident)
|
||||
return bf54x_kpad->keycode[i];
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void bfin_keycodecpy(unsigned short *keycode,
|
||||
const unsigned int *pdata_kc,
|
||||
unsigned short keymapsize)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < keymapsize; i++) {
|
||||
keycode[i] = pdata_kc[i] & 0xffff;
|
||||
keycode[i + keymapsize] = pdata_kc[i] >> 16;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 bfin_kpad_get_prescale(u32 timescale)
|
||||
{
|
||||
u32 sclk = get_sclk();
|
||||
|
||||
return ((((sclk / 1000) * timescale) / 1024) - 1);
|
||||
}
|
||||
|
||||
static inline u16 bfin_kpad_get_keypressed(struct bf54x_kpad *bf54x_kpad)
|
||||
{
|
||||
return (bfin_read_KPAD_STAT() & KPAD_PRESSED);
|
||||
}
|
||||
|
||||
static inline void bfin_kpad_clear_irq(void)
|
||||
{
|
||||
bfin_write_KPAD_STAT(0xFFFF);
|
||||
bfin_write_KPAD_ROWCOL(0xFFFF);
|
||||
}
|
||||
|
||||
static void bfin_kpad_timer(unsigned long data)
|
||||
{
|
||||
struct platform_device *pdev = (struct platform_device *) data;
|
||||
struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
|
||||
|
||||
if (bfin_kpad_get_keypressed(bf54x_kpad)) {
|
||||
/* Try again later */
|
||||
mod_timer(&bf54x_kpad->timer,
|
||||
jiffies + bf54x_kpad->keyup_test_jiffies);
|
||||
return;
|
||||
}
|
||||
|
||||
input_report_key(bf54x_kpad->input, bf54x_kpad->lastkey, 0);
|
||||
input_sync(bf54x_kpad->input);
|
||||
|
||||
/* Clear IRQ Status */
|
||||
|
||||
bfin_kpad_clear_irq();
|
||||
enable_irq(bf54x_kpad->irq);
|
||||
}
|
||||
|
||||
static irqreturn_t bfin_kpad_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = dev_id;
|
||||
struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
|
||||
struct input_dev *input = bf54x_kpad->input;
|
||||
int key;
|
||||
u16 rowcol = bfin_read_KPAD_ROWCOL();
|
||||
|
||||
key = bfin_kpad_find_key(bf54x_kpad, input, rowcol);
|
||||
|
||||
input_report_key(input, key, 1);
|
||||
input_sync(input);
|
||||
|
||||
if (bfin_kpad_get_keypressed(bf54x_kpad)) {
|
||||
disable_irq(bf54x_kpad->irq);
|
||||
bf54x_kpad->lastkey = key;
|
||||
mod_timer(&bf54x_kpad->timer,
|
||||
jiffies + bf54x_kpad->keyup_test_jiffies);
|
||||
} else {
|
||||
input_report_key(input, key, 0);
|
||||
input_sync(input);
|
||||
|
||||
bfin_kpad_clear_irq();
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit bfin_kpad_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bf54x_kpad *bf54x_kpad;
|
||||
struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct input_dev *input;
|
||||
int i, error;
|
||||
|
||||
if (!pdata->rows || !pdata->cols || !pdata->keymap) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": No rows, cols or keymap from pdata\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->keymapsize ||
|
||||
pdata->keymapsize > (pdata->rows * pdata->cols)) {
|
||||
printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bf54x_kpad = kzalloc(sizeof(struct bf54x_kpad), GFP_KERNEL);
|
||||
if (!bf54x_kpad)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, bf54x_kpad);
|
||||
|
||||
/* Allocate memory for keymap followed by private LUT */
|
||||
bf54x_kpad->keycode = kmalloc(pdata->keymapsize *
|
||||
sizeof(unsigned short) * 2, GFP_KERNEL);
|
||||
if (!bf54x_kpad->keycode) {
|
||||
error = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!pdata->debounce_time || !pdata->debounce_time > MAX_MULT ||
|
||||
!pdata->coldrive_time || !pdata->coldrive_time > MAX_MULT) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": Invalid Debounce/Columdrive Time from pdata\n");
|
||||
bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */
|
||||
} else {
|
||||
bfin_write_KPAD_MSEL(
|
||||
((pdata->debounce_time / TIME_SCALE)
|
||||
& DBON_SCALE) |
|
||||
(((pdata->coldrive_time / TIME_SCALE) << 8)
|
||||
& COLDRV_SCALE));
|
||||
|
||||
}
|
||||
|
||||
if (!pdata->keyup_test_interval)
|
||||
bf54x_kpad->keyup_test_jiffies = msecs_to_jiffies(50);
|
||||
else
|
||||
bf54x_kpad->keyup_test_jiffies =
|
||||
msecs_to_jiffies(pdata->keyup_test_interval);
|
||||
|
||||
if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows],
|
||||
DRV_NAME)) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": Requesting Peripherals failed\n");
|
||||
error = -EFAULT;
|
||||
goto out0;
|
||||
}
|
||||
|
||||
if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols],
|
||||
DRV_NAME)) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": Requesting Peripherals failed\n");
|
||||
error = -EFAULT;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
bf54x_kpad->irq = platform_get_irq(pdev, 0);
|
||||
if (bf54x_kpad->irq < 0) {
|
||||
error = -ENODEV;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
error = request_irq(bf54x_kpad->irq, bfin_kpad_isr,
|
||||
IRQF_SAMPLE_RANDOM, DRV_NAME, pdev);
|
||||
if (error) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": unable to claim irq %d; error %d\n",
|
||||
bf54x_kpad->irq, error);
|
||||
error = -EBUSY;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
input = input_allocate_device();
|
||||
if (!input) {
|
||||
error = -ENOMEM;
|
||||
goto out3;
|
||||
}
|
||||
|
||||
bf54x_kpad->input = input;
|
||||
|
||||
input->name = pdev->name;
|
||||
input->phys = "bf54x-keys/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
input_set_drvdata(input, bf54x_kpad);
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
input->id.product = 0x0001;
|
||||
input->id.version = 0x0100;
|
||||
|
||||
input->keycodesize = sizeof(unsigned short);
|
||||
input->keycodemax = pdata->keymapsize;
|
||||
input->keycode = bf54x_kpad->keycode;
|
||||
|
||||
bfin_keycodecpy(bf54x_kpad->keycode, pdata->keymap, pdata->keymapsize);
|
||||
|
||||
/* setup input device */
|
||||
__set_bit(EV_KEY, input->evbit);
|
||||
|
||||
if (pdata->repeat)
|
||||
__set_bit(EV_REP, input->evbit);
|
||||
|
||||
for (i = 0; i < input->keycodemax; i++)
|
||||
__set_bit(bf54x_kpad->keycode[i] & KEY_MAX, input->keybit);
|
||||
__clear_bit(KEY_RESERVED, input->keybit);
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": Unable to register input device (%d)\n", error);
|
||||
goto out4;
|
||||
}
|
||||
|
||||
/* Init Keypad Key Up/Release test timer */
|
||||
|
||||
setup_timer(&bf54x_kpad->timer, bfin_kpad_timer, (unsigned long) pdev);
|
||||
|
||||
bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE));
|
||||
|
||||
bfin_write_KPAD_CTL((((pdata->cols - 1) << 13) & KPAD_COLEN) |
|
||||
(((pdata->rows - 1) << 10) & KPAD_ROWEN) |
|
||||
(2 & KPAD_IRQMODE));
|
||||
|
||||
bfin_write_KPAD_CTL(bfin_read_KPAD_CTL() | KPAD_EN);
|
||||
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
out4:
|
||||
input_free_device(input);
|
||||
out3:
|
||||
free_irq(bf54x_kpad->irq, pdev);
|
||||
out2:
|
||||
peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]);
|
||||
out1:
|
||||
peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]);
|
||||
out0:
|
||||
kfree(bf54x_kpad->keycode);
|
||||
out:
|
||||
kfree(bf54x_kpad);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit bfin_kpad_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
|
||||
|
||||
del_timer_sync(&bf54x_kpad->timer);
|
||||
free_irq(bf54x_kpad->irq, pdev);
|
||||
|
||||
input_unregister_device(bf54x_kpad->input);
|
||||
|
||||
peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]);
|
||||
peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]);
|
||||
|
||||
kfree(bf54x_kpad->keycode);
|
||||
kfree(bf54x_kpad);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct platform_driver bfin_kpad_device_driver = {
|
||||
.probe = bfin_kpad_probe,
|
||||
.remove = __devexit_p(bfin_kpad_remove),
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init bfin_kpad_init(void)
|
||||
{
|
||||
return platform_driver_register(&bfin_kpad_device_driver);
|
||||
}
|
||||
|
||||
static void __exit bfin_kpad_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bfin_kpad_device_driver);
|
||||
}
|
||||
|
||||
module_init(bfin_kpad_init);
|
||||
module_exit(bfin_kpad_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("Keypad driver for BF54x Processors");
|
@ -54,6 +54,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct input_dev *input;
|
||||
int i, error;
|
||||
int wakeup = 0;
|
||||
|
||||
input = input_allocate_device();
|
||||
if (!input)
|
||||
@ -77,31 +78,51 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||
int irq = gpio_to_irq(button->gpio);
|
||||
unsigned int type = button->type ?: EV_KEY;
|
||||
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
|
||||
error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
|
||||
button->desc ? button->desc : "gpio_keys",
|
||||
pdev);
|
||||
if (irq < 0) {
|
||||
error = irq;
|
||||
printk(KERN_ERR
|
||||
"gpio-keys: "
|
||||
"Unable to get irq number for GPIO %d,"
|
||||
"error %d\n",
|
||||
button->gpio, error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
error = request_irq(irq, gpio_keys_isr,
|
||||
IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
button->desc ? button->desc : "gpio_keys",
|
||||
pdev);
|
||||
if (error) {
|
||||
printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
|
||||
printk(KERN_ERR
|
||||
"gpio-keys: Unable to claim irq %d; error %d\n",
|
||||
irq, error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (button->wakeup)
|
||||
wakeup = 1;
|
||||
|
||||
input_set_capability(input, type, button->code);
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
printk(KERN_ERR "Unable to register gpio-keys input device\n");
|
||||
printk(KERN_ERR
|
||||
"gpio-keys: Unable to register input device, "
|
||||
"error: %d\n", error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, wakeup);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (i = i - 1; i >= 0; i--)
|
||||
while (--i >= 0)
|
||||
free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_free_device(input);
|
||||
|
||||
return error;
|
||||
@ -113,6 +134,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
|
||||
struct input_dev *input = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
int irq = gpio_to_irq(pdata->buttons[i].gpio);
|
||||
free_irq(irq, pdev);
|
||||
@ -123,9 +146,53 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
||||
int i;
|
||||
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||
if (button->wakeup) {
|
||||
int irq = gpio_to_irq(button->gpio);
|
||||
enable_irq_wake(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_keys_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
||||
int i;
|
||||
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||
if (button->wakeup) {
|
||||
int irq = gpio_to_irq(button->gpio);
|
||||
disable_irq_wake(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define gpio_keys_suspend NULL
|
||||
#define gpio_keys_resume NULL
|
||||
#endif
|
||||
|
||||
struct platform_driver gpio_keys_device_driver = {
|
||||
.probe = gpio_keys_probe,
|
||||
.remove = __devexit_p(gpio_keys_remove),
|
||||
.suspend = gpio_keys_suspend,
|
||||
.resume = gpio_keys_resume,
|
||||
.driver = {
|
||||
.name = "gpio-keys",
|
||||
}
|
||||
|
277
drivers/input/keyboard/jornada680_kbd.c
Normal file
277
drivers/input/keyboard/jornada680_kbd.c
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* drivers/input/keyboard/jornada680_kbd.c
|
||||
*
|
||||
* HP Jornada 620/660/680/690 scan keyboard platform driver
|
||||
* Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
|
||||
*
|
||||
* Based on hp680_keyb.c
|
||||
* Copyright (C) 2006 Paul Mundt
|
||||
* Copyright (C) 2005 Andriy Skulysh
|
||||
* Split from drivers/input/keyboard/hp600_keyb.c
|
||||
* Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
|
||||
* Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
|
||||
*
|
||||
* 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/input.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/delay.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define PCCR 0xa4000104
|
||||
#define PDCR 0xa4000106
|
||||
#define PECR 0xa4000108
|
||||
#define PFCR 0xa400010a
|
||||
#define PCDR 0xa4000124
|
||||
#define PDDR 0xa4000126
|
||||
#define PEDR 0xa4000128
|
||||
#define PFDR 0xa400012a
|
||||
#define PGDR 0xa400012c
|
||||
#define PHDR 0xa400012e
|
||||
#define PJDR 0xa4000130
|
||||
#define PKDR 0xa4000132
|
||||
#define PLDR 0xa4000134
|
||||
|
||||
static const unsigned short jornada_scancodes[] = {
|
||||
/* PTD1 */ KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0, /* 1 -> 8 */
|
||||
KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5, /* 9 -> 16 */
|
||||
/* PTD5 */ KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0, /* 17 -> 24 */
|
||||
KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N, /* 25 -> 32 */
|
||||
/* PTD7 */ KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0, /* 33 -> 40 */
|
||||
0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA, /* 41 -> 48 */
|
||||
/* PTE0 */ 0, 0, 0, 0, KEY_FINANCE, 0, 0, 0, /* 49 -> 56 */
|
||||
KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /* 57 -> 64 */
|
||||
/* PTE1 */ KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/* 65 -> 72 */
|
||||
KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H, /* 73 -> 80 */
|
||||
/* PTE3 */ KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0, /* 81 -> 88 */
|
||||
0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 89 -> 96 */
|
||||
/* PTE6 */ KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0, /* 97 -> 104 */
|
||||
KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R, /* 105 -> 112 */
|
||||
/* PTE7 */ KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0, 0, /* 113 -> 120 */
|
||||
KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6, /* 121 -> 128 */
|
||||
/* **** */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
#define JORNADA_SCAN_SIZE 18
|
||||
|
||||
struct jornadakbd {
|
||||
struct input_polled_dev *poll_dev;
|
||||
unsigned short keymap[ARRAY_SIZE(jornada_scancodes)];
|
||||
unsigned char length;
|
||||
unsigned char old_scan[JORNADA_SCAN_SIZE];
|
||||
unsigned char new_scan[JORNADA_SCAN_SIZE];
|
||||
};
|
||||
|
||||
static void jornada_parse_kbd(struct jornadakbd *jornadakbd)
|
||||
{
|
||||
struct input_dev *input_dev = jornadakbd->poll_dev->input;
|
||||
unsigned short *keymap = jornadakbd->keymap;
|
||||
unsigned int sync_me = 0;
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0; i < JORNADA_SCAN_SIZE; i++) {
|
||||
unsigned char new = jornadakbd->new_scan[i];
|
||||
unsigned char old = jornadakbd->old_scan[i];
|
||||
unsigned int xor = new ^ old;
|
||||
|
||||
if (xor == 0)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
unsigned int bit = 1 << j;
|
||||
if (xor & bit) {
|
||||
unsigned int scancode = (i << 3) + j;
|
||||
input_event(input_dev,
|
||||
EV_MSC, MSC_SCAN, scancode);
|
||||
input_report_key(input_dev,
|
||||
keymap[scancode],
|
||||
!(new & bit));
|
||||
sync_me = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sync_me)
|
||||
input_sync(input_dev);
|
||||
}
|
||||
|
||||
static void jornada_scan_keyb(unsigned char *s)
|
||||
{
|
||||
int i;
|
||||
unsigned short ec_static, dc_static; /* = UINT16_t */
|
||||
unsigned char matrix_switch[] = {
|
||||
0xfd, 0xff, /* PTD1 PD(1) */
|
||||
0xdf, 0xff, /* PTD5 PD(5) */
|
||||
0x7f, 0xff, /* PTD7 PD(7) */
|
||||
0xff, 0xfe, /* PTE0 PE(0) */
|
||||
0xff, 0xfd, /* PTE1 PE(1) */
|
||||
0xff, 0xf7, /* PTE3 PE(3) */
|
||||
0xff, 0xbf, /* PTE6 PE(6) */
|
||||
0xff, 0x7f, /* PTE7 PE(7) */
|
||||
}, *t = matrix_switch;
|
||||
/* PD(x) :
|
||||
1. 0xcc0c & (1~(1 << (2*(x)+1)))))
|
||||
2. (0xf0cf & 0xfffff) */
|
||||
/* PE(x) :
|
||||
1. 0xcc0c & 0xffff
|
||||
2. 0xf0cf & (1~(1 << (2*(x)+1))))) */
|
||||
unsigned short matrix_PDE[] = {
|
||||
0xcc04, 0xf0cf, /* PD(1) */
|
||||
0xc40c, 0xf0cf, /* PD(5) */
|
||||
0x4c0c, 0xf0cf, /* PD(7) */
|
||||
0xcc0c, 0xf0cd, /* PE(0) */
|
||||
0xcc0c, 0xf0c7, /* PE(1) */
|
||||
0xcc0c, 0xf04f, /* PE(3) */
|
||||
0xcc0c, 0xd0cf, /* PE(6) */
|
||||
0xcc0c, 0x70cf, /* PE(7) */
|
||||
}, *y = matrix_PDE;
|
||||
|
||||
/* Save these control reg bits */
|
||||
dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
|
||||
ec_static = (ctrl_inw(PECR) & (~0xf0cf));
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* disable output for all but the one we want to scan */
|
||||
ctrl_outw((dc_static | *y++), PDCR);
|
||||
ctrl_outw((ec_static | *y++), PECR);
|
||||
udelay(5);
|
||||
|
||||
/* Get scanline row */
|
||||
ctrl_outb(*t++, PDDR);
|
||||
ctrl_outb(*t++, PEDR);
|
||||
udelay(50);
|
||||
|
||||
/* Read data */
|
||||
*s++ = ctrl_inb(PCDR);
|
||||
*s++ = ctrl_inb(PFDR);
|
||||
}
|
||||
/* Scan no lines */
|
||||
ctrl_outb(0xff, PDDR);
|
||||
ctrl_outb(0xff, PEDR);
|
||||
|
||||
/* Enable all scanlines */
|
||||
ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
|
||||
ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
|
||||
|
||||
/* Ignore extra keys and events */
|
||||
*s++ = ctrl_inb(PGDR);
|
||||
*s++ = ctrl_inb(PHDR);
|
||||
}
|
||||
|
||||
static void jornadakbd680_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
struct jornadakbd *jornadakbd = dev->private;
|
||||
|
||||
jornada_scan_keyb(jornadakbd->new_scan);
|
||||
jornada_parse_kbd(jornadakbd);
|
||||
memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE);
|
||||
}
|
||||
|
||||
static int __devinit jornada680kbd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct jornadakbd *jornadakbd;
|
||||
struct input_polled_dev *poll_dev;
|
||||
struct input_dev *input_dev;
|
||||
int i, error;
|
||||
|
||||
jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
|
||||
if (!jornadakbd)
|
||||
return -ENOMEM;
|
||||
|
||||
poll_dev = input_allocate_polled_device();
|
||||
if (!poll_dev) {
|
||||
error = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, jornadakbd);
|
||||
|
||||
jornadakbd->poll_dev = poll_dev;
|
||||
|
||||
memcpy(jornadakbd->keymap, jornada_scancodes,
|
||||
sizeof(jornadakbd->keymap));
|
||||
|
||||
poll_dev->private = jornadakbd;
|
||||
poll_dev->poll = jornadakbd680_poll;
|
||||
poll_dev->poll_interval = 50; /* msec */
|
||||
|
||||
input_dev = poll_dev->input;
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
input_dev->name = "HP Jornada 680 keyboard";
|
||||
input_dev->phys = "jornadakbd/input0";
|
||||
input_dev->keycode = jornadakbd->keymap;
|
||||
input_dev->keycodesize = sizeof(unsigned short);
|
||||
input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
if (jornadakbd->keymap[i])
|
||||
__set_bit(jornadakbd->keymap[i], input_dev->keybit);
|
||||
__clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
error = input_register_polled_device(jornadakbd->poll_dev);
|
||||
if (error)
|
||||
goto failed;
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n",
|
||||
error);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_free_polled_device(poll_dev);
|
||||
kfree(jornadakbd);
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
static int __devexit jornada680kbd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_unregister_polled_device(jornadakbd->poll_dev);
|
||||
input_free_polled_device(jornadakbd->poll_dev);
|
||||
kfree(jornadakbd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver jornada680kbd_driver = {
|
||||
.driver = {
|
||||
.name = "jornada680_kbd",
|
||||
},
|
||||
.probe = jornada680kbd_probe,
|
||||
.remove = __devexit_p(jornada680kbd_remove),
|
||||
};
|
||||
|
||||
static int __init jornada680kbd_init(void)
|
||||
{
|
||||
return platform_driver_register(&jornada680kbd_driver);
|
||||
}
|
||||
|
||||
static void __exit jornada680kbd_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&jornada680kbd_driver);
|
||||
}
|
||||
|
||||
module_init(jornada680kbd_init);
|
||||
module_exit(jornada680kbd_exit);
|
||||
|
||||
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
|
||||
MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
|
||||
MODULE_LICENSE("GPLv2");
|
185
drivers/input/keyboard/jornada720_kbd.c
Normal file
185
drivers/input/keyboard/jornada720_kbd.c
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* drivers/input/keyboard/jornada720_kbd.c
|
||||
*
|
||||
* HP Jornada 720 keyboard platform driver
|
||||
*
|
||||
* Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>
|
||||
*
|
||||
* Copyright (C) 2006 jornada 720 kbd driver by
|
||||
Filip Zyzniewsk <Filip.Zyzniewski@tefnet.plX
|
||||
* based on (C) 2004 jornada 720 kbd driver by
|
||||
Alex Lange <chicken@handhelds.org>
|
||||
*
|
||||
* 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/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/arch/jornada720.h>
|
||||
#include <asm/hardware.h>
|
||||
|
||||
MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
|
||||
MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
|
||||
MODULE_LICENSE("GPLv2");
|
||||
|
||||
static unsigned short jornada_std_keymap[128] = { /* ROW */
|
||||
0, KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* #1 */
|
||||
KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, /* -> */
|
||||
0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, /* #2 */
|
||||
KEY_0, KEY_MINUS, KEY_EQUAL,0, 0, 0, /* -> */
|
||||
0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, /* #3 */
|
||||
KEY_P, KEY_BACKSLASH, KEY_BACKSPACE, 0, 0, 0, /* -> */
|
||||
0, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, /* #4 */
|
||||
KEY_SEMICOLON, KEY_LEFTBRACE, KEY_RIGHTBRACE, 0, 0, 0, /* -> */
|
||||
0, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, /* #5 */
|
||||
KEY_DOT, KEY_KPMINUS, KEY_APOSTROPHE, KEY_ENTER, 0, 0,0, /* -> */
|
||||
0, KEY_TAB, 0, KEY_LEFTSHIFT, 0, KEY_APOSTROPHE, 0, 0, 0, 0, /* #6 */
|
||||
KEY_UP, 0, KEY_RIGHTSHIFT, 0, 0, 0,0, 0, 0, 0, 0, KEY_LEFTALT, KEY_GRAVE, /* -> */
|
||||
0, 0, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0,0, KEY_KPASTERISK, /* -> */
|
||||
KEY_LEFTCTRL, 0, KEY_SPACE, 0, 0, 0, KEY_SLASH, KEY_DELETE, 0, 0, /* -> */
|
||||
0, 0, 0, KEY_POWER, /* -> */
|
||||
};
|
||||
|
||||
struct jornadakbd {
|
||||
unsigned short keymap[ARRAY_SIZE(jornada_std_keymap)];
|
||||
struct input_dev *input;
|
||||
};
|
||||
|
||||
static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = dev_id;
|
||||
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
|
||||
struct input_dev *input = jornadakbd->input;
|
||||
u8 count, kbd_data, scan_code;
|
||||
|
||||
/* startup ssp with spinlock */
|
||||
jornada_ssp_start();
|
||||
|
||||
if (jornada_ssp_inout(GETSCANKEYCODE) != TXDUMMY) {
|
||||
printk(KERN_DEBUG
|
||||
"jornada720_kbd: "
|
||||
"GetKeycode command failed with ETIMEDOUT, "
|
||||
"flushed bus\n");
|
||||
} else {
|
||||
/* How many keycodes are waiting for us? */
|
||||
count = jornada_ssp_byte(TXDUMMY);
|
||||
|
||||
/* Lets drag them out one at a time */
|
||||
while (count--) {
|
||||
/* Exchange TxDummy for location (keymap[kbddata]) */
|
||||
kbd_data = jornada_ssp_byte(TXDUMMY);
|
||||
scan_code = kbd_data & 0x7f;
|
||||
|
||||
input_event(input, EV_MSC, MSC_SCAN, scan_code);
|
||||
input_report_key(input, jornadakbd->keymap[scan_code],
|
||||
!(kbd_data & 0x80));
|
||||
input_sync(input);
|
||||
}
|
||||
}
|
||||
|
||||
/* release spinlock and turn off ssp */
|
||||
jornada_ssp_end();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
};
|
||||
|
||||
static int __devinit jornada720_kbd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct jornadakbd *jornadakbd;
|
||||
struct input_dev *input_dev;
|
||||
int i, err;
|
||||
|
||||
jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!jornadakbd || !input_dev) {
|
||||
err = -ENOMEM;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, jornadakbd);
|
||||
|
||||
memcpy(jornadakbd->keymap, jornada_std_keymap,
|
||||
sizeof(jornada_std_keymap));
|
||||
jornadakbd->input = input_dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
input_dev->name = "HP Jornada 720 keyboard";
|
||||
input_dev->phys = "jornadakbd/input0";
|
||||
input_dev->keycode = jornadakbd->keymap;
|
||||
input_dev->keycodesize = sizeof(unsigned short);
|
||||
input_dev->keycodemax = ARRAY_SIZE(jornada_std_keymap);
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(jornadakbd->keymap); i++)
|
||||
__set_bit(jornadakbd->keymap[i], input_dev->keybit);
|
||||
__clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
err = request_irq(IRQ_GPIO0,
|
||||
jornada720_kbd_interrupt,
|
||||
IRQF_DISABLED | IRQF_TRIGGER_FALLING,
|
||||
"jornadakbd", pdev);
|
||||
if (err) {
|
||||
printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
err = input_register_device(jornadakbd->input);
|
||||
if (err)
|
||||
goto fail2;
|
||||
|
||||
return 0;
|
||||
|
||||
fail2: /* IRQ, DEVICE, MEMORY */
|
||||
free_irq(IRQ_GPIO0, pdev);
|
||||
fail1: /* DEVICE, MEMORY */
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_free_device(input_dev);
|
||||
kfree(jornadakbd);
|
||||
return err;
|
||||
};
|
||||
|
||||
static int __devexit jornada720_kbd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(IRQ_GPIO0, pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_unregister_device(jornadakbd->input);
|
||||
kfree(jornadakbd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver jornada720_kbd_driver = {
|
||||
.driver = {
|
||||
.name = "jornada720_kbd",
|
||||
},
|
||||
.probe = jornada720_kbd_probe,
|
||||
.remove = __devexit_p(jornada720_kbd_remove),
|
||||
};
|
||||
|
||||
static int __init jornada720_kbd_init(void)
|
||||
{
|
||||
return platform_driver_register(&jornada720_kbd_driver);
|
||||
}
|
||||
|
||||
static void __exit jornada720_kbd_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&jornada720_kbd_driver);
|
||||
}
|
||||
|
||||
module_init(jornada720_kbd_init);
|
||||
module_exit(jornada720_kbd_exit);
|
252
drivers/input/keyboard/maple_keyb.c
Normal file
252
drivers/input/keyboard/maple_keyb.c
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* SEGA Dreamcast keyboard driver
|
||||
* Based on drivers/usb/usbkbd.c
|
||||
* Copyright YAEGASHI Takeshi, 2001
|
||||
* Porting to 2.6 Copyright Adrian McMenamin, 2007
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/maple.h>
|
||||
#include <asm/mach/maple.h>
|
||||
|
||||
/* Very simple mutex to ensure proper cleanup */
|
||||
static DEFINE_MUTEX(maple_keyb_mutex);
|
||||
|
||||
#define NR_SCANCODES 256
|
||||
|
||||
MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin");
|
||||
MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct dc_kbd {
|
||||
struct input_dev *dev;
|
||||
unsigned short keycode[NR_SCANCODES];
|
||||
unsigned char new[8];
|
||||
unsigned char old[8];
|
||||
};
|
||||
|
||||
static const unsigned short dc_kbd_keycode[NR_SCANCODES] = {
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, KEY_C, KEY_D,
|
||||
KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
|
||||
KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
|
||||
KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2,
|
||||
KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
|
||||
KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE,
|
||||
KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA,
|
||||
KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6,
|
||||
KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ,
|
||||
KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE,
|
||||
KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP,
|
||||
KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2,
|
||||
KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT,
|
||||
KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15,
|
||||
KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
|
||||
KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT,
|
||||
KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE,
|
||||
KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN,
|
||||
KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA,
|
||||
KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE,
|
||||
KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP,
|
||||
KEY_SCREENLOCK, KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED
|
||||
};
|
||||
|
||||
static void dc_scan_kbd(struct dc_kbd *kbd)
|
||||
{
|
||||
struct input_dev *dev = kbd->dev;
|
||||
void *ptr;
|
||||
int code, keycode;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
code = i + 224;
|
||||
keycode = kbd->keycode[code];
|
||||
input_event(dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(dev, keycode, (kbd->new[0] >> i) & 1);
|
||||
}
|
||||
|
||||
for (i = 2; i < 8; i++) {
|
||||
ptr = memchr(kbd->new + 2, kbd->old[i], 6);
|
||||
code = kbd->old[i];
|
||||
if (code > 3 && ptr == NULL) {
|
||||
keycode = kbd->keycode[code];
|
||||
if (keycode) {
|
||||
input_event(dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(dev, keycode, 0);
|
||||
} else
|
||||
printk(KERN_DEBUG "maple_keyb: "
|
||||
"Unknown key (scancode %#x) released.",
|
||||
code);
|
||||
}
|
||||
ptr = memchr(kbd->old + 2, kbd->new[i], 6);
|
||||
code = kbd->new[i];
|
||||
if (code > 3 && ptr) {
|
||||
keycode = kbd->keycode[code];
|
||||
if (keycode) {
|
||||
input_event(dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(dev, keycode, 1);
|
||||
} else
|
||||
printk(KERN_DEBUG "maple_keyb: "
|
||||
"Unknown key (scancode %#x) pressed.",
|
||||
code);
|
||||
}
|
||||
}
|
||||
input_sync(dev);
|
||||
memcpy(kbd->old, kbd->new, 8);
|
||||
}
|
||||
|
||||
static void dc_kbd_callback(struct mapleq *mq)
|
||||
{
|
||||
struct maple_device *mapledev = mq->dev;
|
||||
struct dc_kbd *kbd = mapledev->private_data;
|
||||
unsigned long *buf = mq->recvbuf;
|
||||
|
||||
/*
|
||||
* We should always be getting the lock because the only
|
||||
* time it may be locked if driver is in cleanup phase.
|
||||
*/
|
||||
if (likely(mutex_trylock(&maple_keyb_mutex))) {
|
||||
|
||||
if (buf[1] == mapledev->function) {
|
||||
memcpy(kbd->new, buf + 2, 8);
|
||||
dc_scan_kbd(kbd);
|
||||
}
|
||||
|
||||
mutex_unlock(&maple_keyb_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static int dc_kbd_connect(struct maple_device *mdev)
|
||||
{
|
||||
int i, error;
|
||||
struct dc_kbd *kbd;
|
||||
struct input_dev *dev;
|
||||
|
||||
if (!(mdev->function & MAPLE_FUNC_KEYBOARD))
|
||||
return -EINVAL;
|
||||
|
||||
kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL);
|
||||
dev = input_allocate_device();
|
||||
if (!kbd || !dev) {
|
||||
error = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mdev->private_data = kbd;
|
||||
|
||||
kbd->dev = dev;
|
||||
memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode));
|
||||
|
||||
dev->name = mdev->product_name;
|
||||
dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
dev->keycode = kbd->keycode;
|
||||
dev->keycodesize = sizeof (unsigned short);
|
||||
dev->keycodemax = ARRAY_SIZE(kbd->keycode);
|
||||
dev->id.bustype = BUS_HOST;
|
||||
dev->dev.parent = &mdev->dev;
|
||||
|
||||
for (i = 0; i < NR_SCANCODES; i++)
|
||||
__set_bit(dc_kbd_keycode[i], dev->keybit);
|
||||
__clear_bit(KEY_RESERVED, dev->keybit);
|
||||
|
||||
input_set_capability(dev, EV_MSC, MSC_SCAN);
|
||||
input_set_drvdata(dev, kbd);
|
||||
|
||||
error = input_register_device(dev);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
/* Maple polling is locked to VBLANK - which may be just 50/s */
|
||||
maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
input_free_device(dev);
|
||||
kfree(kbd);
|
||||
mdev->private_data = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
static void dc_kbd_disconnect(struct maple_device *mdev)
|
||||
{
|
||||
struct dc_kbd *kbd;
|
||||
|
||||
mutex_lock(&maple_keyb_mutex);
|
||||
|
||||
kbd = mdev->private_data;
|
||||
mdev->private_data = NULL;
|
||||
input_unregister_device(kbd->dev);
|
||||
kfree(kbd);
|
||||
|
||||
mutex_unlock(&maple_keyb_mutex);
|
||||
}
|
||||
|
||||
/* allow the keyboard to be used */
|
||||
static int probe_maple_kbd(struct device *dev)
|
||||
{
|
||||
struct maple_device *mdev = to_maple_dev(dev);
|
||||
struct maple_driver *mdrv = to_maple_driver(dev->driver);
|
||||
int error;
|
||||
|
||||
error = dc_kbd_connect(mdev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mdev->driver = mdrv;
|
||||
mdev->registered = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct maple_driver dc_kbd_driver = {
|
||||
.function = MAPLE_FUNC_KEYBOARD,
|
||||
.connect = dc_kbd_connect,
|
||||
.disconnect = dc_kbd_disconnect,
|
||||
.drv = {
|
||||
.name = "Dreamcast_keyboard",
|
||||
.probe = probe_maple_kbd,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dc_kbd_init(void)
|
||||
{
|
||||
return maple_driver_register(&dc_kbd_driver.drv);
|
||||
}
|
||||
|
||||
static void __exit dc_kbd_exit(void)
|
||||
{
|
||||
driver_unregister(&dc_kbd_driver.drv);
|
||||
}
|
||||
|
||||
module_init(dc_kbd_init);
|
||||
module_exit(dc_kbd_exit);
|
@ -233,7 +233,7 @@ static void omap_kp_tasklet(unsigned long data)
|
||||
omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
|
||||
kp_cur_group = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t omap_kp_enable_show(struct device *dev,
|
||||
@ -318,7 +318,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
|
||||
keymap = pdata->keymap;
|
||||
|
||||
if (pdata->rep)
|
||||
set_bit(EV_REP, input_dev->evbit);
|
||||
__set_bit(EV_REP, input_dev->evbit);
|
||||
|
||||
if (pdata->delay)
|
||||
omap_kp->delay = pdata->delay;
|
||||
@ -365,9 +365,9 @@ static int __init omap_kp_probe(struct platform_device *pdev)
|
||||
goto err2;
|
||||
|
||||
/* setup input device */
|
||||
set_bit(EV_KEY, input_dev->evbit);
|
||||
__set_bit(EV_KEY, input_dev->evbit);
|
||||
for (i = 0; keymap[i] != 0; i++)
|
||||
set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
|
||||
__set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
|
||||
input_dev->name = "omap-keypad";
|
||||
input_dev->phys = "omap-keypad/input0";
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
@ -377,10 +377,6 @@ static int __init omap_kp_probe(struct platform_device *pdev)
|
||||
input_dev->id.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
|
||||
input_dev->keycode = keymap;
|
||||
input_dev->keycodesize = sizeof(unsigned int);
|
||||
input_dev->keycodemax = pdata->keymapsize;
|
||||
|
||||
ret = input_register_device(omap_kp->input);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Unable to register omap-keypad input device\n");
|
||||
@ -403,15 +399,15 @@ static int __init omap_kp_probe(struct platform_device *pdev)
|
||||
} else {
|
||||
for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
|
||||
if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]),
|
||||
omap_kp_interrupt,
|
||||
omap_kp_interrupt,
|
||||
IRQF_TRIGGER_FALLING,
|
||||
"omap-keypad", omap_kp) < 0)
|
||||
"omap-keypad", omap_kp) < 0)
|
||||
goto err5;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
err5:
|
||||
for (i = irq_idx-1; i >=0; i--)
|
||||
for (i = irq_idx - 1; i >=0; i--)
|
||||
free_irq(row_gpios[i], 0);
|
||||
err4:
|
||||
input_unregister_device(omap_kp->input);
|
||||
@ -440,9 +436,9 @@ static int omap_kp_remove(struct platform_device *pdev)
|
||||
if (cpu_is_omap24xx()) {
|
||||
int i;
|
||||
for (i = 0; i < omap_kp->cols; i++)
|
||||
omap_free_gpio(col_gpios[i]);
|
||||
omap_free_gpio(col_gpios[i]);
|
||||
for (i = 0; i < omap_kp->rows; i++) {
|
||||
omap_free_gpio(row_gpios[i]);
|
||||
omap_free_gpio(row_gpios[i]);
|
||||
free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
|
||||
}
|
||||
} else {
|
||||
|
@ -48,11 +48,13 @@ static const struct alps_model_info alps_model_data[] = {
|
||||
{ { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
|
||||
{ { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
|
||||
{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */
|
||||
{ { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
|
||||
{ { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
|
||||
{ { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
|
||||
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
|
||||
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
|
||||
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
|
||||
{ { 0x73, 0x02, 0x50 }, 0xcf, 0xff, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -502,18 +502,23 @@ static void atp_complete(struct urb* urb)
|
||||
|
||||
/* reset the accumulator on release */
|
||||
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
|
||||
}
|
||||
|
||||
/* Geyser 3 will continue to send packets continually after
|
||||
the first touch unless reinitialised. Do so if it's been
|
||||
idle for a while in order to avoid waking the kernel up
|
||||
several hundred times a second */
|
||||
if (!key && atp_is_geyser_3(dev)) {
|
||||
/* Geyser 3 will continue to send packets continually after
|
||||
the first touch unless reinitialised. Do so if it's been
|
||||
idle for a while in order to avoid waking the kernel up
|
||||
several hundred times a second */
|
||||
|
||||
if (atp_is_geyser_3(dev)) {
|
||||
if (!x && !y && !key) {
|
||||
dev->idlecount++;
|
||||
if (dev->idlecount == 10) {
|
||||
dev->valid = 0;
|
||||
schedule_work(&dev->work);
|
||||
}
|
||||
}
|
||||
else
|
||||
dev->idlecount = 0;
|
||||
}
|
||||
|
||||
input_report_key(dev->input, BTN_LEFT, key);
|
||||
|
@ -96,6 +96,14 @@ static const struct dmi_system_id lifebook_dmi_table[] = {
|
||||
},
|
||||
.callback = lifebook_set_6byte_proto,
|
||||
},
|
||||
{
|
||||
.ident = "CF-72",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"),
|
||||
},
|
||||
.callback = lifebook_set_serio_phys,
|
||||
.driver_data = "isa0060/serio3",
|
||||
},
|
||||
{
|
||||
.ident = "Lifebook B142",
|
||||
.matches = {
|
||||
@ -282,7 +290,7 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
|
||||
int lifebook_init(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *dev1 = psmouse->dev;
|
||||
int max_coord = lifebook_use_6byte_proto ? 1024 : 4096;
|
||||
int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
|
||||
|
||||
if (lifebook_absolute_mode(psmouse))
|
||||
return -1;
|
||||
|
@ -648,9 +648,10 @@ static int psmouse_extensions(struct psmouse *psmouse,
|
||||
|
||||
/*
|
||||
* Reset to defaults in case the device got confused by extended
|
||||
* protocol probes. Note that we do full reset becuase some mice
|
||||
* put themselves to sleep when see PSMOUSE_RESET_DIS.
|
||||
* protocol probes. Note that we follow up with full reset because
|
||||
* some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
|
||||
*/
|
||||
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
|
||||
psmouse_reset(psmouse);
|
||||
|
||||
if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -385,6 +385,8 @@ static int i8042_enable_kbd_port(void)
|
||||
i8042_ctr |= I8042_CTR_KBDINT;
|
||||
|
||||
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
|
||||
i8042_ctr &= ~I8042_CTR_KBDINT;
|
||||
i8042_ctr |= I8042_CTR_KBDDIS;
|
||||
printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n");
|
||||
return -EIO;
|
||||
}
|
||||
@ -402,6 +404,8 @@ static int i8042_enable_aux_port(void)
|
||||
i8042_ctr |= I8042_CTR_AUXINT;
|
||||
|
||||
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
|
||||
i8042_ctr &= ~I8042_CTR_AUXINT;
|
||||
i8042_ctr |= I8042_CTR_AUXDIS;
|
||||
printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -126,6 +126,16 @@ config TOUCHSCREEN_HP600
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called hp680_ts_input.
|
||||
|
||||
config TOUCHSCREEN_HP7XX
|
||||
tristate "HP Jornada 710/720/728 touchscreen"
|
||||
depends on SA1100_JORNADA720_SSP
|
||||
help
|
||||
Say Y here if you have a HP Jornada 710/720/728 and want
|
||||
to support the built-in touchscreen.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called jornada720_ts.
|
||||
|
||||
config TOUCHSCREEN_PENMOUNT
|
||||
tristate "Penmount serial touchscreen"
|
||||
select SERIO
|
||||
@ -191,6 +201,7 @@ config TOUCHSCREEN_USB_COMPOSITE
|
||||
- Gunze AHL61
|
||||
- DMC TSC-10/25
|
||||
- IRTOUCHSYSTEMS/UNITOP
|
||||
- IdealTEK URTC1000
|
||||
|
||||
Have a look at <http://linux.chapter7.ch/touchkit/> for
|
||||
a usage description and the required user-space stuff.
|
||||
@ -238,4 +249,14 @@ config TOUCHSCREEN_USB_IRTOUCH
|
||||
bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
config TOUCHSCREEN_USB_IDEALTEK
|
||||
default y
|
||||
bool "IdealTEK URTC1000 device support" if EMBEDDED
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
config TOUCHSCREEN_USB_GENERAL_TOUCH
|
||||
default y
|
||||
bool "GeneralTouch Touchscreen device support" if EMBEDDED
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
endif
|
||||
|
@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
|
||||
|
182
drivers/input/touchscreen/jornada720_ts.c
Normal file
182
drivers/input/touchscreen/jornada720_ts.c
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* drivers/input/touchscreen/jornada720_ts.c
|
||||
*
|
||||
* Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
|
||||
*
|
||||
* Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
|
||||
* based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* HP Jornada 710/720/729 Touchscreen Driver
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/arch/jornada720.h>
|
||||
|
||||
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
|
||||
MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
|
||||
MODULE_LICENSE("GPLv2");
|
||||
|
||||
struct jornada_ts {
|
||||
struct input_dev *dev;
|
||||
int x_data[4]; /* X sample values */
|
||||
int y_data[4]; /* Y sample values */
|
||||
};
|
||||
|
||||
static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts)
|
||||
{
|
||||
|
||||
/* 3 low word X samples */
|
||||
jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
|
||||
jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
|
||||
jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY);
|
||||
|
||||
/* 3 low word Y samples */
|
||||
jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY);
|
||||
jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY);
|
||||
jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY);
|
||||
|
||||
/* combined x samples bits */
|
||||
jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY);
|
||||
|
||||
/* combined y samples bits */
|
||||
jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY);
|
||||
}
|
||||
|
||||
static int jornada720_ts_average(int coords[4])
|
||||
{
|
||||
int coord, high_bits = coords[3];
|
||||
|
||||
coord = coords[0] | ((high_bits & 0x03) << 8);
|
||||
coord += coords[1] | ((high_bits & 0x0c) << 6);
|
||||
coord += coords[2] | ((high_bits & 0x30) << 4);
|
||||
|
||||
return coord / 3;
|
||||
}
|
||||
|
||||
static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = dev_id;
|
||||
struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
|
||||
struct input_dev *input = jornada_ts->dev;
|
||||
int x, y;
|
||||
|
||||
/* If GPIO_GPIO9 is set to high then report pen up */
|
||||
if (GPLR & GPIO_GPIO(9)) {
|
||||
input_report_key(input, BTN_TOUCH, 0);
|
||||
input_sync(input);
|
||||
} else {
|
||||
jornada_ssp_start();
|
||||
|
||||
/* proper reply to request is always TXDUMMY */
|
||||
if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) {
|
||||
jornada720_ts_collect_data(jornada_ts);
|
||||
|
||||
x = jornada720_ts_average(jornada_ts->x_data);
|
||||
y = jornada720_ts_average(jornada_ts->y_data);
|
||||
|
||||
input_report_key(input, BTN_TOUCH, 1);
|
||||
input_report_abs(input, ABS_X, x);
|
||||
input_report_abs(input, ABS_Y, y);
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
jornada_ssp_end();
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit jornada720_ts_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct jornada_ts *jornada_ts;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
|
||||
jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
|
||||
if (!jornada_ts || !input_dev) {
|
||||
error = -ENOMEM;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, jornada_ts);
|
||||
|
||||
jornada_ts->dev = input_dev;
|
||||
|
||||
input_dev->name = "HP Jornada 7xx Touchscreen";
|
||||
input_dev->phys = "jornadats/input0";
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||
input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
|
||||
|
||||
error = request_irq(IRQ_GPIO9,
|
||||
jornada720_ts_interrupt,
|
||||
IRQF_DISABLED | IRQF_TRIGGER_RISING,
|
||||
"HP7XX Touchscreen driver", pdev);
|
||||
if (error) {
|
||||
printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
error = input_register_device(jornada_ts->dev);
|
||||
if (error)
|
||||
goto fail2;
|
||||
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
free_irq(IRQ_GPIO9, pdev);
|
||||
fail1:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_free_device(input_dev);
|
||||
kfree(jornada_ts);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit jornada720_ts_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(IRQ_GPIO9, pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_unregister_device(jornada_ts->dev);
|
||||
kfree(jornada_ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver jornada720_ts_driver = {
|
||||
.probe = jornada720_ts_probe,
|
||||
.remove = __devexit_p(jornada720_ts_remove),
|
||||
.driver = {
|
||||
.name = "jornada_ts",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init jornada720_ts_init(void)
|
||||
{
|
||||
return platform_driver_register(&jornada720_ts_driver);
|
||||
}
|
||||
|
||||
static void __exit jornada720_ts_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&jornada720_ts_driver);
|
||||
}
|
||||
|
||||
module_init(jornada720_ts_init);
|
||||
module_exit(jornada720_ts_exit);
|
@ -130,8 +130,7 @@ static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel)
|
||||
if (val & UCB_ADC_DAT_VALID)
|
||||
break;
|
||||
/* yield to other processes */
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(1);
|
||||
schedule_timeout_uninterruptible(1);
|
||||
}
|
||||
|
||||
return UCB_ADC_DAT_VALUE(val);
|
||||
|
@ -10,6 +10,7 @@
|
||||
* - Gunze AHL61
|
||||
* - DMC TSC-10/25
|
||||
* - IRTOUCHSYSTEMS/UNITOP
|
||||
* - IdealTEK URTC1000
|
||||
*
|
||||
* Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
|
||||
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
|
||||
@ -92,7 +93,7 @@ struct usbtouch_usb {
|
||||
};
|
||||
|
||||
|
||||
#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO)
|
||||
#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) || defined(CONFIG_TOUCHSCREEN_USB_IDEALTEK)
|
||||
#define MULTI_PACKET
|
||||
#endif
|
||||
|
||||
@ -112,6 +113,8 @@ enum {
|
||||
DEVTYPE_GUNZE,
|
||||
DEVTYPE_DMC_TSC10,
|
||||
DEVTYPE_IRTOUCH,
|
||||
DEVTYPE_IDEALTEK,
|
||||
DEVTYPE_GENERAL_TOUCH,
|
||||
};
|
||||
|
||||
static struct usb_device_id usbtouch_devices[] = {
|
||||
@ -157,6 +160,14 @@ static struct usb_device_id usbtouch_devices[] = {
|
||||
{USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
|
||||
{USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
|
||||
{USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
|
||||
#endif
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
@ -396,7 +407,8 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
|
||||
TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (buf[0] != 0x06 || buf[1] != 0x00)
|
||||
if ((buf[0] != 0x06 || buf[1] != 0x00) &&
|
||||
(buf[0] != 0x15 || buf[1] != 0x01))
|
||||
return -ENODEV;
|
||||
|
||||
/* start sending data */
|
||||
@ -437,6 +449,57 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* IdealTEK URTC1000 Part
|
||||
*/
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
|
||||
static int idealtek_get_pkt_len(unsigned char *buf, int len)
|
||||
{
|
||||
if (buf[0] & 0x80)
|
||||
return 5;
|
||||
if (buf[0] == 0x01)
|
||||
return len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||
{
|
||||
switch (pkt[0] & 0x98) {
|
||||
case 0x88:
|
||||
/* touch data in IdealTEK mode */
|
||||
dev->x = (pkt[1] << 5) | (pkt[2] >> 2);
|
||||
dev->y = (pkt[3] << 5) | (pkt[4] >> 2);
|
||||
dev->touch = (pkt[0] & 0x40) ? 1 : 0;
|
||||
return 1;
|
||||
|
||||
case 0x98:
|
||||
/* touch data in MT emulation mode */
|
||||
dev->x = (pkt[2] << 5) | (pkt[1] >> 2);
|
||||
dev->y = (pkt[4] << 5) | (pkt[3] >> 2);
|
||||
dev->touch = (pkt[0] & 0x40) ? 1 : 0;
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* General Touch Part
|
||||
*/
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
|
||||
static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||
{
|
||||
dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ;
|
||||
dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ;
|
||||
dev->press = pkt[5] & 0xff;
|
||||
dev->touch = pkt[0] & 0x01;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* the different device descriptors
|
||||
*/
|
||||
@ -537,6 +600,32 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
|
||||
.read_data = irtouch_read_data,
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
|
||||
[DEVTYPE_IDEALTEK] = {
|
||||
.min_xc = 0x0,
|
||||
.max_xc = 0x0fff,
|
||||
.min_yc = 0x0,
|
||||
.max_yc = 0x0fff,
|
||||
.rept_size = 8,
|
||||
.flags = USBTOUCH_FLG_BUFFER,
|
||||
.process_pkt = usbtouch_process_multi,
|
||||
.get_pkt_len = idealtek_get_pkt_len,
|
||||
.read_data = idealtek_read_data,
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
|
||||
[DEVTYPE_GENERAL_TOUCH] = {
|
||||
.min_xc = 0x0,
|
||||
.max_xc = 0x0500,
|
||||
.min_yc = 0x0,
|
||||
.max_yc = 0x0500,
|
||||
.rept_size = 7,
|
||||
.read_data = general_touch_read_data,
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,533 +0,0 @@
|
||||
/*
|
||||
* $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
|
||||
*
|
||||
* Copyright (c) 2001 "Crazy" james Simmons
|
||||
*
|
||||
* Compaq touchscreen protocol driver. The protocol emulated by this driver
|
||||
* is obsolete; for new programs use the tslib library which can read directly
|
||||
* from evdev and perform dejittering, variance filtering and calibration -
|
||||
* all in user space, not at kernel level. The meaning of this driver is
|
||||
* to allow usage of newer input drivers with old applications that use the
|
||||
* old /dev/h3600_ts and /dev/h3600_tsraw devices.
|
||||
*
|
||||
* 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
|
||||
* Fixed to actually work, not just output random numbers.
|
||||
* Added support for both h3600_ts and h3600_tsraw protocol
|
||||
* emulation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <jsimmons@infradead.org>.
|
||||
*/
|
||||
|
||||
#define TSDEV_MINOR_BASE 128
|
||||
#define TSDEV_MINORS 32
|
||||
/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
|
||||
#define TSDEV_MINOR_MASK 15
|
||||
#define TSDEV_BUFFER_SIZE 64
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#ifndef CONFIG_INPUT_TSDEV_SCREEN_X
|
||||
#define CONFIG_INPUT_TSDEV_SCREEN_X 240
|
||||
#endif
|
||||
#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
|
||||
#define CONFIG_INPUT_TSDEV_SCREEN_Y 320
|
||||
#endif
|
||||
|
||||
/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
|
||||
* devices. The first one must output X/Y data in 'cooked' format, e.g.
|
||||
* filtered, dejittered and calibrated. Second device just outputs raw
|
||||
* data received from the hardware.
|
||||
*
|
||||
* This driver doesn't support filtering and dejittering; it supports only
|
||||
* calibration. Filtering and dejittering must be done in the low-level
|
||||
* driver, if needed, because it may gain additional benefits from knowing
|
||||
* the low-level details, the nature of noise and so on.
|
||||
*
|
||||
* The driver precomputes a calibration matrix given the initial xres and
|
||||
* yres values (quite innacurate for most touchscreens) that will result
|
||||
* in a more or less expected range of output values. The driver supports
|
||||
* the TS_SET_CAL ioctl, which will replace the calibration matrix with a
|
||||
* new one, supposedly generated from the values taken from the raw device.
|
||||
*/
|
||||
|
||||
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
|
||||
MODULE_DESCRIPTION("Input driver to touchscreen converter");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
|
||||
module_param(xres, uint, 0);
|
||||
MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
|
||||
|
||||
static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
|
||||
module_param(yres, uint, 0);
|
||||
MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)");
|
||||
|
||||
/* From Compaq's Touch Screen Specification version 0.2 (draft) */
|
||||
struct ts_event {
|
||||
short pressure;
|
||||
short x;
|
||||
short y;
|
||||
short millisecs;
|
||||
};
|
||||
|
||||
struct ts_calibration {
|
||||
int xscale;
|
||||
int xtrans;
|
||||
int yscale;
|
||||
int ytrans;
|
||||
int xyswap;
|
||||
};
|
||||
|
||||
struct tsdev {
|
||||
int exist;
|
||||
int open;
|
||||
int minor;
|
||||
char name[8];
|
||||
struct input_handle handle;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head client_list;
|
||||
struct device dev;
|
||||
|
||||
int x, y, pressure;
|
||||
struct ts_calibration cal;
|
||||
};
|
||||
|
||||
struct tsdev_client {
|
||||
struct fasync_struct *fasync;
|
||||
struct list_head node;
|
||||
struct tsdev *tsdev;
|
||||
int head, tail;
|
||||
struct ts_event event[TSDEV_BUFFER_SIZE];
|
||||
int raw;
|
||||
};
|
||||
|
||||
/* The following ioctl codes are defined ONLY for backward compatibility.
|
||||
* Don't use tsdev for new developement; use the tslib library instead.
|
||||
* Touchscreen calibration is a fully userspace task.
|
||||
*/
|
||||
/* Use 'f' as magic number */
|
||||
#define IOC_H3600_TS_MAGIC 'f'
|
||||
#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
|
||||
#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
|
||||
|
||||
static struct tsdev *tsdev_table[TSDEV_MINORS/2];
|
||||
|
||||
static int tsdev_fasync(int fd, struct file *file, int on)
|
||||
{
|
||||
struct tsdev_client *client = file->private_data;
|
||||
int retval;
|
||||
|
||||
retval = fasync_helper(fd, file, on, &client->fasync);
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static int tsdev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int i = iminor(inode) - TSDEV_MINOR_BASE;
|
||||
struct tsdev_client *client;
|
||||
struct tsdev *tsdev;
|
||||
int error;
|
||||
|
||||
printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
|
||||
"for removal.\nSee Documentation/feature-removal-schedule.txt "
|
||||
"for details.\n");
|
||||
|
||||
if (i >= TSDEV_MINORS)
|
||||
return -ENODEV;
|
||||
|
||||
tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
|
||||
if (!tsdev || !tsdev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
get_device(&tsdev->dev);
|
||||
|
||||
client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
|
||||
if (!client) {
|
||||
error = -ENOMEM;
|
||||
goto err_put_tsdev;
|
||||
}
|
||||
|
||||
client->tsdev = tsdev;
|
||||
client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
|
||||
list_add_tail(&client->node, &tsdev->client_list);
|
||||
|
||||
if (!tsdev->open++ && tsdev->exist) {
|
||||
error = input_open_device(&tsdev->handle);
|
||||
if (error)
|
||||
goto err_free_client;
|
||||
}
|
||||
|
||||
file->private_data = client;
|
||||
return 0;
|
||||
|
||||
err_free_client:
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
err_put_tsdev:
|
||||
put_device(&tsdev->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void tsdev_free(struct device *dev)
|
||||
{
|
||||
struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
|
||||
|
||||
tsdev_table[tsdev->minor] = NULL;
|
||||
kfree(tsdev);
|
||||
}
|
||||
|
||||
static int tsdev_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct tsdev_client *client = file->private_data;
|
||||
struct tsdev *tsdev = client->tsdev;
|
||||
|
||||
tsdev_fasync(-1, file, 0);
|
||||
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
|
||||
if (!--tsdev->open && tsdev->exist)
|
||||
input_close_device(&tsdev->handle);
|
||||
|
||||
put_device(&tsdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct tsdev_client *client = file->private_data;
|
||||
struct tsdev *tsdev = client->tsdev;
|
||||
int retval = 0;
|
||||
|
||||
if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(tsdev->wait,
|
||||
client->head != client->tail || !tsdev->exist);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!tsdev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
while (client->head != client->tail &&
|
||||
retval + sizeof (struct ts_event) <= count) {
|
||||
if (copy_to_user (buffer + retval, client->event + client->tail,
|
||||
sizeof (struct ts_event)))
|
||||
return -EFAULT;
|
||||
client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
|
||||
retval += sizeof (struct ts_event);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* No kernel lock - fine */
|
||||
static unsigned int tsdev_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct tsdev_client *client = file->private_data;
|
||||
struct tsdev *tsdev = client->tsdev;
|
||||
|
||||
poll_wait(file, &tsdev->wait, wait);
|
||||
return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
||||
(tsdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
}
|
||||
|
||||
static int tsdev_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct tsdev_client *client = file->private_data;
|
||||
struct tsdev *tsdev = client->tsdev;
|
||||
int retval = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case TS_GET_CAL:
|
||||
if (copy_to_user((void __user *)arg, &tsdev->cal,
|
||||
sizeof (struct ts_calibration)))
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
|
||||
case TS_SET_CAL:
|
||||
if (copy_from_user(&tsdev->cal, (void __user *)arg,
|
||||
sizeof (struct ts_calibration)))
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct file_operations tsdev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = tsdev_open,
|
||||
.release = tsdev_release,
|
||||
.read = tsdev_read,
|
||||
.poll = tsdev_poll,
|
||||
.fasync = tsdev_fasync,
|
||||
.ioctl = tsdev_ioctl,
|
||||
};
|
||||
|
||||
static void tsdev_event(struct input_handle *handle, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
{
|
||||
struct tsdev *tsdev = handle->private;
|
||||
struct tsdev_client *client;
|
||||
struct timeval time;
|
||||
|
||||
switch (type) {
|
||||
case EV_ABS:
|
||||
switch (code) {
|
||||
case ABS_X:
|
||||
tsdev->x = value;
|
||||
break;
|
||||
|
||||
case ABS_Y:
|
||||
tsdev->y = value;
|
||||
break;
|
||||
|
||||
case ABS_PRESSURE:
|
||||
if (value > handle->dev->absmax[ABS_PRESSURE])
|
||||
value = handle->dev->absmax[ABS_PRESSURE];
|
||||
value -= handle->dev->absmin[ABS_PRESSURE];
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
tsdev->pressure = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
switch (code) {
|
||||
case REL_X:
|
||||
tsdev->x += value;
|
||||
if (tsdev->x < 0)
|
||||
tsdev->x = 0;
|
||||
else if (tsdev->x > xres)
|
||||
tsdev->x = xres;
|
||||
break;
|
||||
|
||||
case REL_Y:
|
||||
tsdev->y += value;
|
||||
if (tsdev->y < 0)
|
||||
tsdev->y = 0;
|
||||
else if (tsdev->y > yres)
|
||||
tsdev->y = yres;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_KEY:
|
||||
if (code == BTN_TOUCH || code == BTN_MOUSE) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
tsdev->pressure = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (!tsdev->pressure)
|
||||
tsdev->pressure = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (type != EV_SYN || code != SYN_REPORT)
|
||||
return;
|
||||
|
||||
list_for_each_entry(client, &tsdev->client_list, node) {
|
||||
int x, y, tmp;
|
||||
|
||||
do_gettimeofday(&time);
|
||||
client->event[client->head].millisecs = time.tv_usec / 1000;
|
||||
client->event[client->head].pressure = tsdev->pressure;
|
||||
|
||||
x = tsdev->x;
|
||||
y = tsdev->y;
|
||||
|
||||
/* Calibration */
|
||||
if (!client->raw) {
|
||||
x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
|
||||
y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
|
||||
if (tsdev->cal.xyswap) {
|
||||
tmp = x; x = y; y = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
client->event[client->head].x = x;
|
||||
client->event[client->head].y = y;
|
||||
client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
wake_up_interruptible(&tsdev->wait);
|
||||
}
|
||||
|
||||
static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct tsdev *tsdev;
|
||||
int minor, delta;
|
||||
int error;
|
||||
|
||||
for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
|
||||
if (minor >= TSDEV_MINORS / 2) {
|
||||
printk(KERN_ERR
|
||||
"tsdev: You have way too many touchscreens\n");
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
|
||||
if (!tsdev)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&tsdev->client_list);
|
||||
init_waitqueue_head(&tsdev->wait);
|
||||
|
||||
tsdev->exist = 1;
|
||||
tsdev->minor = minor;
|
||||
tsdev->handle.dev = dev;
|
||||
tsdev->handle.name = tsdev->name;
|
||||
tsdev->handle.handler = handler;
|
||||
tsdev->handle.private = tsdev;
|
||||
snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
|
||||
|
||||
/* Precompute the rough calibration matrix */
|
||||
delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
|
||||
if (delta == 0)
|
||||
delta = 1;
|
||||
tsdev->cal.xscale = (xres << 8) / delta;
|
||||
tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
|
||||
|
||||
delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
|
||||
if (delta == 0)
|
||||
delta = 1;
|
||||
tsdev->cal.yscale = (yres << 8) / delta;
|
||||
tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
|
||||
|
||||
snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id),
|
||||
"ts%d", minor);
|
||||
tsdev->dev.class = &input_class;
|
||||
tsdev->dev.parent = &dev->dev;
|
||||
tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
|
||||
tsdev->dev.release = tsdev_free;
|
||||
device_initialize(&tsdev->dev);
|
||||
|
||||
tsdev_table[minor] = tsdev;
|
||||
|
||||
error = device_add(&tsdev->dev);
|
||||
if (error)
|
||||
goto err_free_tsdev;
|
||||
|
||||
error = input_register_handle(&tsdev->handle);
|
||||
if (error)
|
||||
goto err_delete_tsdev;
|
||||
|
||||
return 0;
|
||||
|
||||
err_delete_tsdev:
|
||||
device_del(&tsdev->dev);
|
||||
err_free_tsdev:
|
||||
put_device(&tsdev->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void tsdev_disconnect(struct input_handle *handle)
|
||||
{
|
||||
struct tsdev *tsdev = handle->private;
|
||||
struct tsdev_client *client;
|
||||
|
||||
input_unregister_handle(handle);
|
||||
device_del(&tsdev->dev);
|
||||
|
||||
tsdev->exist = 0;
|
||||
|
||||
if (tsdev->open) {
|
||||
input_close_device(handle);
|
||||
list_for_each_entry(client, &tsdev->client_list, node)
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||
wake_up_interruptible(&tsdev->wait);
|
||||
}
|
||||
|
||||
put_device(&tsdev->dev);
|
||||
}
|
||||
|
||||
static const struct input_device_id tsdev_ids[] = {
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
|
||||
.keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
|
||||
.relbit = { BIT(REL_X) | BIT(REL_Y) },
|
||||
}, /* A mouse like device, at least one button, two relative axes */
|
||||
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
|
||||
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
|
||||
.absbit = { BIT(ABS_X) | BIT(ABS_Y) },
|
||||
}, /* A tablet like device, at least touch detection, two absolute axes */
|
||||
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
|
||||
.evbit = { BIT(EV_ABS) },
|
||||
.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
|
||||
}, /* A tablet like device with several gradations of pressure */
|
||||
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(input, tsdev_ids);
|
||||
|
||||
static struct input_handler tsdev_handler = {
|
||||
.event = tsdev_event,
|
||||
.connect = tsdev_connect,
|
||||
.disconnect = tsdev_disconnect,
|
||||
.fops = &tsdev_fops,
|
||||
.minor = TSDEV_MINOR_BASE,
|
||||
.name = "tsdev",
|
||||
.id_table = tsdev_ids,
|
||||
};
|
||||
|
||||
static int __init tsdev_init(void)
|
||||
{
|
||||
return input_register_handler(&tsdev_handler);
|
||||
}
|
||||
|
||||
static void __exit tsdev_exit(void)
|
||||
{
|
||||
input_unregister_handler(&tsdev_handler);
|
||||
}
|
||||
|
||||
module_init(tsdev_init);
|
||||
module_exit(tsdev_exit);
|
@ -172,6 +172,7 @@ config INPUT_ADBHID
|
||||
|
||||
config MAC_EMUMOUSEBTN
|
||||
bool "Support for mouse button 2+3 emulation"
|
||||
select INPUT
|
||||
help
|
||||
This provides generic support for emulating the 2nd and 3rd mouse
|
||||
button with keypresses. If you say Y here, the emulation is still
|
||||
|
@ -52,6 +52,11 @@
|
||||
|
||||
MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
|
||||
|
||||
static int restore_capslock_events;
|
||||
module_param(restore_capslock_events, int, 0644);
|
||||
MODULE_PARM_DESC(restore_capslock_events,
|
||||
"Produce keypress events for capslock on both keyup and keydown.");
|
||||
|
||||
#define KEYB_KEYREG 0 /* register # for key up/down data */
|
||||
#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
|
||||
#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
|
||||
@ -217,6 +222,8 @@ struct adbhid {
|
||||
#define FLAG_FN_KEY_PRESSED 0x00000001
|
||||
#define FLAG_POWER_FROM_FN 0x00000002
|
||||
#define FLAG_EMU_FWDEL_DOWN 0x00000004
|
||||
#define FLAG_CAPSLOCK_TRANSLATE 0x00000008
|
||||
#define FLAG_CAPSLOCK_DOWN 0x00000010
|
||||
|
||||
static struct adbhid *adbhid[16];
|
||||
|
||||
@ -272,19 +279,50 @@ adbhid_keyboard_input(unsigned char *data, int nb, int apoll)
|
||||
}
|
||||
|
||||
static void
|
||||
adbhid_input_keycode(int id, int keycode, int repeat)
|
||||
adbhid_input_keycode(int id, int scancode, int repeat)
|
||||
{
|
||||
struct adbhid *ahid = adbhid[id];
|
||||
int up_flag, key;
|
||||
int keycode, up_flag;
|
||||
|
||||
up_flag = (keycode & 0x80);
|
||||
keycode &= 0x7f;
|
||||
keycode = scancode & 0x7f;
|
||||
up_flag = scancode & 0x80;
|
||||
|
||||
if (restore_capslock_events) {
|
||||
if (keycode == ADB_KEY_CAPSLOCK && !up_flag) {
|
||||
/* Key pressed, turning on the CapsLock LED.
|
||||
* The next 0xff will be interpreted as a release. */
|
||||
ahid->flags |= FLAG_CAPSLOCK_TRANSLATE
|
||||
| FLAG_CAPSLOCK_DOWN;
|
||||
} else if (scancode == 0xff) {
|
||||
/* Scancode 0xff usually signifies that the capslock
|
||||
* key was either pressed or released. */
|
||||
if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) {
|
||||
keycode = ADB_KEY_CAPSLOCK;
|
||||
if (ahid->flags & FLAG_CAPSLOCK_DOWN) {
|
||||
/* Key released */
|
||||
up_flag = 1;
|
||||
ahid->flags &= ~FLAG_CAPSLOCK_DOWN;
|
||||
} else {
|
||||
/* Key pressed */
|
||||
up_flag = 0;
|
||||
ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE;
|
||||
}
|
||||
} else {
|
||||
printk(KERN_INFO "Spurious caps lock event "
|
||||
"(scancode 0xff).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (keycode) {
|
||||
case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */
|
||||
input_report_key(ahid->input, KEY_CAPSLOCK, 1);
|
||||
input_report_key(ahid->input, KEY_CAPSLOCK, 0);
|
||||
input_sync(ahid->input);
|
||||
case ADB_KEY_CAPSLOCK:
|
||||
if (!restore_capslock_events) {
|
||||
/* Generate down/up events for CapsLock everytime. */
|
||||
input_report_key(ahid->input, KEY_CAPSLOCK, 1);
|
||||
input_sync(ahid->input);
|
||||
input_report_key(ahid->input, KEY_CAPSLOCK, 0);
|
||||
input_sync(ahid->input);
|
||||
}
|
||||
return;
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */
|
||||
@ -296,7 +334,7 @@ adbhid_input_keycode(int id, int keycode, int repeat)
|
||||
keycode = ADB_KEY_POWER;
|
||||
}
|
||||
break;
|
||||
case ADB_KEY_POWER:
|
||||
case ADB_KEY_POWER:
|
||||
/* Fn + Command will produce a bogus "power" keycode */
|
||||
if (ahid->flags & FLAG_FN_KEY_PRESSED) {
|
||||
keycode = ADB_KEY_CMD;
|
||||
|
17
include/asm-blackfin/mach-bf548/bf54x_keys.h
Normal file
17
include/asm-blackfin/mach-bf548/bf54x_keys.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef _BFIN_KPAD_H
|
||||
#define _BFIN_KPAD_H
|
||||
|
||||
struct bfin_kpad_platform_data {
|
||||
int rows;
|
||||
int cols;
|
||||
const unsigned int *keymap;
|
||||
unsigned short keymapsize;
|
||||
unsigned short repeat;
|
||||
u32 debounce_time; /* in ns */
|
||||
u32 coldrive_time; /* in ns */
|
||||
u32 keyup_test_interval; /* in ms */
|
||||
};
|
||||
|
||||
#define KEYVAL(col, row, val) (((1 << col) << 24) | ((1 << row) << 16) | (val))
|
||||
|
||||
#endif
|
@ -8,6 +8,7 @@ struct gpio_keys_button {
|
||||
int active_low;
|
||||
char *desc;
|
||||
int type; /* input event type (EV_KEY, EV_SW) */
|
||||
int wakeup; /* configure the button as a wake-up source */
|
||||
};
|
||||
|
||||
struct gpio_keys_platform_data {
|
||||
|
@ -856,7 +856,7 @@ struct ff_rumble_effect {
|
||||
* defining effect parameters
|
||||
*
|
||||
* This structure is sent through ioctl from the application to the driver.
|
||||
* To create a new effect aplication should set its @id to -1; the kernel
|
||||
* To create a new effect application should set its @id to -1; the kernel
|
||||
* will return assigned @id which can later be used to update or delete
|
||||
* this effect.
|
||||
*
|
||||
@ -936,9 +936,82 @@ struct ff_effect {
|
||||
#define BIT(x) (1UL<<((x)%BITS_PER_LONG))
|
||||
#define LONG(x) ((x)/BITS_PER_LONG)
|
||||
|
||||
/**
|
||||
* struct input_dev - represents an input device
|
||||
* @name: name of the device
|
||||
* @phys: physical path to the device in the system hierarchy
|
||||
* @uniq: unique identification code for the device (if device has it)
|
||||
* @id: id of the device (struct input_id)
|
||||
* @evbit: bitmap of types of events supported by the device (EV_KEY,
|
||||
* EV_REL, etc.)
|
||||
* @keybit: bitmap of keys/buttons this device has
|
||||
* @relbit: bitmap of relative axes for the device
|
||||
* @absbit: bitmap of absolute axes for the device
|
||||
* @mscbit: bitmap of miscellaneous events supported by the device
|
||||
* @ledbit: bitmap of leds present on the device
|
||||
* @sndbit: bitmap of sound effects supported by the device
|
||||
* @ffbit: bitmap of force feedback effects supported by the device
|
||||
* @swbit: bitmap of switches present on the device
|
||||
* @keycodemax: size of keycode table
|
||||
* @keycodesize: size of elements in keycode table
|
||||
* @keycode: map of scancodes to keycodes for this device
|
||||
* @setkeycode: optional method to alter current keymap, used to implement
|
||||
* sparse keymaps. If not supplied default mechanism will be used
|
||||
* @getkeycode: optional method to retrieve current keymap. If not supplied
|
||||
* default mechanism will be used
|
||||
* @ff: force feedback structure associated with the device if device
|
||||
* supports force feedback effects
|
||||
* @repeat_key: stores key code of the last key pressed; used to implement
|
||||
* software autorepeat
|
||||
* @timer: timer for software autorepeat
|
||||
* @sync: set to 1 when there were no new events since last EV_SYNC
|
||||
* @abs: current values for reports from absolute axes
|
||||
* @rep: current values for autorepeat parameters (delay, rate)
|
||||
* @key: reflects current state of device's keys/buttons
|
||||
* @led: reflects current state of device's LEDs
|
||||
* @snd: reflects current state of sound effects
|
||||
* @sw: reflects current state of device's switches
|
||||
* @absmax: maximum values for events coming from absolute axes
|
||||
* @absmin: minimum values for events coming from absolute axes
|
||||
* @absfuzz: describes noisiness for axes
|
||||
* @absflat: size of the center flat position (used by joydev)
|
||||
* @open: this method is called when the very first user calls
|
||||
* input_open_device(). The driver must prepare the device
|
||||
* to start generating events (start polling thread,
|
||||
* request an IRQ, submit URB, etc.)
|
||||
* @close: this method is called when the very last user calls
|
||||
* input_close_device().
|
||||
* @flush: purges the device. Most commonly used to get rid of force
|
||||
* feedback effects loaded into the device when disconnecting
|
||||
* from it
|
||||
* @event: event handler for events sent _to_ the device, like EV_LED
|
||||
* or EV_SND. The device is expected to carry out the requested
|
||||
* action (turn on a LED, play sound, etc.) The call is protected
|
||||
* by @event_lock and must not sleep
|
||||
* @grab: input handle that currently has the device grabbed (via
|
||||
* EVIOCGRAB ioctl). When a handle grabs a device it becomes sole
|
||||
* recipient for all input events coming from the device
|
||||
* @event_lock: this spinlock is is taken when input core receives
|
||||
* and processes a new event for the device (in input_event()).
|
||||
* Code that accesses and/or modifies parameters of a device
|
||||
* (such as keymap or absmin, absmax, absfuzz, etc.) after device
|
||||
* has been registered with input core must take this lock.
|
||||
* @mutex: serializes calls to open(), close() and flush() methods
|
||||
* @users: stores number of users (input handlers) that opened this
|
||||
* device. It is used by input_open_device() and input_close_device()
|
||||
* to make sure that dev->open() is only called when the first
|
||||
* user opens device and dev->close() is called when the very
|
||||
* last user closes the device
|
||||
* @going_away: marks devices that are in a middle of unregistering and
|
||||
* causes input_open_device*() fail with -ENODEV.
|
||||
* @dev: driver model's view of this device
|
||||
* @h_list: list of input handles associated with the device. When
|
||||
* accessing the list dev->mutex must be held
|
||||
* @node: used to place the device onto input_dev_list
|
||||
*/
|
||||
struct input_dev {
|
||||
|
||||
void *private;
|
||||
void *private; /* do not use */
|
||||
|
||||
const char *name;
|
||||
const char *phys;
|
||||
@ -966,8 +1039,6 @@ struct input_dev {
|
||||
unsigned int repeat_key;
|
||||
struct timer_list timer;
|
||||
|
||||
int state;
|
||||
|
||||
int sync;
|
||||
|
||||
int abs[ABS_MAX + 1];
|
||||
@ -990,8 +1061,11 @@ struct input_dev {
|
||||
|
||||
struct input_handle *grab;
|
||||
|
||||
struct mutex mutex; /* serializes open and close operations */
|
||||
spinlock_t event_lock;
|
||||
struct mutex mutex;
|
||||
|
||||
unsigned int users;
|
||||
int going_away;
|
||||
|
||||
struct device dev;
|
||||
union { /* temporarily so while we switching to struct device */
|
||||
@ -1057,7 +1131,9 @@ struct input_handle;
|
||||
/**
|
||||
* struct input_handler - implements one of interfaces for input devices
|
||||
* @private: driver-specific data
|
||||
* @event: event handler
|
||||
* @event: event handler. This method is being called by input core with
|
||||
* interrupts disabled and dev->event_lock spinlock held and so
|
||||
* it may not sleep
|
||||
* @connect: called when attaching a handler to an input device
|
||||
* @disconnect: disconnects a handler from input device
|
||||
* @start: starts handler for given handle. This function is called by
|
||||
@ -1069,10 +1145,18 @@ struct input_handle;
|
||||
* @name: name of the handler, to be shown in /proc/bus/input/handlers
|
||||
* @id_table: pointer to a table of input_device_ids this driver can
|
||||
* handle
|
||||
* @blacklist: prointer to a table of input_device_ids this driver should
|
||||
* @blacklist: pointer to a table of input_device_ids this driver should
|
||||
* ignore even if they match @id_table
|
||||
* @h_list: list of input handles associated with the handler
|
||||
* @node: for placing the driver onto input_handler_list
|
||||
*
|
||||
* Input handlers attach to input devices and create input handles. There
|
||||
* are likely several handlers attached to any given input device at the
|
||||
* same time. All of them will get their copy of input event generated by
|
||||
* the device.
|
||||
*
|
||||
* Note that input core serializes calls to connect() and disconnect()
|
||||
* methods.
|
||||
*/
|
||||
struct input_handler {
|
||||
|
||||
@ -1094,6 +1178,18 @@ struct input_handler {
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct input_handle - links input device with an input handler
|
||||
* @private: handler-specific data
|
||||
* @open: counter showing whether the handle is 'open', i.e. should deliver
|
||||
* events from its device
|
||||
* @name: name given to the handle by handler that created it
|
||||
* @dev: input device the handle is attached to
|
||||
* @handler: handler that works with the device through this handle
|
||||
* @d_node: used to put the handle on device's list of attached handles
|
||||
* @h_node: used to put the handle on handler's list of handles from which
|
||||
* it gets events
|
||||
*/
|
||||
struct input_handle {
|
||||
|
||||
void *private;
|
||||
@ -1136,10 +1232,10 @@ static inline void input_set_drvdata(struct input_dev *dev, void *data)
|
||||
dev->private = data;
|
||||
}
|
||||
|
||||
int input_register_device(struct input_dev *);
|
||||
int __must_check input_register_device(struct input_dev *);
|
||||
void input_unregister_device(struct input_dev *);
|
||||
|
||||
int input_register_handler(struct input_handler *);
|
||||
int __must_check input_register_handler(struct input_handler *);
|
||||
void input_unregister_handler(struct input_handler *);
|
||||
|
||||
int input_register_handle(struct input_handle *);
|
||||
@ -1216,7 +1312,7 @@ extern struct class input_class;
|
||||
* @max_effects: maximum number of effects supported by device
|
||||
* @effects: pointer to an array of effects currently loaded into device
|
||||
* @effect_owners: array of effect owners; when file handle owning
|
||||
* an effect gets closed the effcet is automatically erased
|
||||
* an effect gets closed the effect is automatically erased
|
||||
*
|
||||
* Every force-feedback device must implement upload() and playback()
|
||||
* methods; erase() is optional. set_gain() and set_autocenter() need
|
||||
|
@ -416,6 +416,7 @@ extern unsigned short plain_map[NR_KEYS];
|
||||
#define K_SHIFTRLOCK K(KT_LOCK,KG_SHIFTR)
|
||||
#define K_CTRLLLOCK K(KT_LOCK,KG_CTRLL)
|
||||
#define K_CTRLRLOCK K(KT_LOCK,KG_CTRLR)
|
||||
#define K_CAPSSHIFTLOCK K(KT_LOCK,KG_CAPSSHIFT)
|
||||
|
||||
#define K_SHIFT_SLOCK K(KT_SLOCK,KG_SHIFT)
|
||||
#define K_CTRL_SLOCK K(KT_SLOCK,KG_CTRL)
|
||||
@ -425,8 +426,9 @@ extern unsigned short plain_map[NR_KEYS];
|
||||
#define K_SHIFTR_SLOCK K(KT_SLOCK,KG_SHIFTR)
|
||||
#define K_CTRLL_SLOCK K(KT_SLOCK,KG_CTRLL)
|
||||
#define K_CTRLR_SLOCK K(KT_SLOCK,KG_CTRLR)
|
||||
#define K_CAPSSHIFT_SLOCK K(KT_SLOCK,KG_CAPSSHIFT)
|
||||
|
||||
#define NR_LOCK 8
|
||||
#define NR_LOCK 9
|
||||
|
||||
#define K_BRL_BLANK K(KT_BRL, 0)
|
||||
#define K_BRL_DOT1 K(KT_BRL, 1)
|
||||
|
Loading…
Reference in New Issue
Block a user