/*
- * $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
*/
/*
* 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
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;
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;
{
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));
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) {
schedule();
}
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&list->evdev->wait, &wait);
}
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) {
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) {
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;
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;
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;
}
}
}
+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)
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
*/
/*
* 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>
#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);
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
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.
*/
if (type > EV_MAX || !test_bit(type, dev->evbit))
return;
+ add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
+
switch (type) {
case EV_KEY:
if (code > MSC_MAX || !test_bit(code, dev->mscbit))
return;
+
+ if (dev->event) dev->event(dev, type, code, value);
break;
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--;
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.
*/
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.
*/
}
/*
- * 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.
*/
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;
/*
* 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)
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
*/
/*
* 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>
#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;
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) {
return;
}
- event.time = jiffies * (1000 / HZ);
+ event.time = MSECS(jiffies);
while (list) {
{
struct joydev_list *list = file->private_data;
struct joydev_list **listptr;
-
+
listptr = &list->joydev->list;
joydev_fasync(-1, file, 0);
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) {
schedule();
}
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&list->joydev->wait, &wait);
}
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;
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;
}
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:
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) {
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;
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;
}
}
}
+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)
effect->replay.delay,
effect->trigger.button,
effect->trigger.interval,
- effect->u.periodic.direction);
+ effect->direction);
return err;
}
effect->replay.delay,
effect->trigger.button,
effect->trigger.interval,
- effect->u.constant.direction);
+ effect->direction);
return err;
}
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.
*/
/*
* 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>
#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
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,
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 };
}
}
+/* 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;
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;
}
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.
*/
/*
* 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
#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
int exist;
int open;
int minor;
+ char name[16];
wait_queue_head_t wait;
struct mousedev_list *list;
struct input_handle handle;
struct mousedev_list *list;
int index, size;
- add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
-
while (*mousedev) {
list = (*mousedev)->list;
while (list) {
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;
{
struct mousedev_list *list = file->private_data;
struct mousedev_list **listptr;
-
+
listptr = &list->mousedev->list;
mousedev_fasync(-1, file, 0);
if (!list->ready && !list->buffer) {
add_wait_queue(&list->mousedev->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
while (!list->ready) {
schedule();
}
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&list->mousedev->wait, &wait);
}
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");
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;
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;
}
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,
disconnect: mousedev_disconnect,
fops: &mousedev_fops,
minor: MOUSEDEV_MINOR_BASE,
+ name: "mousedev",
+ id_table: mousedev_ids,
};
static int __init mousedev_init(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");
#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
*/
/*
*
* 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;
struct gameport_dev {
void *private;
+ char *name;
void (*connect)(struct gameport *, struct gameport_dev *dev);
void (*disconnect)(struct 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);
#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)
{
static __inline__ void wait_ms(unsigned int ms)
{
- current->state = TASK_UNINTERRUPTIBLE;
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1 + ms * HZ / 1000);
}
#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
*/
/*
*
* 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
* 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__
#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 */
/*
#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
/*
#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
#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
/*
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
+#define BUS_HIL 0x04
#define BUS_ISA 0x10
#define BUS_I8042 0x11
#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;
};
/* 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 */
/* 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;
};
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;
};
/*
- * 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.
*/
void *private;
- int number;
char *name;
+ char *phys;
+ char *uniq;
+ int number;
+
unsigned short idbus;
unsigned short idvendor;
unsigned short idproduct;
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];
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);
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;
void *private;
int open;
+ char *name;
struct input_dev *dev;
struct input_handler *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);
#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
#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
*/
/*
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 *);
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
#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
#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