Linux Input subsystem – I

Overview

What is the Input Subsystem?
The input subsystem is the part of the Linux kernel that manages the various input devices (such as keyboards, mice, joysticks, tablets and a wide range of other devices) that a user uses to interact with the kernel, command line and graphical user interface.
This subsystem is included in the Linux kernel because these devices usually are accessed through special hardware interfaces (such as serial ports, PS/2 ports and the Universal Serial Bus), which are protected and managed by the kernel.
The kernel then exposes the user input in a consistent, device-independent way to user space through a range of defined APIs.

System Framework

Event-driven layer

Is responsible standard Interface and applications

Core layer

Provide the necessary event-driven layer and device driver layer function interface

Device driver layer

Responsible for communications with the underlying input devices and provide the events to upper layers.

Flow:  low-level hardware –> drivers –> input core –> handler –> user space

download

Event-driven and core layer are common, we need to implement the device driver layer. Input device drivers will capture the hardware event information in a uniform format (struct input_event) and report to the core layer, then the core layer sorts the data, then escalated to the appropriate event-handling driver, and finally through the events layer to the user space, applications using /dev device node can get event information.

 

Unified format

Driver submit hardware event information using struct input_event, applications can also use this structure to obtain event information:

struct input_event {

struct timeval time; /Event generated time/

__u16type; /Type of event/

__u16code; /Event code/

__s32value; /Event value/

};

Event type, as defined in linux/input.h

# Event code Specifies
0x00 EV_SYN Separate/synchronize other events (e.g. SYN_REPORT/SYN_MT_REPORT), or report events lost (SYN_DROPPED)
0x01 EV_KEY Key press (KEY_*) or touch (BTN_TOUCH)
0x02 EV_REL Relative changes to a property. Changes relayed through REL_[XYZ] values.
0x03 EV_ABS Absolute coordinates for an event. Values are usually ABS_[XYZ], or ABS_MT for multi-touch
0x04 EV_MSC Miscellaneous codes
0x05 EV_SW Binary switches. E.g. SW_JACK_PHYSICAL_INSERT for headphone insertion
0x11 EV_LED Used for device LEDs, if any
0x12 EV_SND Used for sound devices
0x14 EV_REP Used for auto-repeating events
0x15 EV_FF Used for force-feedback capable devices (e.g. joysticks). An EVIOCSFF ioctl may be used to upload force feedback effects
0x16 EV_PWR Reserved for power events. Largely unused
0x17 EV_FF_STATUS Used for force-feedback capable devices.

 

Event code, contains a wide variety of different event type code

EV_KEY KEY_1, KEY_2, KEY_3…

EV_REL REL_X, REL_Y, REL_Z…

EV_ABS ABS_X, ABS_Y, ABS_Z…

And so on….

Event value, generated by the input devices hardware, such as key device drivers will get hardware status using kernel gpio framework (Assuming active low), 0 if pressed, and 1 if released.

 

Realization of the input device driver

input_dev structure to describe an input device

struct input_dev{

/* Export the information into user space, in the sysfs can be seen*/

const char *name;

const char *phys;

const char *uniq;

struct input_id id;

…………………

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];               /Input device supports bitmaps/

unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];          /The event code key device supports bitmaps/

……

}

evbit, bitmap of types of events supported by the device (EV_KEY, EV_REL, etc.)

keybit, bitmap of keys/buttons this device has        

Set the supported event types and event codes, which the input devices are capable of processing, usually we use set_bit() function to set rather than by direct assignment

Set supported event types (Support for key events)

set_bit(EV_KEY, input_dev->evbit);

Sets the event code support(Support press1)

set_bit(KEY_1, input_dev->keybit);

We can also directly call input_set_capability() to complete the assignment in a single step.

input_set_capability(input_dev,EV_KEY, KEY_1);

 

The kernel interface provides a set of functions for us to realize the input device driver

Allocation/Release of an input device:

struct input_dev* input_allocate_device(void)

void input_free_device(struct input_dev *dev)

input_allocate_device: After successful allocation will return a pointer to struct input_dev

Register and unregister input device

int input_register_device(struct input_dev*dev)

void input_unregister_device(struct input_dev*dev)

Registration function uses to input_dev register an input device in a core layer, cancellation is contrary. Parameter dev is input_allocate_device return value.

 

Report input events

Report key

void input_report_key(struct input_dev *dev, unsigned int code, int value)

Reports relative coordinates

void input_report_rel(struct input_dev *dev, unsigned int code, int value)

Report absolute coordinates

void input_report_abs(struct input_dev *dev, unsigned int code, int value)

Used to synchronize events to prevent data corruption

void input_sync(struct input_dev *dev)

 


Code:

Input Subsystem key-driven code, Hardware platform: s3c2440


#include <linux/input.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/kernel.h>

#include <linux/irq.h>

#include <linux/interrupt.h>

#include <mach/gpio.h>

#include <mach/regs-gpio.h>

#include <asm/irq.h>

#include <asm/io.h>

 

#define DEV_NAME “KEY1”

#define BUTTON_IRQ IRQ_EINT8

 

Static struct input_dev *button_dev;

 

Static irqreturn_t button_interrupt (int irq, void *p)

{

/*get pin value <down 0, up 1> */

intval = s3c2410_gpio_getpin(S3C2410_GPG(0));

input_report_key(button_dev,KEY_1, val);

input_sync(button_dev);

return IRQ_RETVAL(IRQ_HANDLED);

}

 

Static int __init button_init(void)

{

Int err;

/* Interrupt registration*/

if(request_irq(BUTTON_IRQ, button_interrupt,

IRQ_TYPE_EDGE_BOTH,DEV_NAME, NULL)) {

printk(KERN_ERR “cannot allocate irq”);

return- EBUSY;

}

/*allocate input_dev */

button_dev= input_allocate_device();

if(button_dev == NULL) {

printk(KERN_ERR “notenough memory\n”);

err= – ENOMEM;

gotoerr_free_irq;

}

/Set the input device supported event types and event code/

set_bit(EV_KEY,button_dev->evbit);

set_bit(KEY_1,button_dev->keybit);

 

/*Registration of input devices into the core */

err= input_register_device(button_dev);

if(err) {

printk(KERN_ERR “failed to register device\n”);

goto err_free_dev;

}

printk(“initialized\n”);

return0;

 

err_free_dev:

input_free_device(button_dev);

err_free_irq:

free_irq(BUTTON_IRQ,NULL);

return err;

}

 

static void __exit button_exit(void)

{

input_unregister_device(button_dev);

input_free_device(button_dev);

free_irq(BUTTON_IRQ,NULL);

}

module_init(button_init);

module_exit(button_exit);

MODULE_LICENSE(“Dual BSD/GPL”);


 

In the next upcoming session, we shall further have in-depth analysis of Input Subsystem elements and understand how event handlers and linked with the input device driver in core layer.

2 thoughts on “Linux Input subsystem – I

  1. Hi Dhruv , its a nice blog . Can u plz tell how does the application will interact with this driver. Probably a example code of Appl & Driver for the touch screen can give me a clear picture.
    Thanks in advance

    – Balaji

    Liked by 1 person

Leave a reply to Balaji Cancel reply