linux/drivers/input/serio/serio_raw.c
<<
>>
Prefs
   1/*
   2 * Raw serio device providing access to a raw byte stream from underlying
   3 * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
   4 *
   5 * Copyright (c) 2004 Dmitry Torokhov
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License version 2 as published by
   9 * the Free Software Foundation.
  10 */
  11
  12#include <linux/sched.h>
  13#include <linux/slab.h>
  14#include <linux/poll.h>
  15#include <linux/module.h>
  16#include <linux/serio.h>
  17#include <linux/init.h>
  18#include <linux/major.h>
  19#include <linux/device.h>
  20#include <linux/miscdevice.h>
  21#include <linux/wait.h>
  22#include <linux/mutex.h>
  23
  24#define DRIVER_DESC     "Raw serio driver"
  25
  26MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
  27MODULE_DESCRIPTION(DRIVER_DESC);
  28MODULE_LICENSE("GPL");
  29
  30#define SERIO_RAW_QUEUE_LEN     64
  31struct serio_raw {
  32        unsigned char queue[SERIO_RAW_QUEUE_LEN];
  33        unsigned int tail, head;
  34
  35        char name[16];
  36        unsigned int refcnt;
  37        struct serio *serio;
  38        struct miscdevice dev;
  39        wait_queue_head_t wait;
  40        struct list_head list;
  41        struct list_head node;
  42};
  43
  44struct serio_raw_list {
  45        struct fasync_struct *fasync;
  46        struct serio_raw *serio_raw;
  47        struct list_head node;
  48};
  49
  50static DEFINE_MUTEX(serio_raw_mutex);
  51static LIST_HEAD(serio_raw_list);
  52static unsigned int serio_raw_no;
  53
  54/*********************************************************************
  55 *             Interface with userspace (file operations)            *
  56 *********************************************************************/
  57
  58static int serio_raw_fasync(int fd, struct file *file, int on)
  59{
  60        struct serio_raw_list *list = file->private_data;
  61
  62        return fasync_helper(fd, file, on, &list->fasync);
  63}
  64
  65static struct serio_raw *serio_raw_locate(int minor)
  66{
  67        struct serio_raw *serio_raw;
  68
  69        list_for_each_entry(serio_raw, &serio_raw_list, node) {
  70                if (serio_raw->dev.minor == minor)
  71                        return serio_raw;
  72        }
  73
  74        return NULL;
  75}
  76
  77static int serio_raw_open(struct inode *inode, struct file *file)
  78{
  79        struct serio_raw *serio_raw;
  80        struct serio_raw_list *list;
  81        int retval = 0;
  82
  83        retval = mutex_lock_interruptible(&serio_raw_mutex);
  84        if (retval)
  85                return retval;
  86
  87        serio_raw = serio_raw_locate(iminor(inode));
  88        if (!serio_raw) {
  89                retval = -ENODEV;
  90                goto out;
  91        }
  92
  93        if (!serio_raw->serio) {
  94                retval = -ENODEV;
  95                goto out;
  96        }
  97
  98        list = kzalloc(sizeof(struct serio_raw_list), GFP_KERNEL);
  99        if (!list) {
 100                retval = -ENOMEM;
 101                goto out;
 102        }
 103
 104        list->serio_raw = serio_raw;
 105        file->private_data = list;
 106
 107        serio_raw->refcnt++;
 108        list_add_tail(&list->node, &serio_raw->list);
 109
 110out:
 111        mutex_unlock(&serio_raw_mutex);
 112        return retval;
 113}
 114
 115static int serio_raw_cleanup(struct serio_raw *serio_raw)
 116{
 117        if (--serio_raw->refcnt == 0) {
 118                misc_deregister(&serio_raw->dev);
 119                list_del_init(&serio_raw->node);
 120                kfree(serio_raw);
 121
 122                return 1;
 123        }
 124
 125        return 0;
 126}
 127
 128static int serio_raw_release(struct inode *inode, struct file *file)
 129{
 130        struct serio_raw_list *list = file->private_data;
 131        struct serio_raw *serio_raw = list->serio_raw;
 132
 133        mutex_lock(&serio_raw_mutex);
 134
 135        serio_raw_cleanup(serio_raw);
 136
 137        mutex_unlock(&serio_raw_mutex);
 138        return 0;
 139}
 140
 141static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
 142{
 143        unsigned long flags;
 144        int empty;
 145
 146        spin_lock_irqsave(&serio_raw->serio->lock, flags);
 147
 148        empty = serio_raw->head == serio_raw->tail;
 149        if (!empty) {
 150                *c = serio_raw->queue[serio_raw->tail];
 151                serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
 152        }
 153
 154        spin_unlock_irqrestore(&serio_raw->serio->lock, flags);
 155
 156        return !empty;
 157}
 158
 159static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 160{
 161        struct serio_raw_list *list = file->private_data;
 162        struct serio_raw *serio_raw = list->serio_raw;
 163        char uninitialized_var(c);
 164        ssize_t retval = 0;
 165
 166        if (!serio_raw->serio)
 167                return -ENODEV;
 168
 169        if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
 170                return -EAGAIN;
 171
 172        retval = wait_event_interruptible(list->serio_raw->wait,
 173                                          serio_raw->head != serio_raw->tail || !serio_raw->serio);
 174        if (retval)
 175                return retval;
 176
 177        if (!serio_raw->serio)
 178                return -ENODEV;
 179
 180        while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) {
 181                if (put_user(c, buffer++))
 182                        return -EFAULT;
 183                retval++;
 184        }
 185
 186        return retval;
 187}
 188
 189static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 190{
 191        struct serio_raw_list *list = file->private_data;
 192        ssize_t written = 0;
 193        int retval;
 194        unsigned char c;
 195
 196        retval = mutex_lock_interruptible(&serio_raw_mutex);
 197        if (retval)
 198                return retval;
 199
 200        if (!list->serio_raw->serio) {
 201                retval = -ENODEV;
 202                goto out;
 203        }
 204
 205        if (count > 32)
 206                count = 32;
 207
 208        while (count--) {
 209                if (get_user(c, buffer++)) {
 210                        retval = -EFAULT;
 211                        goto out;
 212                }
 213                if (serio_write(list->serio_raw->serio, c)) {
 214                        retval = -EIO;
 215                        goto out;
 216                }
 217                written++;
 218        };
 219
 220out:
 221        mutex_unlock(&serio_raw_mutex);
 222        return written;
 223}
 224
 225static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
 226{
 227        struct serio_raw_list *list = file->private_data;
 228
 229        poll_wait(file, &list->serio_raw->wait, wait);
 230
 231        if (list->serio_raw->head != list->serio_raw->tail)
 232                return POLLIN | POLLRDNORM;
 233
 234        return 0;
 235}
 236
 237static const struct file_operations serio_raw_fops = {
 238        .owner =        THIS_MODULE,
 239        .open =         serio_raw_open,
 240        .release =      serio_raw_release,
 241        .read =         serio_raw_read,
 242        .write =        serio_raw_write,
 243        .poll =         serio_raw_poll,
 244        .fasync =       serio_raw_fasync,
 245        .llseek = noop_llseek,
 246};
 247
 248
 249/*********************************************************************
 250 *                   Interface with serio port                       *
 251 *********************************************************************/
 252
 253static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
 254                                        unsigned int dfl)
 255{
 256        struct serio_raw *serio_raw = serio_get_drvdata(serio);
 257        struct serio_raw_list *list;
 258        unsigned int head = serio_raw->head;
 259
 260        /* we are holding serio->lock here so we are prootected */
 261        serio_raw->queue[head] = data;
 262        head = (head + 1) % SERIO_RAW_QUEUE_LEN;
 263        if (likely(head != serio_raw->tail)) {
 264                serio_raw->head = head;
 265                list_for_each_entry(list, &serio_raw->list, node)
 266                        kill_fasync(&list->fasync, SIGIO, POLL_IN);
 267                wake_up_interruptible(&serio_raw->wait);
 268        }
 269
 270        return IRQ_HANDLED;
 271}
 272
 273static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
 274{
 275        struct serio_raw *serio_raw;
 276        int err;
 277
 278        if (!(serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
 279                printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
 280                return -ENOMEM;
 281        }
 282
 283        mutex_lock(&serio_raw_mutex);
 284
 285        snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++);
 286        serio_raw->refcnt = 1;
 287        serio_raw->serio = serio;
 288        INIT_LIST_HEAD(&serio_raw->list);
 289        init_waitqueue_head(&serio_raw->wait);
 290
 291        serio_set_drvdata(serio, serio_raw);
 292
 293        err = serio_open(serio, drv);
 294        if (err)
 295                goto out_free;
 296
 297        list_add_tail(&serio_raw->node, &serio_raw_list);
 298
 299        serio_raw->dev.minor = PSMOUSE_MINOR;
 300        serio_raw->dev.name = serio_raw->name;
 301        serio_raw->dev.parent = &serio->dev;
 302        serio_raw->dev.fops = &serio_raw_fops;
 303
 304        err = misc_register(&serio_raw->dev);
 305        if (err) {
 306                serio_raw->dev.minor = MISC_DYNAMIC_MINOR;
 307                err = misc_register(&serio_raw->dev);
 308        }
 309
 310        if (err) {
 311                printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n",
 312                        serio->phys);
 313                goto out_close;
 314        }
 315
 316        printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n",
 317                serio->phys, serio_raw->name, serio_raw->dev.minor);
 318        goto out;
 319
 320out_close:
 321        serio_close(serio);
 322        list_del_init(&serio_raw->node);
 323out_free:
 324        serio_set_drvdata(serio, NULL);
 325        kfree(serio_raw);
 326out:
 327        mutex_unlock(&serio_raw_mutex);
 328        return err;
 329}
 330
 331static int serio_raw_reconnect(struct serio *serio)
 332{
 333        struct serio_raw *serio_raw = serio_get_drvdata(serio);
 334        struct serio_driver *drv = serio->drv;
 335
 336        if (!drv || !serio_raw) {
 337                printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n");
 338                return -1;
 339        }
 340
 341        /*
 342         * Nothing needs to be done here, we just need this method to
 343         * keep the same device.
 344         */
 345        return 0;
 346}
 347
 348static void serio_raw_disconnect(struct serio *serio)
 349{
 350        struct serio_raw *serio_raw;
 351
 352        mutex_lock(&serio_raw_mutex);
 353
 354        serio_raw = serio_get_drvdata(serio);
 355
 356        serio_close(serio);
 357        serio_set_drvdata(serio, NULL);
 358
 359        serio_raw->serio = NULL;
 360        if (!serio_raw_cleanup(serio_raw))
 361                wake_up_interruptible(&serio_raw->wait);
 362
 363        mutex_unlock(&serio_raw_mutex);
 364}
 365
 366static struct serio_device_id serio_raw_serio_ids[] = {
 367        {
 368                .type   = SERIO_8042,
 369                .proto  = SERIO_ANY,
 370                .id     = SERIO_ANY,
 371                .extra  = SERIO_ANY,
 372        },
 373        {
 374                .type   = SERIO_8042_XL,
 375                .proto  = SERIO_ANY,
 376                .id     = SERIO_ANY,
 377                .extra  = SERIO_ANY,
 378        },
 379        { 0 }
 380};
 381
 382MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids);
 383
 384static struct serio_driver serio_raw_drv = {
 385        .driver         = {
 386                .name   = "serio_raw",
 387        },
 388        .description    = DRIVER_DESC,
 389        .id_table       = serio_raw_serio_ids,
 390        .interrupt      = serio_raw_interrupt,
 391        .connect        = serio_raw_connect,
 392        .reconnect      = serio_raw_reconnect,
 393        .disconnect     = serio_raw_disconnect,
 394        .manual_bind    = 1,
 395};
 396
 397static int __init serio_raw_init(void)
 398{
 399        return serio_register_driver(&serio_raw_drv);
 400}
 401
 402static void __exit serio_raw_exit(void)
 403{
 404        serio_unregister_driver(&serio_raw_drv);
 405}
 406
 407module_init(serio_raw_init);
 408module_exit(serio_raw_exit);
 409