1, a first version of the key driver: day07 / 04
// kernel module of the basic requirements
init.h the module.h the LICENSE
struct the cdev btn_cdev;
btn_read (...)
{
// blocked
queue sleep
// nonblocking
will copy data to user space
}
struct the file_operations btn_fops =
{
.Open
.release // exclusive access device race
.read = btn_read // wait queue
}
timer_func / delay_work_func ()
{
determines which key is triggered
by reading electrical pins Analyzing the trigger is pressed flat position or release trigger
to save key
wake sleeping processes
}
btn_isr ()
{
delay jitter or the bottom half of the way to debounce
}
int the __init btn_drv_init (void)
{
Application device number register
initialization operation of the set of functions cdev //
Register cdev
automatically generated device file
registering interrupt
}
void btn_drv_exit The __exit (void)
{
}
the module_init (btn_drv_init);
the module_exit (btn_drv_exit)
above procedures problems:
1) the normalized key value problem
2) key buffer
circular buffer queue
attention to solve a race condition
3) hold the button
to open a new timer key after pressing the key save
the timer time to time to keep a key buffer key
until you release the key to stop the timer
2, the second version of the key drivers: input subsystem
2.1 What is the input subsystem
with the linux kernel to support the growing number of hardware
found in a class of devices, not only the input output: keyboard mouse touch screen ...
this type of equipment in the realization of the driver must resolve
device number
cdev
Device automatically creates a file
of the key buffer
hold the
... ...
core designer of the type of equipment and hardware independent code implemented in the kernel finished
the portion of the code is referred to as input subsystem
2.2 input subsystem acting
driving section engineer in achieving a particular input device driver
can reuse the part of the code, the code focused on driving-related programming hardware
to shorten the time of programming input device drivers
use 2.3 input subsystem (the portion of the code multiplexing method )
the INPUT subsystem core file: drivers / input / input.c
core data structure
struct input_dev
{
name
// the device will identify which events trigger which events will not
evbit
/ * report which identifies EV_KEY key code does not report what
buttons encoding * /
keybit
. . .
}
Using the steps:
1) apply a variable input_dev (kmalloc)
* input_allocate_device input_dev struct (void)
2) variable initialization input_dev
3) registered input_dev variable
int input_register_device (struct input_dev * dev)
4) hardware operations
registered interrupt
remove jitter
which key trigger judgment
judgment is to press the trigger or trigger the release of
5) report events (save key wake the sleeping process)
void input_event (struct input_dev * dev,
unsigned int type, unsigned int code, int value)
dev, who report
type, report the event type
code, when different types of events is not the same meaning
if when EV_KEY , its meaning is the key code
value, different event types different meaning
if EV_KEY when, on behalf of the trigger or press release trigger
0, release trigger
1, press the trigger
6) cancellation input_dev variable
void input_unregister_device (struct input_dev * dev)
7) release input_dev variable
void input_free_device (struct input_dev * dev)
Note: After installing the module corresponds to experiment to find a device file how?
There are two ways, may determine the corresponding device file
. 1) LS / dev / INPUT / * Event
the insmod btn_drv.ko
LS / dev / INPUT / * Event
2) CAT / proc / Bus / INPUT / Devices
verification: Driver effective of
hexdump / dev / input / event5
serial No. second code value microseconds type
0000000 d7c4 54a4 1e63 0001 0001 0067 0001 0000
0000010 0001 0000 0000 d7c4 54a4 1e70 0000 0000
0.00002 million d7c4 54a4 1BFC 0004 0001 0067 0000 0000
0000030 d7c4 54a4 1c00 0004 0000 0000 0000 0000
requirements class: possible key driver 7 according to the above steps (can read)
and higher requirements: Study linux subsystem code
Drivers / INPUT / to the input.c
input_init ()
{
// main function operating device number corresponding to a set of device 13 is input_fops
the register_chrdev (INPUT_MAJOR, "INPUT", & input_fops);
}
Open ( "/ dev / the INPUT / event5", ....)
---------------------------------- ---------
SYS_OPEN ()
{
struct File btn_file; // global
input_fops.open (the inode, & btn_file) input_open_file //
{
// the minor number corresponds to locate the device Handler
// find it for a key device the handler is evdev_handler
handler input_table = [iminor (the inode) >>. 5];
// evdev_handler the recorded address set operation function returns
new_fops = fops_get (handler-> FOPS)
// handler to modify btn_file.f_op recorded the set of functions operating
File-> = new_fops the f_op;
}
}
#include " ../../global.h " #include <Linux / Input.h> #include <Linux / interrupt.h> #include <Linux / gpio.h> #include <Mach / platform.h> static struct input_dev btn_input * = NULL; typedef struct btn_desc { char * name; // name int IRQ; // interrupt number unsigned Short code; // key code value int GPIO; // pin numbers } btn_desc_t; btn_desc_t buttons [] = { { "up", IRQ_GPIO_A_START+28, KEY_UP, PAD_GPIO_A+28}, {"down", IRQ_GPIO_B_START+30, KEY_DOWN, PAD_GPIO_B+30}, {"left", IRQ_GPIO_B_START+31, KEY_LEFT, PAD_GPIO_B+31}, {"right", IRQ_GPIO_B_START+9, KEY_RIGHT, PAD_GPIO_B+9}, }; struct timer_list btn_timer; irqreturn_t btn_isr(int irq, void *dev) { / * pass key description * / btn_timer.data = (unsigned Long ) dev; mod_timer ( & btn_timer, of jiffies + HZ / 100 ); return IRQ_HANDLED; } void btn_timer_func (unsigned Long Data) { int STAT = 0 ; / * get the keys which triggered * / btn_desc_t * pData = (btn_desc_t * ) the Data; / * judge is to press the trigger or trigger release * / STAT = gpio_get_value (pdata-> the GPIO); / * 5 report events (save key wake up the sleeping process) * / input_event (btn_input, EV_KEY, pData -> code,! STAT); input_event (btn_input, EV_SYN, 0 , 0 ); } int the __init btn_drv_init ( void ) { int I = 0 ; int RET = 0 ; / * . 1 Application input_dev variable * / btn_input = input_allocate_device (); / * 2 input_dev initialize variables * / btn_input -> name = " mybuttons " ; // segment error //strcpy (btn_input-> name, "mybuttons"); / * 2.1 Configuring the device will report the event type * / __set_bit (EV_SYN, btn_input -> evbit); __set_bit (EV_KEY, btn_input -> evbit); __set_bit (EV_REP, btn_input -> evbit); / * report the 2.2 configuration EV_KEY key code * / for (; I <ARRAY_SIZE (buttons); I ++ ) { __set_bit (buttons [I] .code, btn_input -> keybit); } / * . 3 Register input_dev variables * / RET = input_register_device (btn_input); / * . 4 hardware operations * / for (I =0; i<ARRAY_SIZE(buttons); i++) { ret = request_irq(buttons[i].irq, btn_isr, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, buttons[i].name, buttons+i); } init_timer(&btn_timer); btn_timer.function = btn_timer_func; return 0; } void __exit btn_drv_exit(void) { int i = 0; del_timer(&btn_timer); for(; i<ARRAY_SIZE(buttons); i++) { free_irq(buttons[i].irq, buttons+i); } /*6注销input_dev变量*/ input_unregister_device(btn_input); /*7释放input_dev变量空间*/ input_free_device(btn_input); } module_init(btn_drv_init); module_exit(btn_drv_exit);
#include <stdio.h> #include <fcntl.h> #include <linux/input.h> //struct input_event key_info; struct key { long sec; long usec; unsigned short type; unsigned short code; int val; }key_info; int main(void) { int fd = open("/dev/input/event5", O_RDONLY); while(1) { read(fd, &key_info, sizeof(key_info)); if(key_info.type == EV_KEY) { printf("type=%d code=%d value=%d\n", key_info.type, key_info.code, key_info.val); } } close(fd); return 0; }