Commit 51847e22 authored by Vojtech Pavlik's avatar Vojtech Pavlik Committed by Linus Torvalds

[PATCH] Input drivers, step #3

This patch updates the input core to the current version, fixing a bunch
of bugs, adding hotplug support and a listing of available input devices
in /proc. The later is very useful for troubleshooting.

Vojtech Pavlik
SuSE Labs
parent 3ba2a466
/*
* $Id: evdev.c,v 1.27 2001/05/28 09:06:44 vojtech Exp $
* $Id: evdev.c,v 1.42 2002/01/02 11:59:56 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Event char devices, giving access to raw input device events.
*
* Sponsored by SuSE
*/
/*
......@@ -24,8 +22,8 @@
* 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 <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#define EVDEV_MINOR_BASE 64
......@@ -42,7 +40,9 @@
struct evdev {
int exist;
int open;
int open_for_write;
int minor;
char name[16];
struct input_handle handle;
wait_queue_head_t wait;
devfs_handle_t devfs;
......@@ -89,6 +89,11 @@ static int evdev_fasync(int fd, struct file *file, int on)
return retval < 0 ? retval : 0;
}
static int evdev_flush(struct file * file)
{
return input_flush_device(&((struct evdev_list*)file->private_data)->evdev->handle, file);
}
static int evdev_release(struct inode * inode, struct file * file)
{
struct evdev_list *list = file->private_data;
......@@ -120,10 +125,16 @@ static int evdev_open(struct inode * inode, struct file * file)
{
struct evdev_list *list;
int i = minor(inode->i_rdev) - EVDEV_MINOR_BASE;
int accept_err;
if (i >= EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
/* Ask the driver if he wishes to accept the open() */
if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) {
return accept_err;
}
if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
return -ENOMEM;
memset(list, 0, sizeof(struct evdev_list));
......@@ -167,7 +178,7 @@ static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_
if (list->head == list->tail) {
add_wait_queue(&list->evdev->wait, &wait);
current->state = TASK_INTERRUPTIBLE;
set_current_state(TASK_INTERRUPTIBLE);
while (list->head == list->tail) {
......@@ -187,7 +198,7 @@ static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_
schedule();
}
current->state = TASK_RUNNING;
set_current_state(TASK_RUNNING);
remove_wait_queue(&list->evdev->wait, &wait);
}
......@@ -219,7 +230,7 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct evdev_list *list = file->private_data;
struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev;
int retval;
int retval, t, u;
switch (cmd) {
......@@ -232,6 +243,40 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval;
if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval;
return 0;
case EVIOCGREP:
if ((retval = put_user(dev->rep[0], ((int *) arg) + 0))) return retval;
if ((retval = put_user(dev->rep[1], ((int *) arg) + 1))) return retval;
return 0;
case EVIOCSREP:
if ((retval = get_user(dev->rep[0], ((int *) arg) + 0))) return retval;
if ((retval = get_user(dev->rep[1], ((int *) arg) + 1))) return retval;
return 0;
case EVIOCGKEYCODE:
if ((retval = get_user(t, ((int *) arg) + 0))) return retval;
if (t < 0 || t > dev->keycodemax) return -EINVAL;
switch (dev->keycodesize) {
case 1: u = *(u8*)(dev->keycode + t); break;
case 2: u = *(u16*)(dev->keycode + t * 2); break;
case 4: u = *(u32*)(dev->keycode + t * 4); break;
default: return -EINVAL;
}
if ((retval = put_user(u, ((int *) arg) + 1))) return retval;
return 0;
case EVIOCSKEYCODE:
if ((retval = get_user(t, ((int *) arg) + 0))) return retval;
if (t < 0 || t > dev->keycodemax) return -EINVAL;
if ((retval = get_user(u, ((int *) arg) + 1))) return retval;
switch (dev->keycodesize) {
case 1: *(u8*)(dev->keycode + t) = u; break;
case 2: *(u16*)(dev->keycode + t * 2) = u; break;
case 4: *(u32*)(dev->keycode + t * 4) = u; break;
default: return -EINVAL;
}
return 0;
case EVIOCSFF:
if (dev->upload_effect) {
......@@ -280,22 +325,55 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
default: return -EINVAL;
}
len = NBITS(len) * sizeof(long);
if (len > _IOC_SIZE(cmd)) {
printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n",
len, _IOC_SIZE(cmd));
len = _IOC_SIZE(cmd);
}
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, bits, len) ? -EFAULT : len;
}
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
int len;
len = NBITS(KEY_MAX) * sizeof(long);
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->key, len) ? -EFAULT : len;
}
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
int len;
len = NBITS(LED_MAX) * sizeof(long);
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->led, len) ? -EFAULT : len;
}
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
int len;
len = NBITS(SND_MAX) * sizeof(long);
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->snd, len) ? -EFAULT : len;
}
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
int len;
if (!dev->name) return 0;
if (!dev->name) return -ENOENT;
len = strlen(dev->name) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len;
}
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
int len;
if (!dev->phys) return -ENOENT;
len = strlen(dev->phys) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->phys, len) ? -EFAULT : len;
}
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
int len;
if (!dev->uniq) return -ENOENT;
len = strlen(dev->uniq) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->uniq, len) ? -EFAULT : len;
}
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
int t = _IOC_NR(cmd) & ABS_MAX;
......@@ -321,9 +399,10 @@ static struct file_operations evdev_fops = {
release: evdev_release,
ioctl: evdev_ioctl,
fasync: evdev_fasync,
flush: evdev_flush
};
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct evdev *evdev;
int minor;
......@@ -342,16 +421,17 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
evdev->minor = minor;
evdev_table[minor] = evdev;
sprintf(evdev->name, "event%d", minor);
evdev->handle.dev = dev;
evdev->handle.name = evdev->name;
evdev->handle.handler = handler;
evdev->handle.private = evdev;
evdev->exist = 1;
evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
// printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number);
evdev->exist = 1;
return &evdev->handle;
}
......@@ -372,12 +452,21 @@ static void evdev_disconnect(struct input_handle *handle)
}
}
static struct input_device_id evdev_ids[] = {
{ driver_info: 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
event: evdev_event,
connect: evdev_connect,
disconnect: evdev_disconnect,
fops: &evdev_fops,
minor: EVDEV_MINOR_BASE,
name: "evdev",
id_table: evdev_ids,
};
static int __init evdev_init(void)
......@@ -394,7 +483,6 @@ static void __exit evdev_exit(void)
module_init(evdev_init);
module_exit(evdev_exit);
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Event character device driver");
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver event char devices");
MODULE_LICENSE("GPL");
/*
* $Id: input.c,v 1.20 2001/05/17 15:50:27 vojtech Exp $
* $Id: input.c,v 1.48 2001/12/26 21:08:33 jsimmons Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* The input layer module itself
*
* Sponsored by SuSE
* The input core
*/
/*
......@@ -24,8 +22,8 @@
* 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 <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/init.h>
......@@ -34,12 +32,16 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/random.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input layer module");
#include <linux/pm.h>
#include <linux/proc_fs.h>
#include <linux/kmod.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input core");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(input_register_device);
EXPORT_SYMBOL(input_unregister_device);
EXPORT_SYMBOL(input_register_handler);
......@@ -48,6 +50,8 @@ EXPORT_SYMBOL(input_register_minor);
EXPORT_SYMBOL(input_unregister_minor);
EXPORT_SYMBOL(input_open_device);
EXPORT_SYMBOL(input_close_device);
EXPORT_SYMBOL(input_accept_process);
EXPORT_SYMBOL(input_flush_device);
EXPORT_SYMBOL(input_event);
#define INPUT_MAJOR 13
......@@ -60,10 +64,22 @@ static devfs_handle_t input_devfs_handle;
static int input_number;
static long input_devices[NBITS(INPUT_DEVICES)];
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_bus_input_dir;
DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
static int input_devices_state;
#endif
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct input_handle *handle = dev->handle;
/*
* Wake up the device if it is sleeping.
*/
if (dev->pm_dev)
pm_access(dev->pm_dev);
/*
* Filter non-events, and bad input values out.
*/
......@@ -71,6 +87,8 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
if (type > EV_MAX || !test_bit(type, dev->evbit))
return;
add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
switch (type) {
case EV_KEY:
......@@ -130,6 +148,8 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
if (code > MSC_MAX || !test_bit(code, dev->mscbit))
return;
if (dev->event) dev->event(dev, type, code, value);
break;
......@@ -185,16 +205,36 @@ static void input_repeat_key(unsigned long data)
mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]);
}
int input_accept_process(struct input_handle *handle, struct file *file)
{
if (handle->dev->accept)
return handle->dev->accept(handle->dev, file);
return 0;
}
int input_open_device(struct input_handle *handle)
{
if (handle->dev->pm_dev)
pm_access(handle->dev->pm_dev);
handle->open++;
if (handle->dev->open)
return handle->dev->open(handle->dev);
return 0;
}
int input_flush_device(struct input_handle* handle, struct file* file)
{
if (handle->dev->flush)
return handle->dev->flush(handle->dev, file);
return 0;
}
void input_close_device(struct input_handle *handle)
{
if (handle->dev->pm_dev)
pm_dev_idle(handle->dev->pm_dev);
if (handle->dev->close)
handle->dev->close(handle->dev);
handle->open--;
......@@ -208,25 +248,197 @@ static void input_link_handle(struct input_handle *handle)
handle->handler->handle = handle;
}
/**
* input_find_and_remove - Find and remove node
*
* @type: data type
* @initval: initial value
* @targ: node to find
* @next: next node in the list
*
* Searches the linked list for the target node @targ. If the node
* is found, it is removed from the list.
*
* If the node is not found, the end of the list will be hit,
* indicating that it wasn't in the list to begin with.
*
* Returns nothing.
*/
#define input_find_and_remove(type, initval, targ, next) \
do { \
type **ptr; \
for (ptr = &initval; *ptr; ptr = &((*ptr)->next)) \
if (*ptr == targ) break; \
if (*ptr) *ptr = (*ptr)->next; \
} while (0)
static void input_unlink_handle(struct input_handle *handle)
{
struct input_handle **handleptr;
input_find_and_remove(struct input_handle, handle->dev->handle, handle, dnext);
input_find_and_remove(struct input_handle, handle->handler->handle, handle, hnext);
}
#define MATCH_BIT(bit, max) \
for (i = 0; i < NBITS(max); i++) \
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
break; \
if (i != NBITS(max)) \
continue;
static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev)
{
int i;
handleptr = &handle->dev->handle;
while (*handleptr && (*handleptr != handle))
handleptr = &((*handleptr)->dnext);
*handleptr = (*handleptr)->dnext;
for (; id->flags || id->driver_info; id++) {
handleptr = &handle->handler->handle;
while (*handleptr && (*handleptr != handle))
handleptr = &((*handleptr)->hnext);
*handleptr = (*handleptr)->hnext;
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->idbus != dev->idbus)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->idvendor != dev->idvendor)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->idproduct != dev->idproduct)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->idversion != dev->idversion)
continue;
MATCH_BIT(evbit, EV_MAX);
MATCH_BIT(keybit, KEY_MAX);
MATCH_BIT(relbit, REL_MAX);
MATCH_BIT(absbit, ABS_MAX);
MATCH_BIT(mscbit, MSC_MAX);
MATCH_BIT(ledbit, LED_MAX);
MATCH_BIT(sndbit, SND_MAX);
MATCH_BIT(ffbit, FF_MAX);
return id;
}
return NULL;
}
/*
* Input hotplugging interface - loading event handlers based on
* device bitfields.
*/
#ifdef CONFIG_HOTPLUG
/*
* Input hotplugging invokes what /proc/sys/kernel/hotplug says
* (normally /sbin/hotplug) when input devices get added or removed.
*
* This invokes a user mode policy agent, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
*/
#define SPRINTF_BIT_A(bit, name, max) \
do { \
envp[i++] = scratch; \
scratch += sprintf(scratch, name); \
for (j = NBITS(max) - 1; j >= 0; j--) \
if (dev->bit[j]) break; \
for (; j >= 0; j--) \
scratch += sprintf(scratch, "%lx ", dev->bit[j]); \
scratch++; \
} while (0)
#define SPRINTF_BIT_A2(bit, name, max, ev) \
do { \
if (test_bit(ev, dev->evbit)) \
SPRINTF_BIT_A(bit, name, max); \
} while (0)
static void input_call_hotplug(char *verb, struct input_dev *dev)
{
char *argv[3], **envp, *buf, *scratch;
int i = 0, j, value;
if (!hotplug_path[0]) {
printk(KERN_ERR "input.c: calling hotplug a hotplug agent defined\n");
return;
}
if (in_interrupt()) {
printk(KERN_ERR "input.c: calling hotplug from interrupt\n");
return;
}
if (!current->fs->root) {
printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n");
return;
}
if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) {
printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n");
return;
}
if (!(buf = kmalloc(1024, GFP_KERNEL))) {
kfree (envp);
printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n");
return;
}
argv[0] = hotplug_path;
argv[1] = "input";
argv[2] = 0;
envp[i++] = "HOME=/";
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
scratch = buf;
envp[i++] = scratch;
scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
envp[i++] = scratch;
scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x",
dev->idbus, dev->idvendor, dev->idproduct, dev->idversion) + 1;
if (dev->name) {
envp[i++] = scratch;
scratch += sprintf(scratch, "NAME=%s", dev->name) + 1;
}
if (dev->phys) {
envp[i++] = scratch;
scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1;
}
SPRINTF_BIT_A(evbit, "EV=", EV_MAX);
SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY);
SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL);
SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS);
SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC);
SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED);
SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND);
SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF);
envp[i++] = 0;
printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n",
argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]);
value = call_usermodehelper(argv [0], argv, envp);
kfree(buf);
kfree(envp);
if (value != 0)
printk(KERN_WARNING "input.c: hotplug returned %d\n", value);
}
#endif
void input_register_device(struct input_dev *dev)
{
struct input_handler *handler = input_handler;
struct input_handle *handle;
struct input_device_id *id;
/*
* Initialize repeat timer to default values.
......@@ -259,18 +471,45 @@ void input_register_device(struct input_dev *dev)
*/
while (handler) {
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
if ((id = input_match_device(handler->id_table, dev)))
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
handler = handler->next;
}
/*
* Notify the hotplug agent.
*/
#ifdef CONFIG_HOTPLUG
input_call_hotplug("add", dev);
#endif
/*
* Notify /proc.
*/
#ifdef CONFIG_PROC_FS
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
void input_unregister_device(struct input_dev *dev)
{
struct input_handle *handle = dev->handle;
struct input_dev **devptr = &input_dev;
struct input_handle *dnext;
if (!dev) return;
/*
* Turn off power management for the device.
*/
if (dev->pm_dev)
pm_unregister(dev->pm_dev);
/*
* Kill any pending repeat timers.
*/
......@@ -289,23 +528,36 @@ void input_unregister_device(struct input_dev *dev)
}
/*
* Remove the device.
* Notify the hotplug agent.
*/
while (*devptr && (*devptr != dev))
devptr = &((*devptr)->next);
*devptr = (*devptr)->next;
#ifdef CONFIG_HOTPLUG
input_call_hotplug("remove", dev);
#endif
/*
* Remove the device.
*/
input_find_and_remove(struct input_dev, input_dev, dev, next);
input_number--;
/*
* Notify /proc.
*/
if (dev->number < INPUT_DEVICES)
clear_bit(dev->number, input_devices);
#ifdef CONFIG_PROC_FS
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
void input_register_handler(struct input_handler *handler)
{
struct input_dev *dev = input_dev;
struct input_handle *handle;
struct input_device_id *id;
if (!handler) return;
/*
* Add minors if needed.
......@@ -326,15 +578,24 @@ void input_register_handler(struct input_handler *handler)
*/
while (dev) {
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
if ((id = input_match_device(handler->id_table, dev)))
if ((handle = handler->connect(handler, dev, id)))
input_link_handle(handle);
dev = dev->next;
}
/*
* Notify /proc.
*/
#ifdef CONFIG_PROC_FS
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
void input_unregister_handler(struct input_handler *handler)
{
struct input_handler **handlerptr = &input_handler;
struct input_handle *handle = handler->handle;
struct input_handle *hnext;
......@@ -352,18 +613,23 @@ void input_unregister_handler(struct input_handler *handler)
/*
* Remove it.
*/
while (*handlerptr && (*handlerptr != handler))
handlerptr = &((*handlerptr)->next);
*handlerptr = (*handlerptr)->next;
input_find_and_remove(struct input_handler, input_handler, handler,
next);
/*
* Remove minors.
*/
if (handler->fops != NULL)
input_table[handler->minor >> 5] = NULL;
/*
* Notify /proc.
*/
#ifdef CONFIG_PROC_FS
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
static int input_open_file(struct inode *inode, struct file *file)
......@@ -415,18 +681,164 @@ void input_unregister_minor(devfs_handle_t handle)
devfs_unregister(handle);
}
/*
* ProcFS interface for the input drivers.
*/
#ifdef CONFIG_PROC_FS
#define SPRINTF_BIT_B(bit, name, max) \
do { \
len += sprintf(buf + len, "B: %s", name); \
for (i = NBITS(max) - 1; i >= 0; i--) \
if (dev->bit[i]) break; \
for (; i >= 0; i--) \
len += sprintf(buf + len, "%lx ", dev->bit[i]); \
len += sprintf(buf + len, "\n"); \
} while (0)
#define SPRINTF_BIT_B2(bit, name, max, ev) \
do { \
if (test_bit(ev, dev->evbit)) \
SPRINTF_BIT_B(bit, name, max); \
} while (0)
static unsigned int input_devices_poll(struct file *file, poll_table *wait)
{
int state = input_devices_state;
poll_wait(file, &input_devices_poll_wait, wait);
if (state != input_devices_state)
return POLLIN | POLLRDNORM;
return 0;
}
static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
{
struct input_dev *dev = input_dev;
struct input_handle *handle;
off_t at = 0;
int i, len, cnt = 0;
while (dev) {
len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",
dev->idbus, dev->idvendor, dev->idproduct, dev->idversion);
len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : "");
len += sprintf(buf + len, "D: Drivers=");
handle = dev->handle;
while (handle) {
len += sprintf(buf + len, "%s ", handle->name);
handle = handle->dnext;
}
len += sprintf(buf + len, "\n");
SPRINTF_BIT_B(evbit, "EV=", EV_MAX);
SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY);
SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL);
SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS);
SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC);
SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED);
SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND);
SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF);
len += sprintf(buf + len, "\n");
at += len;
if (at >= pos) {
if (!*start) {
*start = buf + (pos - (at - len));
cnt = at - pos;
} else cnt += len;
buf += len;
if (cnt >= count)
break;
}
dev = dev->next;
}
if (!dev) *eof = 1;
return (count > cnt) ? cnt : count;
}
static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
{
struct input_handler *handler = input_handler;
off_t at = 0;
int len = 0, cnt = 0;
int i = 0;
while (handler) {
if (handler->fops)
len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n",
i++, handler->name, handler->minor);
else
len = sprintf(buf, "N: Number=%d Name=%s\n",
i++, handler->name);
at += len;
if (at >= pos) {
if (!*start) {
*start = buf + (pos - (at - len));
cnt = at - pos;
} else cnt += len;
buf += len;
if (cnt >= count)
break;
}
handler = handler->next;
}
if (!handler) *eof = 1;
return (count > cnt) ? cnt : count;
}
#endif
static int __init input_init(void)
{
struct proc_dir_entry *entry;
#ifdef CONFIG_PROC_FS
proc_bus_input_dir = proc_mkdir("input", proc_bus);
proc_bus_input_dir->owner = THIS_MODULE;
entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL);
entry->owner = THIS_MODULE;
entry->proc_fops->poll = input_devices_poll;
entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
entry->owner = THIS_MODULE;
#endif
if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
return -EBUSY;
}
input_devfs_handle = devfs_mk_dir(NULL, "input", NULL);
return 0;
}
static void __exit input_exit(void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("handlers", proc_bus_input_dir);
remove_proc_entry("input", proc_bus);
#endif
devfs_unregister(input_devfs_handle);
if (devfs_unregister_chrdev(INPUT_MAJOR, "input"))
printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR);
......
/*
* $Id: joydev.c,v 1.19 2001/01/10 19:49:40 vojtech Exp $
* $Id: joydev.c,v 1.38 2001/12/27 10:37:41 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
* Copyright (c) 1999-2001 Vojtech Pavlik
* Copyright (c) 1999 Colin Van Dyke
*
* Joystick device driver for the input driver suite.
*
* Sponsored by SuSE and Intel
*/
/*
......@@ -25,8 +23,8 @@
* 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 <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <asm/io.h>
......@@ -45,14 +43,22 @@
#include <linux/init.h>
#include <linux/smp_lock.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Joystick device interfaces");
MODULE_SUPPORTED_DEVICE("input/js");
MODULE_LICENSE("GPL");
#define JOYDEV_MINOR_BASE 0
#define JOYDEV_MINORS 32
#define JOYDEV_BUFFER_SIZE 64
#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
struct joydev {
int exist;
int open;
int minor;
char name[16];
struct input_handle handle;
wait_queue_head_t wait;
devfs_handle_t devfs;
......@@ -81,11 +87,6 @@ struct joydev_list {
static struct joydev *joydev_table[JOYDEV_MINORS];
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Joystick device driver");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("input/js");
static int joydev_correct(int value, struct js_corr *corr)
{
switch (corr->type) {
......@@ -133,7 +134,7 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
return;
}
event.time = jiffies * (1000 / HZ);
event.time = MSECS(jiffies);
while (list) {
......@@ -163,7 +164,7 @@ static int joydev_release(struct inode * inode, struct file * file)
{
struct joydev_list *list = file->private_data;
struct joydev_list **listptr;
listptr = &list->joydev->list;
joydev_fasync(-1, file, 0);
......@@ -249,7 +250,7 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) {
add_wait_queue(&list->joydev->wait, &wait);
current->state = TASK_INTERRUPTIBLE;
set_current_state(TASK_INTERRUPTIBLE);
while (list->head == list->tail) {
......@@ -265,7 +266,7 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
schedule();
}
current->state = TASK_RUNNING;
set_current_state(TASK_RUNNING);
remove_wait_queue(&list->joydev->wait, &wait);
}
......@@ -276,7 +277,7 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
struct js_event event;
event.time = jiffies * (1000/HZ);
event.time = MSECS(jiffies);
if (list->startup < joydev->nkey) {
event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
......@@ -360,9 +361,9 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return copy_to_user((struct js_corr *) arg, joydev->corr,
sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
case JSIOCSAXMAP:
if (copy_from_user((__u8 *) arg, joydev->abspam, sizeof(__u8) * ABS_MAX))
if (copy_from_user(joydev->abspam, (__u8 *) arg, sizeof(__u8) * ABS_MAX))
return -EFAULT;
for (i = 0; i < ABS_MAX; i++) {
for (i = 0; i < joydev->nabs; i++) {
if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
joydev->absmap[joydev->abspam[i]] = i;
}
......@@ -371,11 +372,11 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return copy_to_user((__u8 *) arg, joydev->abspam,
sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
case JSIOCSBTNMAP:
if (copy_from_user((__u16 *) arg, joydev->absmap, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
if (copy_from_user(joydev->keypam, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
return -EFAULT;
for (i = 0; i < KEY_MAX - BTN_MISC; i++); {
for (i = 0; i < joydev->nkey; i++); {
if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
joydev->keymap[joydev->abspam[i - BTN_MISC]] = i;
joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
}
return 0;
case JSIOCGBTNMAP:
......@@ -405,15 +406,13 @@ static struct file_operations joydev_fops = {
fasync: joydev_fasync,
};
static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct joydev *joydev;
int i, j, minor;
int i, j, t, minor;
if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
(test_bit(ABS_X, dev->absbit) || test_bit(ABS_Y, dev->absbit)) &&
(test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
|| test_bit(BTN_1, dev->keybit)))) return NULL;
if (test_bit(BTN_TOUCH, dev->keybit))
return NULL;
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
if (minor == JOYDEV_MINORS) {
......@@ -430,12 +429,13 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev->minor = minor;
joydev_table[minor] = joydev;
sprintf(joydev->name, "js%d", minor);
joydev->handle.dev = dev;
joydev->handle.name = joydev->name;
joydev->handle.handler = handler;
joydev->handle.private = joydev;
joydev->exist = 1;
for (i = 0; i < ABS_MAX; i++)
if (test_bit(i, dev->absbit)) {
joydev->absmap[i] = joydev->nabs;
......@@ -467,15 +467,17 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev->corr[i].prec = dev->absfuzz[j];
joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
continue;
joydev->corr[i].coef[2] = (1 << 29) / t;
joydev->corr[i].coef[3] = (1 << 29) / t;
joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
}
joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
// printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number);
joydev->exist = 1;
return &joydev->handle;
}
......@@ -495,12 +497,35 @@ static void joydev_disconnect(struct input_handle *handle)
}
}
static struct input_device_id joydev_ids[] = {
{
flags: INPUT_DEVICE_ID_MATCH_EVBIT,
evbit: { BIT(EV_KEY) | BIT(EV_ABS) },
absbit: { BIT(ABS_X) },
},
{
flags: INPUT_DEVICE_ID_MATCH_EVBIT,
evbit: { BIT(EV_KEY) | BIT(EV_ABS) },
absbit: { BIT(ABS_WHEEL) },
},
{
flags: INPUT_DEVICE_ID_MATCH_EVBIT,
evbit: { BIT(EV_KEY) | BIT(EV_ABS) },
absbit: { BIT(ABS_THROTTLE) },
},
{ }, /* Terminating entry */
};
MODULE_DEVICE_TABLE(input, joydev_ids);
static struct input_handler joydev_handler = {
event: joydev_event,
connect: joydev_connect,
disconnect: joydev_disconnect,
fops: &joydev_fops,
minor: JOYDEV_MINOR_BASE,
name: "joydev",
id_table: joydev_ids,
};
static int __init joydev_init(void)
......
......@@ -641,7 +641,7 @@ static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effec
effect->replay.delay,
effect->trigger.button,
effect->trigger.interval,
effect->u.periodic.direction);
effect->direction);
return err;
}
......@@ -680,7 +680,7 @@ static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effec
effect->replay.delay,
effect->trigger.button,
effect->trigger.interval,
effect->u.constant.direction);
effect->direction);
return err;
}
......@@ -722,7 +722,7 @@ static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* ef
case 0: /* Only one axis, choose orientation */
mod1 = mod_chunk->start;
mod2 = 0xffff;
direction = effect->u.interactive.direction;
direction = effect->direction;
axes = 0x20;
break;
......
/*
* $Id: keybdev.c,v 1.3 2000/05/28 17:31:36 vojtech Exp $
* $Id: keybdev.c,v 1.16 2002/01/09 04:21:41 lethal Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Input driver to keyboard driver binding.
*
* Sponsored by SuSE
* Input core to console keyboard binding.
*/
/*
......@@ -24,8 +22,8 @@
* 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 <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/config.h>
......@@ -37,10 +35,16 @@
#include <linux/module.h>
#include <linux/kbd_kern.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input core to console keyboard binding");
MODULE_LICENSE("GPL");
char keybdev_name[] = "keyboard";
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || \
defined(__mips__) || defined(CONFIG_SPARC64) || defined(CONFIG_SUPERH) || \
defined(CONFIG_PPC) || defined(__mc68000__) || defined(__hppa__) || \
defined(__arm__)
defined(__arm__) || defined(__x86_64__)
static int x86_sysrq_alt = 0;
#ifdef CONFIG_SPARC64
......@@ -48,8 +52,6 @@ static int sparc_l1_a_state = 0;
extern void batten_down_hatches(void);
#endif
static int jp_kbd_109 = 1; /* Yes, .jp is the default. See 51142. */
static unsigned short x86_keycodes[256] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
......@@ -62,7 +64,7 @@ static unsigned short x86_keycodes[256] =
360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269,
118,117,125,374,379,115,112,125,121,123,264,265,266,267,268,269,
271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
......@@ -167,26 +169,38 @@ void keybdev_ledfunc(unsigned int led)
}
}
/* Tell the user who may be running in X and not see the console that we have
panic'ed. This is to distingush panics from "real" lockups.
Could in theory send the panic message as morse, but that is left as an
exercise for the reader. */
void panic_blink(void)
{
static unsigned long last_jiffie;
static char led;
/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is different. */
if (jiffies - last_jiffie > HZ/2) {
led ^= 0x01 | 0x04;
keybdev_ledfunc(led);
last_jiffie = jiffies;
}
}
void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
{
if (type != EV_KEY) return;
if (emulate_raw(code, down))
printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code);
emulate_raw(code, down);
tasklet_schedule(&keyboard_tasklet);
}
static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev)
static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct input_handle *handle;
int i;
if (!test_bit(EV_KEY, dev->evbit))
return NULL;
for (i = KEY_RESERVED; i < BTN_MISC; i++)
if (test_bit(i, dev->keybit)) break;
for (i = KEY_ESC; i < BTN_MISC; i++)
if (test_bit(i, dev->keybit))
break;
if (i == BTN_MISC)
return NULL;
......@@ -196,41 +210,42 @@ static struct input_handle *keybdev_connect(struct input_handler *handler, struc
memset(handle, 0, sizeof(struct input_handle));
handle->dev = dev;
handle->name = keybdev_name;
handle->handler = handler;
input_open_device(handle);
// printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
return handle;
}
static void keybdev_disconnect(struct input_handle *handle)
{
// printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
input_close_device(handle);
kfree(handle);
}
static struct input_device_id keybdev_ids[] = {
{
flags: INPUT_DEVICE_ID_MATCH_EVBIT,
evbit: { BIT(EV_KEY) },
},
{ }, /* Terminating entry */
};
MODULE_DEVICE_TABLE(input, keybdev_ids);
static struct input_handler keybdev_handler = {
event: keybdev_event,
connect: keybdev_connect,
disconnect: keybdev_disconnect,
name: "keybdev",
id_table: keybdev_ids,
};
static int __init keybdev_init(void)
{
input_register_handler(&keybdev_handler);
kbd_ledfunc = keybdev_ledfunc;
if (jp_kbd_109) {
x86_keycodes[0xb5] = 0x73; /* backslash, underscore */
x86_keycodes[0xb6] = 0x70;
x86_keycodes[0xb7] = 0x7d; /* Yen, pipe */
x86_keycodes[0xb8] = 0x79;
x86_keycodes[0xb9] = 0x7b;
}
return 0;
}
......@@ -243,7 +258,3 @@ static void __exit keybdev_exit(void)
module_init(keybdev_init);
module_exit(keybdev_exit);
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input driver to keyboard driver binding");
MODULE_PARM(jp_kbd_109, "i");
MODULE_LICENSE("GPL");
/*
* $Id: mousedev.c,v 1.24 2000/11/15 10:57:45 vojtech Exp $
* $Id: mousedev.c,v 1.38 2001/12/26 21:08:33 jsimmons Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Input driver to ImExPS/2 device driver module.
*
* Sponsored by SuSE
* Input driver to ExplorerPS/2 device driver module.
*/
/*
......@@ -24,8 +22,8 @@
* 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 <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#define MOUSEDEV_MINOR_BASE 32
......@@ -41,6 +39,10 @@
#include <linux/smp_lock.h>
#include <linux/random.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
MODULE_LICENSE("GPL");
#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
#endif
......@@ -52,6 +54,7 @@ struct mousedev {
int exist;
int open;
int minor;
char name[16];
wait_queue_head_t wait;
struct mousedev_list *list;
struct input_handle handle;
......@@ -89,8 +92,6 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
struct mousedev_list *list;
int index, size;
add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
while (*mousedev) {
list = (*mousedev)->list;
while (list) {
......@@ -101,13 +102,23 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
switch (code) {
case ABS_X:
size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
list->dx += (value * xres - list->oldx) / size;
list->oldx += list->dx * size;
if (size != 0) {
list->dx += (value * xres - list->oldx) / size;
list->oldx += list->dx * size;
} else {
list->dx += value - list->oldx;
list->oldx += list->dx;
}
break;
case ABS_Y:
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
list->dy -= (value * yres - list->oldy) / size;
list->oldy -= list->dy * size;
if (size != 0) {
list->dy -= (value * yres - list->oldy) / size;
list->oldy -= list->dy * size;
} else {
list->dy -= value - list->oldy;
list->oldy -= list->dy;
}
break;
}
break;
......@@ -169,7 +180,7 @@ static int mousedev_release(struct inode * inode, struct file * file)
{
struct mousedev_list *list = file->private_data;
struct mousedev_list **listptr;
listptr = &list->mousedev->list;
mousedev_fasync(-1, file, 0);
......@@ -344,7 +355,7 @@ static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, lo
if (!list->ready && !list->buffer) {
add_wait_queue(&list->mousedev->wait, &wait);
current->state = TASK_INTERRUPTIBLE;
set_current_state(TASK_INTERRUPTIBLE);
while (!list->ready) {
......@@ -360,7 +371,7 @@ static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, lo
schedule();
}
current->state = TASK_RUNNING;
set_current_state(TASK_RUNNING);
remove_wait_queue(&list->mousedev->wait, &wait);
}
......@@ -401,19 +412,11 @@ struct file_operations mousedev_fops = {
fasync: mousedev_fasync,
};
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev)
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct mousedev *mousedev;
int minor = 0;
if (!test_bit(EV_KEY, dev->evbit) ||
(!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
return NULL;
if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
(!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
return NULL;
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
......@@ -425,11 +428,12 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
memset(mousedev, 0, sizeof(struct mousedev));
init_waitqueue_head(&mousedev->wait);
mousedev->exist = 1;
mousedev->minor = minor;
mousedev_table[minor] = mousedev;
sprintf(mousedev->name, "mouse%d", minor);
mousedev->handle.dev = dev;
mousedev->handle.name = mousedev->name;
mousedev->handle.handler = handler;
mousedev->handle.private = mousedev;
......@@ -438,7 +442,7 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
if (mousedev_mix.open)
input_open_device(&mousedev->handle);
// printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
mousedev->exist = 1;
return &mousedev->handle;
}
......@@ -459,6 +463,26 @@ static void mousedev_disconnect(struct input_handle *handle)
kfree(mousedev);
}
}
static struct input_device_id mousedev_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 */
{ }, /* Terminating entry */
};
MODULE_DEVICE_TABLE(input, mousedev_ids);
static struct input_handler mousedev_handler = {
event: mousedev_event,
......@@ -466,6 +490,8 @@ static struct input_handler mousedev_handler = {
disconnect: mousedev_disconnect,
fops: &mousedev_fops,
minor: MOUSEDEV_MINOR_BASE,
name: "mousedev",
id_table: mousedev_ids,
};
static int __init mousedev_init(void)
......@@ -493,10 +519,6 @@ static void __exit mousedev_exit(void)
module_init(mousedev_init);
module_exit(mousedev_exit);
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver");
MODULE_LICENSE("GPL");
MODULE_PARM(xres, "i");
MODULE_PARM_DESC(xres, "Horizontal screen resolution");
MODULE_PARM(yres, "i");
......
......@@ -2,11 +2,9 @@
#define _GAMEPORT_H
/*
* $Id: gameport.h,v 1.11 2001/04/26 10:24:46 vojtech Exp $
* $Id: gameport.h,v 1.20 2002/01/03 08:55:05 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
*
* Sponsored by SuSE
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
......@@ -26,21 +24,27 @@
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/sched.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/input.h>
struct gameport;
struct gameport {
void *private;
void *private; /* Private pointer for joystick drivers */
void *driver; /* Private pointer for gameport drivers */
char *name;
char *phys;
int number;
unsigned short idbus;
unsigned short idvendor;
unsigned short idproduct;
unsigned short idversion;
int io;
int speed;
int fuzz;
......@@ -59,6 +63,7 @@ struct gameport {
struct gameport_dev {
void *private;
char *name;
void (*connect)(struct gameport *, struct gameport_dev *dev);
void (*disconnect)(struct gameport *);
......@@ -74,8 +79,8 @@ void gameport_rescan(struct gameport *gameport);
void gameport_register_port(struct gameport *gameport);
void gameport_unregister_port(struct gameport *gameport);
#else
static void __inline__ gameport_register_port(struct gameport *gameport) { return; }
static void __inline__ gameport_unregister_port(struct gameport *gameport) { return; }
void __inline__ gameport_register_port(struct gameport *gameport) { return; }
void __inline__ gameport_unregister_port(struct gameport *gameport) { return; }
#endif
void gameport_register_device(struct gameport_dev *dev);
......@@ -94,6 +99,7 @@ void gameport_unregister_device(struct gameport_dev *dev);
#define GAMEPORT_ID_VENDOR_MICROSOFT 0x0007
#define GAMEPORT_ID_VENDOR_THRUSTMASTER 0x0008
#define GAMEPORT_ID_VENDOR_GRAVIS 0x0009
#define GAMEPORT_ID_VENDOR_GUILLEMOT 0x000a
static __inline__ void gameport_trigger(struct gameport *gameport)
{
......@@ -134,7 +140,7 @@ static __inline__ int gameport_time(struct gameport *gameport, int time)
static __inline__ void wait_ms(unsigned int ms)
{
current->state = TASK_UNINTERRUPTIBLE;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1 + ms * HZ / 1000);
}
......
......@@ -2,11 +2,9 @@
#define _INPUT_H
/*
* $Id: input.h,v 1.34 2001/05/28 09:06:44 vojtech Exp $
* $Id: input.h,v 1.57 2002/01/02 11:59:56 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
*
* Sponsored by SuSE
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
......@@ -17,7 +15,7 @@
*
* 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
* 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
......@@ -25,8 +23,8 @@
* 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 <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#ifdef __KERNEL__
......@@ -64,17 +62,20 @@ struct input_event {
#define EVIOCSREP _IOW('E', 0x03, int[2]) /* get repeat settings */
#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
#define EVIOCGKEY _IOR('E', 0x05, int[2]) /* get key value */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGBUS _IOR('E', 0x07, short[4]) /* get bus address */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, int[5]) /* get abs value/limits */
#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCSGAIN _IOW('E', 0x82, unsigned short) /* Set overall gain */
#define EVIOCSAUTOCENTER _IOW('E', 0x83, unsigned short) /* Enable or disable auto-centering */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
/*
......@@ -90,6 +91,8 @@ struct input_event {
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
/*
......@@ -304,8 +307,23 @@ struct input_event {
#define KEY_PROG4 203
#define KEY_SUSPEND 205
#define KEY_CLOSE 206
#define KEY_UNKNOWN 220
#define KEY_PLAY 207
#define KEY_FASTFORWARD 208
#define KEY_BASSBOOST 209
#define KEY_PRINT 210
#define KEY_HP 211
#define KEY_CAMERA 212
#define KEY_SOUND 213
#define KEY_QUESTION 214
#define KEY_EMAIL 215
#define KEY_CHAT 216
#define KEY_SEARCH 217
#define KEY_CONNECT 218
#define KEY_FINANCE 219
#define KEY_SPORT 220
#define KEY_SHOP 221
#define KEY_UNKNOWN 240
#define BTN_MISC 0x100
#define BTN_0 0x100
......@@ -415,14 +433,16 @@ struct input_event {
#define ABS_DISTANCE 0x19
#define ABS_TILT_X 0x1a
#define ABS_TILT_Y 0x1b
#define ABS_MISC 0x1c
#define ABS_MAX 0x1f
#define ABS_VOLUME 0x20
#define ABS_MISC 0x28
#define ABS_MAX 0x3f
/*
* Misc events
*/
#define MSC_SERIAL 0x00
#define MSC_PULSELED 0x01
#define MSC_MAX 0x07
/*
......@@ -468,6 +488,7 @@ struct input_event {
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_ISA 0x10
#define BUS_I8042 0x11
......@@ -479,33 +500,43 @@ struct input_event {
#define BUS_ADB 0x17
#define BUS_I2C 0x18
/*
* Values describing the status of an effect
*/
#define FF_STATUS_STOPPED 0x00
#define FF_STATUS_PLAYING 0x01
#define FF_STATUS_MAX 0x01
/*
* Structures used in ioctls to upload effects to a device
* The first structures are not passed directly by using ioctls.
* They are sub-structures of the actually sent structure (called ff_effect)
*
* Ranges:
* 0 <= __u16 <= 65535
* -32767 <= __s16 <= +32767 ! Not -32768 for lower bound !
*/
struct ff_replay {
__u16 length; /* Duration of an effect */
__u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */
__u16 delay; /* Time to wait before to start playing an effect */
};
struct ff_trigger {
__u16 button; /* Number of button triggering an effect */
__u16 interval; /* Time to wait before an effect can be re-triggered */
__u16 interval; /* Time to wait before an effect can be re-triggered (ms) */
};
struct ff_shape {
__u16 attack_length; /* Duration of attack */
__s16 attack_level; /* Level at beginning of attack */
__u16 fade_length; /* Duration of fade */
__s16 fade_level; /* Level at end of fade */
__u16 attack_length; /* Duration of attack (ms) */
__u16 attack_level; /* Level at beginning of attack */
__u16 fade_length; /* Duration of fade (ms) */
__u16 fade_level; /* Level at end of fade */
};
/* FF_CONSTANT */
struct ff_constant_effect {
__s16 level; /* Strength of effect */
__u16 direction; /* Direction of effect (see periodic effects) */
__s16 level; /* Strength of effect. Negative values are OK */
struct ff_shape shape;
};
......@@ -514,12 +545,13 @@ struct ff_interactive_effect {
/* Axis along which effect must be created. If null, the field named direction
* is used
* It is a bit array (ie to enable axes X and Y, use BIT(ABS_X) | BIT(ABS_Y)
* It overrides the value of ff_effect::direction, which is used only if
* axis == 0
*/
__u16 axis;
__u16 direction;
__s16 right_saturation; /* Max level when joystick is on the right */
__s16 left_saturation; /* Max level when joystick in on the left */
__u16 right_saturation; /* Max level when joystick is on the right */
__u16 left_saturation; /* Max level when joystick in on the left */
__s16 right_coeff; /* Indicates how fast the force grows when the
joystick moves to the right */
......@@ -533,12 +565,10 @@ struct ff_interactive_effect {
/* FF_PERIODIC */
struct ff_periodic_effect {
__u16 waveform; /* Kind of wave (sine, square...) */
__u16 period;
__u16 period; /* in ms */
__s16 magnitude; /* Peak value */
__s16 offset; /* Mean value of wave (roughly) */
__u16 phase; /* 'Horizontal' shift */
__u16 direction; /* Direction. 0 deg -> 0x0000
90 deg -> 0x4000 */
struct ff_shape shape;
};
......@@ -549,10 +579,17 @@ struct ff_periodic_effect {
struct ff_effect {
__u16 type;
/* Following field denotes the unique id assigned to an effect.
* It is set by the driver.
* If user sets if to -1, a new effect is created, and its id is returned in the same field
* Else, the user sets it to the effect id it wants to update.
*/
__s16 id;
__u16 direction; /* Direction. 0 deg -> 0x0000 (down)
90 deg -> 0x4000 (left)
180 deg -> 0x8000 (up)
270 deg -> 0xC000 (right)
*/
struct ff_trigger trigger;
struct ff_replay replay;
......@@ -564,7 +601,7 @@ struct ff_effect {
};
/*
* Buttons that can trigger effects. Use for example FF_BTN(BTN_TRIGGER) to
* Buttons that can trigger effects. Use for example FF_BTN(BTN_TRIGGER) to
* access the bitmap.
*/
......@@ -625,8 +662,11 @@ struct input_dev {
void *private;
int number;
char *name;
char *phys;
char *uniq;
int number;
unsigned short idbus;
unsigned short idvendor;
unsigned short idproduct;
......@@ -649,6 +689,9 @@ struct input_dev {
unsigned int repeat_key;
struct timer_list timer;
struct pm_dev *pm_dev;
int state;
int abs[ABS_MAX + 1];
int rep[REP_MAX + 1];
......@@ -661,8 +704,12 @@ struct input_dev {
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
int only_one_writer;
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*accept)(struct input_dev *dev, struct file *file);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
int (*erase_effect)(struct input_dev *dev, int effect_id);
......@@ -671,16 +718,63 @@ struct input_dev {
struct input_dev *next;
};
/*
* Structure for hotplug & device<->driver matching.
*/
#define INPUT_DEVICE_ID_MATCH_BUS 1
#define INPUT_DEVICE_ID_MATCH_VENDOR 2
#define INPUT_DEVICE_ID_MATCH_PRODUCT 4
#define INPUT_DEVICE_ID_MATCH_VERSION 8
#define INPUT_DEVICE_ID_MATCH_EVBIT 0x010
#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x020
#define INPUT_DEVICE_ID_MATCH_RELBIT 0x040
#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x080
#define INPUT_DEVICE_ID_MATCH_MSCIT 0x100
#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200
#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400
#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800
#define INPUT_DEVICE_ID_MATCH_DEVICE\
(INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT)
#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\
(INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION)
struct input_device_id {
unsigned long flags;
unsigned short idbus;
unsigned short idvendor;
unsigned short idproduct;
unsigned short idversion;
unsigned long evbit[NBITS(EV_MAX)];
unsigned long keybit[NBITS(KEY_MAX)];
unsigned long relbit[NBITS(REL_MAX)];
unsigned long absbit[NBITS(ABS_MAX)];
unsigned long mscbit[NBITS(MSC_MAX)];
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
unsigned long driver_info;
};
struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev);
struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);
void (*disconnect)(struct input_handle *handle);
struct file_operations *fops;
int minor;
char *name;
struct input_device_id *id_table;
struct input_handle *handle;
struct input_handler *next;
......@@ -691,6 +785,7 @@ struct input_handle {
void *private;
int open;
char *name;
struct input_dev *dev;
struct input_handler *handler;
......@@ -708,6 +803,9 @@ void input_unregister_handler(struct input_handler *);
int input_open_device(struct input_handle *);
void input_close_device(struct input_handle *);
int input_accept_process(struct input_handle *handle, struct file *file);
int input_flush_device(struct input_handle* handle, struct file* file);
devfs_handle_t input_register_minor(char *name, int minor, int minor_base);
void input_unregister_minor(devfs_handle_t handle);
......@@ -716,6 +814,8 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c))
#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c)
#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c)
#define input_report_ff(a,b,c) input_event(a, EV_FF, b, c)
#define input_report_ff_status(a,b,c) input_event(a, EV_FF_STATUS, b, c)
#endif
#endif
......@@ -2,31 +2,29 @@
#define _SERIO_H
/*
* $Id: serio.h,v 1.11 2001/05/29 02:58:50 jsimmons Exp $
* $Id: serio.h,v 1.21 2001/12/19 05:15:21 skids Exp $
*
* Copyright (C) 1999 Vojtech Pavlik
*
* Sponsored by SuSE
* Copyright (C) 1999-2001 Vojtech Pavlik
*/
/*
* 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
* 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 <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
/*
......@@ -42,23 +40,31 @@ struct serio {
void *private;
void *driver;
char *name;
char *phys;
int number;
unsigned short idbus;
unsigned short idvendor;
unsigned short idproduct;
unsigned short idversion;
unsigned long type;
int number;
int (*write)(struct serio *, unsigned char);
int (*open)(struct serio *);
void (*close)(struct serio *);
struct serio_dev *dev;
struct serio *next;
};
struct serio_dev {
void *private;
char *name;
void (*write_wakeup)(struct serio *);
void (*interrupt)(struct serio *, unsigned char, unsigned int);
void (*connect)(struct serio *, struct serio_dev *dev);
void (*disconnect)(struct serio *);
......@@ -80,6 +86,13 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data)
return serio->write(serio, data);
}
static __inline__ void serio_dev_write_wakeup(struct serio *serio)
{
if (serio->dev && serio->dev->write_wakeup) {
serio->dev->write_wakeup(serio);
}
}
#define SERIO_TIMEOUT 1
#define SERIO_PARITY 2
......@@ -87,6 +100,7 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data)
#define SERIO_XT 0x00000000UL
#define SERIO_8042 0x01000000UL
#define SERIO_RS232 0x02000000UL
#define SERIO_HIL_MLC 0x03000000UL
#define SERIO_PROTO 0xFFUL
#define SERIO_MSC 0x01
......@@ -108,6 +122,9 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data)
#define SERIO_STOWAWAY 0x20
#define SERIO_H3600 0x21
#define SERIO_PS2SER 0x22
#define SERIO_TWIDKBD 0x23
#define SERIO_TWIDJOY 0x24
#define SERIO_HIL 0x25
#define SERIO_ID 0xff00UL
#define SERIO_EXTRA 0xff0000UL
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment