linux/drivers/input/evdev.c
<<
>>
Prefs
   1/*
   2 * Event char devices, giving access to raw input device events.
   3 *
   4 * Copyright (c) 1999-2002 Vojtech Pavlik
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License version 2 as published by
   8 * the Free Software Foundation.
   9 */
  10
  11#define EVDEV_MINOR_BASE        64
  12#define EVDEV_MINORS            32
  13#define EVDEV_BUFFER_SIZE       64
  14
  15#include <linux/poll.h>
  16#include <linux/slab.h>
  17#include <linux/module.h>
  18#include <linux/init.h>
  19#include <linux/input.h>
  20#include <linux/major.h>
  21#include <linux/smp_lock.h>
  22#include <linux/device.h>
  23#include <linux/compat.h>
  24
  25struct evdev {
  26        int exist;
  27        int open;
  28        int minor;
  29        char name[16];
  30        struct input_handle handle;
  31        wait_queue_head_t wait;
  32        struct evdev_list *grab;
  33        struct list_head list;
  34};
  35
  36struct evdev_list {
  37        struct input_event buffer[EVDEV_BUFFER_SIZE];
  38        int head;
  39        int tail;
  40        struct fasync_struct *fasync;
  41        struct evdev *evdev;
  42        struct list_head node;
  43};
  44
  45static struct evdev *evdev_table[EVDEV_MINORS];
  46
  47static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
  48{
  49        struct evdev *evdev = handle->private;
  50        struct evdev_list *list;
  51
  52        if (evdev->grab) {
  53                list = evdev->grab;
  54
  55                do_gettimeofday(&list->buffer[list->head].time);
  56                list->buffer[list->head].type = type;
  57                list->buffer[list->head].code = code;
  58                list->buffer[list->head].value = value;
  59                list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
  60
  61                kill_fasync(&list->fasync, SIGIO, POLL_IN);
  62        } else
  63                list_for_each_entry(list, &evdev->list, node) {
  64
  65                        do_gettimeofday(&list->buffer[list->head].time);
  66                        list->buffer[list->head].type = type;
  67                        list->buffer[list->head].code = code;
  68                        list->buffer[list->head].value = value;
  69                        list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
  70
  71                        kill_fasync(&list->fasync, SIGIO, POLL_IN);
  72                }
  73
  74        wake_up_interruptible(&evdev->wait);
  75}
  76
  77static int evdev_fasync(int fd, struct file *file, int on)
  78{
  79        int retval;
  80        struct evdev_list *list = file->private_data;
  81
  82        retval = fasync_helper(fd, file, on, &list->fasync);
  83
  84        return retval < 0 ? retval : 0;
  85}
  86
  87static int evdev_flush(struct file *file, fl_owner_t id)
  88{
  89        struct evdev_list *list = file->private_data;
  90
  91        if (!list->evdev->exist)
  92                return -ENODEV;
  93
  94        return input_flush_device(&list->evdev->handle, file);
  95}
  96
  97static void evdev_free(struct evdev *evdev)
  98{
  99        evdev_table[evdev->minor] = NULL;
 100        kfree(evdev);
 101}
 102
 103static int evdev_release(struct inode * inode, struct file * file)
 104{
 105        struct evdev_list *list = file->private_data;
 106
 107        if (list->evdev->grab == list) {
 108                input_release_device(&list->evdev->handle);
 109                list->evdev->grab = NULL;
 110        }
 111
 112        evdev_fasync(-1, file, 0);
 113        list_del(&list->node);
 114
 115        if (!--list->evdev->open) {
 116                if (list->evdev->exist)
 117                        input_close_device(&list->evdev->handle);
 118                else
 119                        evdev_free(list->evdev);
 120        }
 121
 122        kfree(list);
 123        return 0;
 124}
 125
 126static int evdev_open(struct inode * inode, struct file * file)
 127{
 128        struct evdev_list *list;
 129        int i = iminor(inode) - EVDEV_MINOR_BASE;
 130
 131        if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
 132                return -ENODEV;
 133
 134        if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
 135                return -ENOMEM;
 136
 137        list->evdev = evdev_table[i];
 138        list_add_tail(&list->node, &evdev_table[i]->list);
 139        file->private_data = list;
 140
 141        if (!list->evdev->open++)
 142                if (list->evdev->exist)
 143                        input_open_device(&list->evdev->handle);
 144
 145        return 0;
 146}
 147
 148#ifdef CONFIG_COMPAT
 149
 150struct input_event_compat {
 151        struct compat_timeval time;
 152        __u16 type;
 153        __u16 code;
 154        __s32 value;
 155};
 156
 157/* Note to the author of this code: did it ever occur to
 158   you why the ifdefs are needed? Think about it again. -AK */
 159#ifdef CONFIG_X86_64
 160#  define COMPAT_TEST is_compat_task()
 161#elif defined(CONFIG_IA64)
 162#  define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current))
 163#elif defined(CONFIG_S390)
 164#  define COMPAT_TEST test_thread_flag(TIF_31BIT)
 165#elif defined(CONFIG_MIPS)
 166#  define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR)
 167#else
 168#  define COMPAT_TEST test_thread_flag(TIF_32BIT)
 169#endif
 170
 171static inline size_t evdev_event_size(void)
 172{
 173        return COMPAT_TEST ?
 174                sizeof(struct input_event_compat) : sizeof(struct input_event);
 175}
 176
 177static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
 178{
 179        if (COMPAT_TEST) {
 180                struct input_event_compat compat_event;
 181
 182                if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat)))
 183                        return -EFAULT;
 184
 185                event->time.tv_sec = compat_event.time.tv_sec;
 186                event->time.tv_usec = compat_event.time.tv_usec;
 187                event->type = compat_event.type;
 188                event->code = compat_event.code;
 189                event->value = compat_event.value;
 190
 191        } else {
 192                if (copy_from_user(event, buffer, sizeof(struct input_event)))
 193                        return -EFAULT;
 194        }
 195
 196        return 0;
 197}
 198
 199static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
 200{
 201        if (COMPAT_TEST) {
 202                struct input_event_compat compat_event;
 203
 204                compat_event.time.tv_sec = event->time.tv_sec;
 205                compat_event.time.tv_usec = event->time.tv_usec;
 206                compat_event.type = event->type;
 207                compat_event.code = event->code;
 208                compat_event.value = event->value;
 209
 210                if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
 211                        return -EFAULT;
 212
 213        } else {
 214                if (copy_to_user(buffer, event, sizeof(struct input_event)))
 215                        return -EFAULT;
 216        }
 217
 218        return 0;
 219}
 220
 221#else
 222
 223static inline size_t evdev_event_size(void)
 224{
 225        return sizeof(struct input_event);
 226}
 227
 228static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
 229{
 230        if (copy_from_user(event, buffer, sizeof(struct input_event)))
 231                return -EFAULT;
 232
 233        return 0;
 234}
 235
 236static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
 237{
 238        if (copy_to_user(buffer, event, sizeof(struct input_event)))
 239                return -EFAULT;
 240
 241        return 0;
 242}
 243
 244#endif /* CONFIG_COMPAT */
 245
 246static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 247{
 248        struct evdev_list *list = file->private_data;
 249        struct input_event event;
 250        int retval = 0;
 251
 252        if (!list->evdev->exist)
 253                return -ENODEV;
 254
 255        while (retval < count) {
 256
 257                if (evdev_event_from_user(buffer + retval, &event))
 258                        return -EFAULT;
 259                input_inject_event(&list->evdev->handle, event.type, event.code, event.value);
 260                retval += evdev_event_size();
 261        }
 262
 263        return retval;
 264}
 265
 266static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 267{
 268        struct evdev_list *list = file->private_data;
 269        int retval;
 270
 271        if (count < evdev_event_size())
 272                return -EINVAL;
 273
 274        if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
 275                return -EAGAIN;
 276
 277        retval = wait_event_interruptible(list->evdev->wait,
 278                list->head != list->tail || (!list->evdev->exist));
 279
 280        if (retval)
 281                return retval;
 282
 283        if (!list->evdev->exist)
 284                return -ENODEV;
 285
 286        while (list->head != list->tail && retval + evdev_event_size() <= count) {
 287
 288                struct input_event *event = (struct input_event *) list->buffer + list->tail;
 289
 290                if (evdev_event_to_user(buffer + retval, event))
 291                        return -EFAULT;
 292
 293                list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
 294                retval += evdev_event_size();
 295        }
 296
 297        return retval;
 298}
 299
 300/* No kernel lock - fine */
 301static unsigned int evdev_poll(struct file *file, poll_table *wait)
 302{
 303        struct evdev_list *list = file->private_data;
 304
 305        poll_wait(file, &list->evdev->wait, wait);
 306        return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
 307                (list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 308}
 309
 310#ifdef CONFIG_COMPAT
 311
 312#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
 313#define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
 314
 315#ifdef __BIG_ENDIAN
 316static int bits_to_user(unsigned long *bits, unsigned int maxbit,
 317                        unsigned int maxlen, void __user *p, int compat)
 318{
 319        int len, i;
 320
 321        if (compat) {
 322                len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
 323                if (len < maxlen)
 324                        len = maxlen;
 325
 326                for (i = 0; i < len / sizeof(compat_long_t); i++)
 327                        if (copy_to_user((compat_long_t __user *) p + i,
 328                                         (compat_long_t *) bits +
 329                                                i + 1 - ((i % 2) << 1),
 330                                         sizeof(compat_long_t)))
 331                                return -EFAULT;
 332        } else {
 333                len = NBITS(maxbit) * sizeof(long);
 334                if (len > maxlen)
 335                        len = maxlen;
 336
 337                if (copy_to_user(p, bits, len))
 338                        return -EFAULT;
 339        }
 340
 341        return len;
 342}
 343#else
 344static int bits_to_user(unsigned long *bits, unsigned int maxbit,
 345                        unsigned int maxlen, void __user *p, int compat)
 346{
 347        int len = compat ?
 348                        NBITS_COMPAT(maxbit) * sizeof(compat_long_t) :
 349                        NBITS(maxbit) * sizeof(long);
 350
 351        if (len > maxlen)
 352                len = maxlen;
 353
 354        return copy_to_user(p, bits, len) ? -EFAULT : len;
 355}
 356#endif /* __BIG_ENDIAN */
 357
 358#else
 359
 360static int bits_to_user(unsigned long *bits, unsigned int maxbit,
 361                        unsigned int maxlen, void __user *p, int compat)
 362{
 363        int len = NBITS(maxbit) * sizeof(long);
 364
 365        if (len > maxlen)
 366                len = maxlen;
 367
 368        return copy_to_user(p, bits, len) ? -EFAULT : len;
 369}
 370
 371#endif /* CONFIG_COMPAT */
 372
 373static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
 374{
 375        int len;
 376
 377        if (!str)
 378                return -ENOENT;
 379
 380        len = strlen(str) + 1;
 381        if (len > maxlen)
 382                len = maxlen;
 383
 384        return copy_to_user(p, str, len) ? -EFAULT : len;
 385}
 386
 387static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
 388                                void __user *p, int compat_mode)
 389{
 390        struct evdev_list *list = file->private_data;
 391        struct evdev *evdev = list->evdev;
 392        struct input_dev *dev = evdev->handle.dev;
 393        struct input_absinfo abs;
 394        int __user *ip = (int __user *)p;
 395        int i, t, u, v;
 396
 397        if (!evdev->exist)
 398                return -ENODEV;
 399
 400        switch (cmd) {
 401
 402                case EVIOCGVERSION:
 403                        return put_user(EV_VERSION, ip);
 404
 405                case EVIOCGID:
 406                        if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
 407                                return -EFAULT;
 408                        return 0;
 409
 410                case EVIOCGREP:
 411                        if (!test_bit(EV_REP, dev->evbit))
 412                                return -ENOSYS;
 413                        if (put_user(dev->rep[REP_DELAY], ip))
 414                                return -EFAULT;
 415                        if (put_user(dev->rep[REP_PERIOD], ip + 1))
 416                                return -EFAULT;
 417                        return 0;
 418
 419                case EVIOCSREP:
 420                        if (!test_bit(EV_REP, dev->evbit))
 421                                return -ENOSYS;
 422                        if (get_user(u, ip))
 423                                return -EFAULT;
 424                        if (get_user(v, ip + 1))
 425                                return -EFAULT;
 426
 427                        input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
 428                        input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
 429
 430                        return 0;
 431
 432                case EVIOCGKEYCODE:
 433                        if (get_user(t, ip))
 434                                return -EFAULT;
 435                        if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
 436                                return -EINVAL;
 437                        if (put_user(INPUT_KEYCODE(dev, t), ip + 1))
 438                                return -EFAULT;
 439                        return 0;
 440
 441                case EVIOCSKEYCODE:
 442                        if (get_user(t, ip))
 443                                return -EFAULT;
 444                        if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
 445                                return -EINVAL;
 446                        if (get_user(v, ip + 1))
 447                                return -EFAULT;
 448                        if (v < 0 || v > KEY_MAX)
 449                                return -EINVAL;
 450                        if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8)))
 451                                return -EINVAL;
 452
 453                        u = SET_INPUT_KEYCODE(dev, t, v);
 454                        clear_bit(u, dev->keybit);
 455                        set_bit(v, dev->keybit);
 456                        for (i = 0; i < dev->keycodemax; i++)
 457                                if (INPUT_KEYCODE(dev, i) == u)
 458                                        set_bit(u, dev->keybit);
 459
 460                        return 0;
 461
 462                case EVIOCSFF:
 463                        if (dev->upload_effect) {
 464                                struct ff_effect effect;
 465                                int err;
 466
 467                                if (copy_from_user(&effect, p, sizeof(effect)))
 468                                        return -EFAULT;
 469                                err = dev->upload_effect(dev, &effect);
 470                                if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
 471                                        return -EFAULT;
 472                                return err;
 473                        } else
 474                                return -ENOSYS;
 475
 476                case EVIOCRMFF:
 477                        if (!dev->erase_effect)
 478                                return -ENOSYS;
 479
 480                        return dev->erase_effect(dev, (int)(unsigned long) p);
 481
 482                case EVIOCGEFFECTS:
 483                        if (put_user(dev->ff_effects_max, ip))
 484                                return -EFAULT;
 485                        return 0;
 486
 487                case EVIOCGRAB:
 488                        if (p) {
 489                                if (evdev->grab)
 490                                        return -EBUSY;
 491                                if (input_grab_device(&evdev->handle))
 492                                        return -EBUSY;
 493                                evdev->grab = list;
 494                                return 0;
 495                        } else {
 496                                if (evdev->grab != list)
 497                                        return -EINVAL;
 498                                input_release_device(&evdev->handle);
 499                                evdev->grab = NULL;
 500                                return 0;
 501                        }
 502
 503                default:
 504
 505                        if (_IOC_TYPE(cmd) != 'E')
 506                                return -EINVAL;
 507
 508                        if (_IOC_DIR(cmd) == _IOC_READ) {
 509
 510                                if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 511
 512                                        long *bits;
 513                                        int len;
 514
 515                                        switch (_IOC_NR(cmd) & EV_MAX) {
 516                                                case      0: bits = dev->evbit;  len = EV_MAX;  break;
 517                                                case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
 518                                                case EV_REL: bits = dev->relbit; len = REL_MAX; break;
 519                                                case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
 520                                                case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
 521                                                case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
 522                                                case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
 523                                                case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
 524                                                case EV_SW:  bits = dev->swbit;  len = SW_MAX;  break;
 525                                                default: return -EINVAL;
 526                                        }
 527                                        return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
 528                                }
 529
 530                                if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
 531                                        return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
 532                                                            p, compat_mode);
 533
 534                                if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
 535                                        return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
 536                                                            p, compat_mode);
 537
 538                                if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
 539                                        return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
 540                                                            p, compat_mode);
 541
 542                                if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
 543                                        return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
 544                                                            p, compat_mode);
 545
 546                                if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
 547                                        return str_to_user(dev->name, _IOC_SIZE(cmd), p);
 548
 549                                if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
 550                                        return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
 551
 552                                if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
 553                                        return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
 554
 555                                if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 556
 557                                        int t = _IOC_NR(cmd) & ABS_MAX;
 558
 559                                        abs.value = dev->abs[t];
 560                                        abs.minimum = dev->absmin[t];
 561                                        abs.maximum = dev->absmax[t];
 562                                        abs.fuzz = dev->absfuzz[t];
 563                                        abs.flat = dev->absflat[t];
 564
 565                                        if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
 566                                                return -EFAULT;
 567
 568                                        return 0;
 569                                }
 570
 571                        }
 572
 573                        if (_IOC_DIR(cmd) == _IOC_WRITE) {
 574
 575                                if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 576
 577                                        int t = _IOC_NR(cmd) & ABS_MAX;
 578
 579                                        if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
 580                                                return -EFAULT;
 581
 582                                        dev->abs[t] = abs.value;
 583                                        dev->absmin[t] = abs.minimum;
 584                                        dev->absmax[t] = abs.maximum;
 585                                        dev->absfuzz[t] = abs.fuzz;
 586                                        dev->absflat[t] = abs.flat;
 587
 588                                        return 0;
 589                                }
 590                        }
 591        }
 592        return -EINVAL;
 593}
 594
 595static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 596{
 597        return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
 598}
 599
 600#ifdef CONFIG_COMPAT
 601static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 602{
 603        return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
 604}
 605#endif
 606
 607static struct file_operations evdev_fops = {
 608        .owner =        THIS_MODULE,
 609        .read =         evdev_read,
 610        .write =        evdev_write,
 611        .poll =         evdev_poll,
 612        .open =         evdev_open,
 613        .release =      evdev_release,
 614        .unlocked_ioctl = evdev_ioctl,
 615#ifdef CONFIG_COMPAT
 616        .compat_ioctl = evdev_ioctl_compat,
 617#endif
 618        .fasync =       evdev_fasync,
 619        .flush =        evdev_flush
 620};
 621
 622static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
 623{
 624        struct evdev *evdev;
 625        struct class_device *cdev;
 626        int minor;
 627
 628        for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
 629        if (minor == EVDEV_MINORS) {
 630                printk(KERN_ERR "evdev: no more free evdev devices\n");
 631                return NULL;
 632        }
 633
 634        if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
 635                return NULL;
 636
 637        INIT_LIST_HEAD(&evdev->list);
 638        init_waitqueue_head(&evdev->wait);
 639
 640        evdev->exist = 1;
 641        evdev->minor = minor;
 642        evdev->handle.dev = dev;
 643        evdev->handle.name = evdev->name;
 644        evdev->handle.handler = handler;
 645        evdev->handle.private = evdev;
 646        sprintf(evdev->name, "event%d", minor);
 647
 648        evdev_table[minor] = evdev;
 649
 650        cdev = class_device_create(&input_class, &dev->cdev,
 651                        MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
 652                        dev->cdev.dev, evdev->name);
 653
 654        /* temporary symlink to keep userspace happy */
 655        sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
 656                          evdev->name);
 657
 658        return &evdev->handle;
 659}
 660
 661static void evdev_disconnect(struct input_handle *handle)
 662{
 663        struct evdev *evdev = handle->private;
 664        struct evdev_list *list;
 665
 666        sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
 667        class_device_destroy(&input_class,
 668                        MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
 669        evdev->exist = 0;
 670
 671        if (evdev->open) {
 672                input_close_device(handle);
 673                wake_up_interruptible(&evdev->wait);
 674                list_for_each_entry(list, &evdev->list, node)
 675                        kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 676        } else
 677                evdev_free(evdev);
 678}
 679
 680static struct input_device_id evdev_ids[] = {
 681        { .driver_info = 1 },   /* Matches all devices */
 682        { },                    /* Terminating zero entry */
 683};
 684
 685MODULE_DEVICE_TABLE(input, evdev_ids);
 686
 687static struct input_handler evdev_handler = {
 688        .event =        evdev_event,
 689        .connect =      evdev_connect,
 690        .disconnect =   evdev_disconnect,
 691        .fops =         &evdev_fops,
 692        .minor =        EVDEV_MINOR_BASE,
 693        .name =         "evdev",
 694        .id_table =     evdev_ids,
 695};
 696
 697static int __init evdev_init(void)
 698{
 699        input_register_handler(&evdev_handler);
 700        return 0;
 701}
 702
 703static void __exit evdev_exit(void)
 704{
 705        input_unregister_handler(&evdev_handler);
 706}
 707
 708module_init(evdev_init);
 709module_exit(evdev_exit);
 710
 711MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 712MODULE_DESCRIPTION("Input driver event char devices");
 713MODULE_LICENSE("GPL");
 714
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.