Reader small image

You're reading from  Linux Device Drivers Development

Product typeBook
Published inOct 2017
Reading LevelIntermediate
PublisherPackt
ISBN-139781785280009
Edition1st Edition
Languages
Right arrow
Author (1)
John Madieu
John Madieu
author image
John Madieu

John Madieu is an embedded Linux and kernel engineer living in Paris, France. His main activities consist of developing device drivers and Board Support Packages (BSPs) for companies in domains such as IoT, automation, transport, healthcare, energy, and the military. John is the founder and chief consultant at LABCSMART, a company that provides training and services for embedded Linux and Linux kernel engineering. He is an open source and embedded systems enthusiast, convinced that it is only by sharing knowledge that we can learn more. He is passionate about boxing, which he practiced for 6 years professionally, and continues to channel this passion through training sessions that he provides voluntarily.
Read more about John Madieu

Right arrow

Input Devices Drivers

Input devices are devices by which you can interact with the system. Such devices include buttons, keyboards, touchscreens, mouse, and so on. They work by sending events, caught and broadcast over the system by the input core. This chapter will explain each structure used by the input core to handle input devices. We will also see how you can manage events from the user space.

In this chapter, we will cover the following topics:

  • Inputting core data structures
  • Allocating and registering input devices, as well as the polled device family
  • Generating and reporting events to the input core
  • Input device from user space
  • Writing a driver example

Input device structures

First of all, the main file to include in order to interface with the input subsystem is linux/input.h:

#include <linux/input.h> 

Whatever type of input device it is, whatever type of event it sends, an input device is represented in the kernel as an instance of struct input_dev:

struct input_dev { 
  const char *name; 
  const char *phys; 
 
  unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; 
  unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; 
  unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; 
  unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; 
  unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; 
 
  unsigned int repeat_key; 
 
  int rep[REP_CNT]; 
  struct input_absinfo *absinfo; 
  unsigned long key[BITS_TO_LONGS(KEY_CNT)]; 
 
  int (*open)(struct input_dev *dev); 
  void (*close)(struct input_dev *dev); 
 
  unsigned int users; 
  struct device dev; 
 
  unsigned...

Allocating and registering an input device

Prior to registering and sending the event with an input device, it should be allocated with the input_allocate_device() function. In order to free the previously allocated memory for a non-registered input device, the input_free_device() function should be used. If the device has already been registered, input_unregister_device() should be used instead. Like every function where memory allocation is needed, we can use a resource-managed version of functions:

struct input_dev *input_allocate_device(void) 
struct input_dev *devm_input_allocate_device(struct device *dev) 
 
void input_free_device(struct input_dev *dev) 
static void devm_input_device_unregister(struct device *dev, 
                                         void *res) 
int input_register_device(struct input_dev *dev) 
void input_unregister_device(struct input_dev *dev...

Generating and reporting an input event

Device allocation and registration are essential, but they are not the main goal of an input device driver, which is designed to report even to the input core. Depending on the type of event your device can support, the kernel provides appropriate APIs to report them to the core.

Given an EV_XXX capable device, the corresponding report function would be input_report_xxx(). The following table shows a mapping between the most important event types and their report functions:

Event type

Report function

Code example

EV_KEY

input_report_key()

input_report_key(poll_dev->input, BTN_0, gpiod_get_value(ms-> reset_btn_desc) & 1);

EV_REL

input_report_rel()

input_report_rel(nunchuk->input, REL_X, (nunchuk->report.joy_x - 128)/10);

EV_ABS

input_report_abs()

input_report_abs(bma150->input, ABS_X, x_value...

User space interface

Every registered input device is represented by a /dev/input/event<X> char device, from which we can read the event from the user space. An application reading this file will receive event packets in the struct input_event format:

struct input_event { 
  struct timeval time; 
  __u16 type; 
  __u16 code; 
  __s32 value; 
} 

Let's see the meaning of each element in the structure:

  • time is the timestamp. It returns the time at which the event happened.
  • type is the event type, for example, EV_KEY for a key press or release, EV_REL for relative moment, or EV_ABS for an absolute one. More types are defined in include/linux/input-event-codes.h.
  • code is the event code, for example, REL_X or KEY_BACKSPACE; again a complete list is in include/linux/input-event-codes.h.
  • value is the value that the event carries. For the EV_REL event type, it carries...

Putting it all together

So far, we have described structures used when writing drivers for input devices, and how they can be managed from the user space:

  1. Allocate a new input device, according to its type, polled or not, using input_allocate_polled_device() or input_allocate_device().
  2. Fill in the mandatory fields (if necessary):
    • Specify the type of event the device supports by using the set_bit() helper macro on the input_dev.evbit field
    • Depending on the event type, EV_REL, EV_ABS, EV_KEY, or other, indicate code this device can report using either input_dev.relbit, input_dev.absbit, input_dev.keybit, or other
    • Specify input_dev.dev in order to set up a proper device tree
    • Fill abs_info if necessary
    • For polled devices, indicate at which interval the poll() function should be called:
  1. Write your open() function if necessary, in which you should prepare and set up the...

Summary

This chapter described the whole input framework, and highlighted the difference between polled and interrupt-driven input devices. Having reached the end of this chapter, you have gained the knowledge necessary to write a driver for any input driver, whatever its type, and whatever input event it supports. The user space interface was discussed too, and a sample was provided. The next chapter discusses another important framework, the RTC, which is a key element of time management in PCs as well as embedded devices.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Linux Device Drivers Development
Published in: Oct 2017Publisher: PacktISBN-13: 9781785280009
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
John Madieu

John Madieu is an embedded Linux and kernel engineer living in Paris, France. His main activities consist of developing device drivers and Board Support Packages (BSPs) for companies in domains such as IoT, automation, transport, healthcare, energy, and the military. John is the founder and chief consultant at LABCSMART, a company that provides training and services for embedded Linux and Linux kernel engineering. He is an open source and embedded systems enthusiast, convinced that it is only by sharing knowledge that we can learn more. He is passionate about boxing, which he practiced for 6 years professionally, and continues to channel this passion through training sessions that he provides voluntarily.
Read more about John Madieu