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