diff --git a/index.html b/index.html index 8cf88a9..7206668 100644 --- a/index.html +++ b/index.html @@ -18,7 +18,7 @@

The Linux Kernel Module Programming Guide

Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang

-
October 25, 2024
+
October 26, 2024
@@ -6111,144 +6111,146 @@ will generate the class_attribute 283    return len; 284 285fail_register_vinput: -286    device_unregister(&vinput->dev); -287    /* avoid calling vinput_destroy_vdevice() twice */ -288    return err; -289fail_register: -290    vinput_destroy_vdevice(vinput); -291fail: -292    return err; -293} -294/* This macro generates class_attr_export structure and export_store() */ -295static CLASS_ATTR_WO(export); -296 -297#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) -298static ssize_t unexport_store(const struct class *class, -299                              const struct class_attribute *attr, -300#else -301static ssize_t unexport_store(struct class *class, struct class_attribute *attr, -302#endif -303                              const char *buf, size_t len) -304{ -305    int err; -306    unsigned long id; -307    struct vinput *vinput; -308 -309    err = kstrtol(buf, 10, &id); -310    if (err) { -311        err = -EINVAL; -312        goto failed; -313    } -314 -315    vinput = vinput_get_vdevice_by_id(id); -316    if (IS_ERR(vinput)) { -317        pr_err("vinput: No such vinput device %ld\n", id); -318        err = PTR_ERR(vinput); -319        goto failed; -320    } -321 -322    vinput_unregister_vdevice(vinput); -323    device_unregister(&vinput->dev); -324 -325    return len; -326failed: -327    return err; -328} -329/* This macro generates class_attr_unexport structure and unexport_store() */ -330static CLASS_ATTR_WO(unexport); -331 -332static struct attribute *vinput_class_attrs[] = { -333    &class_attr_export.attr, -334    &class_attr_unexport.attr, -335    NULL, -336}; -337 -338/* This macro generates vinput_class_groups structure */ -339ATTRIBUTE_GROUPS(vinput_class); -340 -341static struct class vinput_class = { -342    .name = "vinput", -343#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) -344    .owner = THIS_MODULE, -345#endif -346    .class_groups = vinput_class_groups, -347}; -348 -349int vinput_register(struct vinput_device *dev) -350{ -351    spin_lock(&vinput_lock); -352    list_add(&dev->list, &vinput_devices); -353    spin_unlock(&vinput_lock); -354 -355    pr_info("vinput: registered new virtual input device '%s'\n", dev->name); +286    input_free_device(vinput->input); +287    device_unregister(&vinput->dev); +288    /* avoid calling vinput_destroy_vdevice() twice */ +289    return err; +290fail_register: +291    input_free_device(vinput->input); +292    vinput_destroy_vdevice(vinput); +293fail: +294    return err; +295} +296/* This macro generates class_attr_export structure and export_store() */ +297static CLASS_ATTR_WO(export); +298 +299#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) +300static ssize_t unexport_store(const struct class *class, +301                              const struct class_attribute *attr, +302#else +303static ssize_t unexport_store(struct class *class, struct class_attribute *attr, +304#endif +305                              const char *buf, size_t len) +306{ +307    int err; +308    unsigned long id; +309    struct vinput *vinput; +310 +311    err = kstrtol(buf, 10, &id); +312    if (err) { +313        err = -EINVAL; +314        goto failed; +315    } +316 +317    vinput = vinput_get_vdevice_by_id(id); +318    if (IS_ERR(vinput)) { +319        pr_err("vinput: No such vinput device %ld\n", id); +320        err = PTR_ERR(vinput); +321        goto failed; +322    } +323 +324    vinput_unregister_vdevice(vinput); +325    device_unregister(&vinput->dev); +326 +327    return len; +328failed: +329    return err; +330} +331/* This macro generates class_attr_unexport structure and unexport_store() */ +332static CLASS_ATTR_WO(unexport); +333 +334static struct attribute *vinput_class_attrs[] = { +335    &class_attr_export.attr, +336    &class_attr_unexport.attr, +337    NULL, +338}; +339 +340/* This macro generates vinput_class_groups structure */ +341ATTRIBUTE_GROUPS(vinput_class); +342 +343static struct class vinput_class = { +344    .name = "vinput", +345#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +346    .owner = THIS_MODULE, +347#endif +348    .class_groups = vinput_class_groups, +349}; +350 +351int vinput_register(struct vinput_device *dev) +352{ +353    spin_lock(&vinput_lock); +354    list_add(&dev->list, &vinput_devices); +355    spin_unlock(&vinput_lock); 356 -357    return 0; -358} -359EXPORT_SYMBOL(vinput_register); -360 -361void vinput_unregister(struct vinput_device *dev) -362{ -363    struct list_head *curr, *next; -364 -365    /* Remove from the list first */ -366    spin_lock(&vinput_lock); -367    list_del(&dev->list); -368    spin_unlock(&vinput_lock); -369 -370    /* unregister all devices of this type */ -371    list_for_each_safe (curr, next, &vinput_vdevices) { -372        struct vinput *vinput = list_entry(curr, struct vinput, list); -373        if (vinput && vinput->type == dev) { -374            vinput_unregister_vdevice(vinput); -375            device_unregister(&vinput->dev); -376        } -377    } -378 -379    pr_info("vinput: unregistered virtual input device '%s'\n", dev->name); -380} -381EXPORT_SYMBOL(vinput_unregister); -382 -383static int __init vinput_init(void) -384{ -385    int err = 0; -386 -387    pr_info("vinput: Loading virtual input driver\n"); +357    pr_info("vinput: registered new virtual input device '%s'\n", dev->name); +358 +359    return 0; +360} +361EXPORT_SYMBOL(vinput_register); +362 +363void vinput_unregister(struct vinput_device *dev) +364{ +365    struct list_head *curr, *next; +366 +367    /* Remove from the list first */ +368    spin_lock(&vinput_lock); +369    list_del(&dev->list); +370    spin_unlock(&vinput_lock); +371 +372    /* unregister all devices of this type */ +373    list_for_each_safe (curr, next, &vinput_vdevices) { +374        struct vinput *vinput = list_entry(curr, struct vinput, list); +375        if (vinput && vinput->type == dev) { +376            vinput_unregister_vdevice(vinput); +377            device_unregister(&vinput->dev); +378        } +379    } +380 +381    pr_info("vinput: unregistered virtual input device '%s'\n", dev->name); +382} +383EXPORT_SYMBOL(vinput_unregister); +384 +385static int __init vinput_init(void) +386{ +387    int err = 0; 388 -389    vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops); -390    if (vinput_dev < 0) { -391        pr_err("vinput: Unable to allocate char dev region\n"); -392        err = vinput_dev; -393        goto failed_alloc; -394    } -395 -396    spin_lock_init(&vinput_lock); +389    pr_info("vinput: Loading virtual input driver\n"); +390 +391    vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops); +392    if (vinput_dev < 0) { +393        pr_err("vinput: Unable to allocate char dev region\n"); +394        err = vinput_dev; +395        goto failed_alloc; +396    } 397 -398    err = class_register(&vinput_class); -399    if (err < 0) { -400        pr_err("vinput: Unable to register vinput class\n"); -401        goto failed_class; -402    } -403 -404    return 0; -405failed_class: -406    unregister_chrdev(vinput_dev, DRIVER_NAME); -407failed_alloc: -408    return err; -409} -410 -411static void __exit vinput_end(void) -412{ -413    pr_info("vinput: Unloading virtual input driver\n"); -414 -415    unregister_chrdev(vinput_dev, DRIVER_NAME); -416    class_unregister(&vinput_class); -417} -418 -419module_init(vinput_init); -420module_exit(vinput_end); -421 -422MODULE_LICENSE("GPL"); -423MODULE_DESCRIPTION("Emulate input events"); +398    spin_lock_init(&vinput_lock); +399 +400    err = class_register(&vinput_class); +401    if (err < 0) { +402        pr_err("vinput: Unable to register vinput class\n"); +403        goto failed_class; +404    } +405 +406    return 0; +407failed_class: +408    unregister_chrdev(vinput_dev, DRIVER_NAME); +409failed_alloc: +410    return err; +411} +412 +413static void __exit vinput_end(void) +414{ +415    pr_info("vinput: Unloading virtual input driver\n"); +416 +417    unregister_chrdev(vinput_dev, DRIVER_NAME); +418    class_unregister(&vinput_class); +419} +420 +421module_init(vinput_init); +422module_exit(vinput_end); +423 +424MODULE_LICENSE("GPL"); +425MODULE_DESCRIPTION("Emulate input events");

Here the virtual keyboard is one of example to use vinput. It supports all KEY_MAX keycodes. The injection format is the KEY_CODE @@ -6261,7 +6263,7 @@ following demonstrates how simulation work. = 34):

-
1echo "+34" | sudo tee /dev/vinput0
+
1echo "+34" | sudo tee /dev/vinput0

Simulate a key release on "g" ( KEY_G = 34):

@@ -6269,120 +6271,120 @@ following demonstrates how simulation work.

-
1echo "-34" | sudo tee /dev/vinput0
+
1echo "-34" | sudo tee /dev/vinput0

-
1/* 
-2 * vkbd.c 
-3 */ 
-4 
-5#include <linux/init.h> 
-6#include <linux/input.h> 
-7#include <linux/module.h> 
-8#include <linux/spinlock.h> 
-9 
-10#include "vinput.h" 
-11 
-12#define VINPUT_KBD "vkbd" 
-13#define VINPUT_RELEASE 0 
-14#define VINPUT_PRESS 1 
-15 
-16static unsigned short vkeymap[KEY_MAX]; 
-17 
-18static int vinput_vkbd_init(struct vinput *vinput) 
-19{ 
-20    int i; 
-21 
-22    /* Set up the input bitfield */ 
-23    vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 
-24    vinput->input->keycodesize = sizeof(unsigned short); 
-25    vinput->input->keycodemax = KEY_MAX; 
-26    vinput->input->keycode = vkeymap; 
-27 
-28    for (i = 0; i < KEY_MAX; i++) 
-29        set_bit(vkeymap[i], vinput->input->keybit); 
-30 
-31    /* vinput will help us allocate new input device structure via 
-32     * input_allocate_device(). So, we can register it straightforwardly. 
-33     */ 
-34    return input_register_device(vinput->input); 
-35} 
-36 
-37static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len) 
-38{ 
-39    spin_lock(&vinput->lock); 
-40    len = snprintf(buff, len, "%+ld\n", vinput->last_entry); 
-41    spin_unlock(&vinput->lock); 
-42 
-43    return len; 
-44} 
-45 
-46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len) 
-47{ 
-48    int ret; 
-49    long key = 0; 
-50    short type = VINPUT_PRESS; 
-51 
-52    /* Determine which event was received (press or release) 
-53     * and store the state. 
-54     */ 
-55    if (buff[0] == '+') 
-56        ret = kstrtol(buff + 1, 10, &key); 
-57    else 
-58        ret = kstrtol(buff, 10, &key); 
-59    if (ret) 
-60        dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret); 
-61    spin_lock(&vinput->lock); 
-62    vinput->last_entry = key; 
-63    spin_unlock(&vinput->lock); 
-64 
-65    if (key < 0) { 
-66        type = VINPUT_RELEASE; 
-67        key = -key; 
-68    } 
-69 
-70    dev_info(&vinput->dev, "Event %s code %ld\n", 
-71             (type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key); 
-72 
-73    /* Report the state received to input subsystem. */ 
-74    input_report_key(vinput->input, key, type); 
-75    /* Tell input subsystem that it finished the report. */ 
-76    input_sync(vinput->input); 
-77 
-78    return len; 
-79} 
-80 
-81static struct vinput_ops vkbd_ops = { 
-82    .init = vinput_vkbd_init, 
-83    .send = vinput_vkbd_send, 
-84    .read = vinput_vkbd_read, 
-85}; 
-86 
-87static struct vinput_device vkbd_dev = { 
-88    .name = VINPUT_KBD, 
-89    .ops = &vkbd_ops, 
-90}; 
-91 
-92static int __init vkbd_init(void) 
-93{ 
-94    int i; 
-95 
-96    for (i = 0; i < KEY_MAX; i++) 
-97        vkeymap[i] = i; 
-98    return vinput_register(&vkbd_dev); 
-99} 
-100 
-101static void __exit vkbd_end(void) 
-102{ 
-103    vinput_unregister(&vkbd_dev); 
-104} 
-105 
-106module_init(vkbd_init); 
-107module_exit(vkbd_end); 
-108 
-109MODULE_LICENSE("GPL"); 
-110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
+
1/* 
+2 * vkbd.c 
+3 */ 
+4 
+5#include <linux/init.h> 
+6#include <linux/input.h> 
+7#include <linux/module.h> 
+8#include <linux/spinlock.h> 
+9 
+10#include "vinput.h" 
+11 
+12#define VINPUT_KBD "vkbd" 
+13#define VINPUT_RELEASE 0 
+14#define VINPUT_PRESS 1 
+15 
+16static unsigned short vkeymap[KEY_MAX]; 
+17 
+18static int vinput_vkbd_init(struct vinput *vinput) 
+19{ 
+20    int i; 
+21 
+22    /* Set up the input bitfield */ 
+23    vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 
+24    vinput->input->keycodesize = sizeof(unsigned short); 
+25    vinput->input->keycodemax = KEY_MAX; 
+26    vinput->input->keycode = vkeymap; 
+27 
+28    for (i = 0; i < KEY_MAX; i++) 
+29        set_bit(vkeymap[i], vinput->input->keybit); 
+30 
+31    /* vinput will help us allocate new input device structure via 
+32     * input_allocate_device(). So, we can register it straightforwardly. 
+33     */ 
+34    return input_register_device(vinput->input); 
+35} 
+36 
+37static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len) 
+38{ 
+39    spin_lock(&vinput->lock); 
+40    len = snprintf(buff, len, "%+ld\n", vinput->last_entry); 
+41    spin_unlock(&vinput->lock); 
+42 
+43    return len; 
+44} 
+45 
+46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len) 
+47{ 
+48    int ret; 
+49    long key = 0; 
+50    short type = VINPUT_PRESS; 
+51 
+52    /* Determine which event was received (press or release) 
+53     * and store the state. 
+54     */ 
+55    if (buff[0] == '+') 
+56        ret = kstrtol(buff + 1, 10, &key); 
+57    else 
+58        ret = kstrtol(buff, 10, &key); 
+59    if (ret) 
+60        dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret); 
+61    spin_lock(&vinput->lock); 
+62    vinput->last_entry = key; 
+63    spin_unlock(&vinput->lock); 
+64 
+65    if (key < 0) { 
+66        type = VINPUT_RELEASE; 
+67        key = -key; 
+68    } 
+69 
+70    dev_info(&vinput->dev, "Event %s code %ld\n", 
+71             (type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key); 
+72 
+73    /* Report the state received to input subsystem. */ 
+74    input_report_key(vinput->input, key, type); 
+75    /* Tell input subsystem that it finished the report. */ 
+76    input_sync(vinput->input); 
+77 
+78    return len; 
+79} 
+80 
+81static struct vinput_ops vkbd_ops = { 
+82    .init = vinput_vkbd_init, 
+83    .send = vinput_vkbd_send, 
+84    .read = vinput_vkbd_read, 
+85}; 
+86 
+87static struct vinput_device vkbd_dev = { 
+88    .name = VINPUT_KBD, 
+89    .ops = &vkbd_ops, 
+90}; 
+91 
+92static int __init vkbd_init(void) 
+93{ 
+94    int i; 
+95 
+96    for (i = 0; i < KEY_MAX; i++) 
+97        vkeymap[i] = i; 
+98    return vinput_register(&vkbd_dev); 
+99} 
+100 
+101static void __exit vkbd_end(void) 
+102{ 
+103    vinput_unregister(&vkbd_dev); 
+104} 
+105 
+106module_init(vkbd_init); 
+107module_exit(vkbd_end); 
+108 
+109MODULE_LICENSE("GPL"); 
+110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");

17 Standardizing the interfaces: The Device Model

diff --git a/lkmpg-for-ht.html b/lkmpg-for-ht.html index 8cf88a9..7206668 100644 --- a/lkmpg-for-ht.html +++ b/lkmpg-for-ht.html @@ -18,7 +18,7 @@

The Linux Kernel Module Programming Guide

Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang

-
October 25, 2024
+
October 26, 2024
@@ -6111,144 +6111,146 @@ will generate the class_attribute 283    return len; 284 285fail_register_vinput: -286    device_unregister(&vinput->dev); -287    /* avoid calling vinput_destroy_vdevice() twice */ -288    return err; -289fail_register: -290    vinput_destroy_vdevice(vinput); -291fail: -292    return err; -293} -294/* This macro generates class_attr_export structure and export_store() */ -295static CLASS_ATTR_WO(export); -296 -297#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) -298static ssize_t unexport_store(const struct class *class, -299                              const struct class_attribute *attr, -300#else -301static ssize_t unexport_store(struct class *class, struct class_attribute *attr, -302#endif -303                              const char *buf, size_t len) -304{ -305    int err; -306    unsigned long id; -307    struct vinput *vinput; -308 -309    err = kstrtol(buf, 10, &id); -310    if (err) { -311        err = -EINVAL; -312        goto failed; -313    } -314 -315    vinput = vinput_get_vdevice_by_id(id); -316    if (IS_ERR(vinput)) { -317        pr_err("vinput: No such vinput device %ld\n", id); -318        err = PTR_ERR(vinput); -319        goto failed; -320    } -321 -322    vinput_unregister_vdevice(vinput); -323    device_unregister(&vinput->dev); -324 -325    return len; -326failed: -327    return err; -328} -329/* This macro generates class_attr_unexport structure and unexport_store() */ -330static CLASS_ATTR_WO(unexport); -331 -332static struct attribute *vinput_class_attrs[] = { -333    &class_attr_export.attr, -334    &class_attr_unexport.attr, -335    NULL, -336}; -337 -338/* This macro generates vinput_class_groups structure */ -339ATTRIBUTE_GROUPS(vinput_class); -340 -341static struct class vinput_class = { -342    .name = "vinput", -343#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) -344    .owner = THIS_MODULE, -345#endif -346    .class_groups = vinput_class_groups, -347}; -348 -349int vinput_register(struct vinput_device *dev) -350{ -351    spin_lock(&vinput_lock); -352    list_add(&dev->list, &vinput_devices); -353    spin_unlock(&vinput_lock); -354 -355    pr_info("vinput: registered new virtual input device '%s'\n", dev->name); +286    input_free_device(vinput->input); +287    device_unregister(&vinput->dev); +288    /* avoid calling vinput_destroy_vdevice() twice */ +289    return err; +290fail_register: +291    input_free_device(vinput->input); +292    vinput_destroy_vdevice(vinput); +293fail: +294    return err; +295} +296/* This macro generates class_attr_export structure and export_store() */ +297static CLASS_ATTR_WO(export); +298 +299#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) +300static ssize_t unexport_store(const struct class *class, +301                              const struct class_attribute *attr, +302#else +303static ssize_t unexport_store(struct class *class, struct class_attribute *attr, +304#endif +305                              const char *buf, size_t len) +306{ +307    int err; +308    unsigned long id; +309    struct vinput *vinput; +310 +311    err = kstrtol(buf, 10, &id); +312    if (err) { +313        err = -EINVAL; +314        goto failed; +315    } +316 +317    vinput = vinput_get_vdevice_by_id(id); +318    if (IS_ERR(vinput)) { +319        pr_err("vinput: No such vinput device %ld\n", id); +320        err = PTR_ERR(vinput); +321        goto failed; +322    } +323 +324    vinput_unregister_vdevice(vinput); +325    device_unregister(&vinput->dev); +326 +327    return len; +328failed: +329    return err; +330} +331/* This macro generates class_attr_unexport structure and unexport_store() */ +332static CLASS_ATTR_WO(unexport); +333 +334static struct attribute *vinput_class_attrs[] = { +335    &class_attr_export.attr, +336    &class_attr_unexport.attr, +337    NULL, +338}; +339 +340/* This macro generates vinput_class_groups structure */ +341ATTRIBUTE_GROUPS(vinput_class); +342 +343static struct class vinput_class = { +344    .name = "vinput", +345#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +346    .owner = THIS_MODULE, +347#endif +348    .class_groups = vinput_class_groups, +349}; +350 +351int vinput_register(struct vinput_device *dev) +352{ +353    spin_lock(&vinput_lock); +354    list_add(&dev->list, &vinput_devices); +355    spin_unlock(&vinput_lock); 356 -357    return 0; -358} -359EXPORT_SYMBOL(vinput_register); -360 -361void vinput_unregister(struct vinput_device *dev) -362{ -363    struct list_head *curr, *next; -364 -365    /* Remove from the list first */ -366    spin_lock(&vinput_lock); -367    list_del(&dev->list); -368    spin_unlock(&vinput_lock); -369 -370    /* unregister all devices of this type */ -371    list_for_each_safe (curr, next, &vinput_vdevices) { -372        struct vinput *vinput = list_entry(curr, struct vinput, list); -373        if (vinput && vinput->type == dev) { -374            vinput_unregister_vdevice(vinput); -375            device_unregister(&vinput->dev); -376        } -377    } -378 -379    pr_info("vinput: unregistered virtual input device '%s'\n", dev->name); -380} -381EXPORT_SYMBOL(vinput_unregister); -382 -383static int __init vinput_init(void) -384{ -385    int err = 0; -386 -387    pr_info("vinput: Loading virtual input driver\n"); +357    pr_info("vinput: registered new virtual input device '%s'\n", dev->name); +358 +359    return 0; +360} +361EXPORT_SYMBOL(vinput_register); +362 +363void vinput_unregister(struct vinput_device *dev) +364{ +365    struct list_head *curr, *next; +366 +367    /* Remove from the list first */ +368    spin_lock(&vinput_lock); +369    list_del(&dev->list); +370    spin_unlock(&vinput_lock); +371 +372    /* unregister all devices of this type */ +373    list_for_each_safe (curr, next, &vinput_vdevices) { +374        struct vinput *vinput = list_entry(curr, struct vinput, list); +375        if (vinput && vinput->type == dev) { +376            vinput_unregister_vdevice(vinput); +377            device_unregister(&vinput->dev); +378        } +379    } +380 +381    pr_info("vinput: unregistered virtual input device '%s'\n", dev->name); +382} +383EXPORT_SYMBOL(vinput_unregister); +384 +385static int __init vinput_init(void) +386{ +387    int err = 0; 388 -389    vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops); -390    if (vinput_dev < 0) { -391        pr_err("vinput: Unable to allocate char dev region\n"); -392        err = vinput_dev; -393        goto failed_alloc; -394    } -395 -396    spin_lock_init(&vinput_lock); +389    pr_info("vinput: Loading virtual input driver\n"); +390 +391    vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops); +392    if (vinput_dev < 0) { +393        pr_err("vinput: Unable to allocate char dev region\n"); +394        err = vinput_dev; +395        goto failed_alloc; +396    } 397 -398    err = class_register(&vinput_class); -399    if (err < 0) { -400        pr_err("vinput: Unable to register vinput class\n"); -401        goto failed_class; -402    } -403 -404    return 0; -405failed_class: -406    unregister_chrdev(vinput_dev, DRIVER_NAME); -407failed_alloc: -408    return err; -409} -410 -411static void __exit vinput_end(void) -412{ -413    pr_info("vinput: Unloading virtual input driver\n"); -414 -415    unregister_chrdev(vinput_dev, DRIVER_NAME); -416    class_unregister(&vinput_class); -417} -418 -419module_init(vinput_init); -420module_exit(vinput_end); -421 -422MODULE_LICENSE("GPL"); -423MODULE_DESCRIPTION("Emulate input events"); +398    spin_lock_init(&vinput_lock); +399 +400    err = class_register(&vinput_class); +401    if (err < 0) { +402        pr_err("vinput: Unable to register vinput class\n"); +403        goto failed_class; +404    } +405 +406    return 0; +407failed_class: +408    unregister_chrdev(vinput_dev, DRIVER_NAME); +409failed_alloc: +410    return err; +411} +412 +413static void __exit vinput_end(void) +414{ +415    pr_info("vinput: Unloading virtual input driver\n"); +416 +417    unregister_chrdev(vinput_dev, DRIVER_NAME); +418    class_unregister(&vinput_class); +419} +420 +421module_init(vinput_init); +422module_exit(vinput_end); +423 +424MODULE_LICENSE("GPL"); +425MODULE_DESCRIPTION("Emulate input events");

Here the virtual keyboard is one of example to use vinput. It supports all KEY_MAX keycodes. The injection format is the KEY_CODE @@ -6261,7 +6263,7 @@ following demonstrates how simulation work. = 34):

-
1echo "+34" | sudo tee /dev/vinput0
+
1echo "+34" | sudo tee /dev/vinput0

Simulate a key release on "g" ( KEY_G = 34):

@@ -6269,120 +6271,120 @@ following demonstrates how simulation work.

-
1echo "-34" | sudo tee /dev/vinput0
+
1echo "-34" | sudo tee /dev/vinput0

-
1/* 
-2 * vkbd.c 
-3 */ 
-4 
-5#include <linux/init.h> 
-6#include <linux/input.h> 
-7#include <linux/module.h> 
-8#include <linux/spinlock.h> 
-9 
-10#include "vinput.h" 
-11 
-12#define VINPUT_KBD "vkbd" 
-13#define VINPUT_RELEASE 0 
-14#define VINPUT_PRESS 1 
-15 
-16static unsigned short vkeymap[KEY_MAX]; 
-17 
-18static int vinput_vkbd_init(struct vinput *vinput) 
-19{ 
-20    int i; 
-21 
-22    /* Set up the input bitfield */ 
-23    vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 
-24    vinput->input->keycodesize = sizeof(unsigned short); 
-25    vinput->input->keycodemax = KEY_MAX; 
-26    vinput->input->keycode = vkeymap; 
-27 
-28    for (i = 0; i < KEY_MAX; i++) 
-29        set_bit(vkeymap[i], vinput->input->keybit); 
-30 
-31    /* vinput will help us allocate new input device structure via 
-32     * input_allocate_device(). So, we can register it straightforwardly. 
-33     */ 
-34    return input_register_device(vinput->input); 
-35} 
-36 
-37static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len) 
-38{ 
-39    spin_lock(&vinput->lock); 
-40    len = snprintf(buff, len, "%+ld\n", vinput->last_entry); 
-41    spin_unlock(&vinput->lock); 
-42 
-43    return len; 
-44} 
-45 
-46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len) 
-47{ 
-48    int ret; 
-49    long key = 0; 
-50    short type = VINPUT_PRESS; 
-51 
-52    /* Determine which event was received (press or release) 
-53     * and store the state. 
-54     */ 
-55    if (buff[0] == '+') 
-56        ret = kstrtol(buff + 1, 10, &key); 
-57    else 
-58        ret = kstrtol(buff, 10, &key); 
-59    if (ret) 
-60        dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret); 
-61    spin_lock(&vinput->lock); 
-62    vinput->last_entry = key; 
-63    spin_unlock(&vinput->lock); 
-64 
-65    if (key < 0) { 
-66        type = VINPUT_RELEASE; 
-67        key = -key; 
-68    } 
-69 
-70    dev_info(&vinput->dev, "Event %s code %ld\n", 
-71             (type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key); 
-72 
-73    /* Report the state received to input subsystem. */ 
-74    input_report_key(vinput->input, key, type); 
-75    /* Tell input subsystem that it finished the report. */ 
-76    input_sync(vinput->input); 
-77 
-78    return len; 
-79} 
-80 
-81static struct vinput_ops vkbd_ops = { 
-82    .init = vinput_vkbd_init, 
-83    .send = vinput_vkbd_send, 
-84    .read = vinput_vkbd_read, 
-85}; 
-86 
-87static struct vinput_device vkbd_dev = { 
-88    .name = VINPUT_KBD, 
-89    .ops = &vkbd_ops, 
-90}; 
-91 
-92static int __init vkbd_init(void) 
-93{ 
-94    int i; 
-95 
-96    for (i = 0; i < KEY_MAX; i++) 
-97        vkeymap[i] = i; 
-98    return vinput_register(&vkbd_dev); 
-99} 
-100 
-101static void __exit vkbd_end(void) 
-102{ 
-103    vinput_unregister(&vkbd_dev); 
-104} 
-105 
-106module_init(vkbd_init); 
-107module_exit(vkbd_end); 
-108 
-109MODULE_LICENSE("GPL"); 
-110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
+
1/* 
+2 * vkbd.c 
+3 */ 
+4 
+5#include <linux/init.h> 
+6#include <linux/input.h> 
+7#include <linux/module.h> 
+8#include <linux/spinlock.h> 
+9 
+10#include "vinput.h" 
+11 
+12#define VINPUT_KBD "vkbd" 
+13#define VINPUT_RELEASE 0 
+14#define VINPUT_PRESS 1 
+15 
+16static unsigned short vkeymap[KEY_MAX]; 
+17 
+18static int vinput_vkbd_init(struct vinput *vinput) 
+19{ 
+20    int i; 
+21 
+22    /* Set up the input bitfield */ 
+23    vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 
+24    vinput->input->keycodesize = sizeof(unsigned short); 
+25    vinput->input->keycodemax = KEY_MAX; 
+26    vinput->input->keycode = vkeymap; 
+27 
+28    for (i = 0; i < KEY_MAX; i++) 
+29        set_bit(vkeymap[i], vinput->input->keybit); 
+30 
+31    /* vinput will help us allocate new input device structure via 
+32     * input_allocate_device(). So, we can register it straightforwardly. 
+33     */ 
+34    return input_register_device(vinput->input); 
+35} 
+36 
+37static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len) 
+38{ 
+39    spin_lock(&vinput->lock); 
+40    len = snprintf(buff, len, "%+ld\n", vinput->last_entry); 
+41    spin_unlock(&vinput->lock); 
+42 
+43    return len; 
+44} 
+45 
+46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len) 
+47{ 
+48    int ret; 
+49    long key = 0; 
+50    short type = VINPUT_PRESS; 
+51 
+52    /* Determine which event was received (press or release) 
+53     * and store the state. 
+54     */ 
+55    if (buff[0] == '+') 
+56        ret = kstrtol(buff + 1, 10, &key); 
+57    else 
+58        ret = kstrtol(buff, 10, &key); 
+59    if (ret) 
+60        dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret); 
+61    spin_lock(&vinput->lock); 
+62    vinput->last_entry = key; 
+63    spin_unlock(&vinput->lock); 
+64 
+65    if (key < 0) { 
+66        type = VINPUT_RELEASE; 
+67        key = -key; 
+68    } 
+69 
+70    dev_info(&vinput->dev, "Event %s code %ld\n", 
+71             (type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key); 
+72 
+73    /* Report the state received to input subsystem. */ 
+74    input_report_key(vinput->input, key, type); 
+75    /* Tell input subsystem that it finished the report. */ 
+76    input_sync(vinput->input); 
+77 
+78    return len; 
+79} 
+80 
+81static struct vinput_ops vkbd_ops = { 
+82    .init = vinput_vkbd_init, 
+83    .send = vinput_vkbd_send, 
+84    .read = vinput_vkbd_read, 
+85}; 
+86 
+87static struct vinput_device vkbd_dev = { 
+88    .name = VINPUT_KBD, 
+89    .ops = &vkbd_ops, 
+90}; 
+91 
+92static int __init vkbd_init(void) 
+93{ 
+94    int i; 
+95 
+96    for (i = 0; i < KEY_MAX; i++) 
+97        vkeymap[i] = i; 
+98    return vinput_register(&vkbd_dev); 
+99} 
+100 
+101static void __exit vkbd_end(void) 
+102{ 
+103    vinput_unregister(&vkbd_dev); 
+104} 
+105 
+106module_init(vkbd_init); 
+107module_exit(vkbd_end); 
+108 
+109MODULE_LICENSE("GPL"); 
+110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");

17 Standardizing the interfaces: The Device Model