Open/DRIVER/INPUT/INPUT.C This is the core of the input code.
Found it
static int __init input_init (void)
{
Err = Class_register (&input_class); Registers a class that will appear in the Sys/class input directory after registration.
......
Err = Register_chrdev (input_major, "input", &input_fops), registering an INPUT device with a main device number of 13,
}
Open Input_fops
static const struct File_operations Input_fops = {
. Owner = This_module,
. open = Input_open_file,
};
Only one to register an open function in the kernel, then read,write, and so on should be registered, should be registered in the Input_open_file,
parsing static int input_open_file (struct inode *inode, struct file *file)
{
struct Input_handler *handler = Input_table[iminor (inode) >> 5]; Assigns a member of the input_table array to handler, which is analyzed in detail below
if (!handler | |!) ( New_fops = Fops_get (handler->fops))) Gets the file_operations structure in handler
Return-enodev;
Old_fops = file->f_op;
File->f_op = New_fops;
Err = New_fops->open (inode, file); Open this handler->fops->open function
}
Q 1:input_table[iminor (inode) >> 5] This array is someone who assigns a value.
int Input_register_handler (struct Input_handler *handler)
{
Init_list_head (&handler->h_list);
Input_table[handler->minor >> 5] = handler; Assigns the handler to the Input_table array, and the position is divided by this device number by 32.
List_add_tail (&handler->node, &input_handler_list); Add this handler node to the Input_handler_list list
List_for_each_entry (Dev, &input_dev_list, node) iterates through the Input_dev devices in the Input_dev_list list at once, then matches the handler that are passed in, looking for input_ Is there a device in Dev_list that supports this handler?
Input_attach_handler (Dev, handler); The exact matching method will be analyzed in detail next
}
Question 2: Then who will call Input_register_handler, which is where handler comes from
Search to get
EVBUG.C (drivers\input): 106:return Input_register_handler (&evbug_handler);
EVDEV.C (drivers\input): 745:return Input_register_handler (&evdev_handler);
Input.c (drivers\input): 1193:int input_register_handler (struct Input_handler *handler)
Input.c (drivers\input): 1219:export_symbol (Input_register_handler);
Input.h (include\linux): 1130:int input_register_handler (struct input_handler *);
JOYDEV.C (drivers\input): 647:return Input_register_handler (&joydev_handler);
KEYBOARD.C (Drivers\char): 1367:error = Input_register_handler (&kbd_handler);
----= Input_register_handler (&kbd_handler); Matches (1 in 1 files)----
KEYBOARD.C (Drivers\char): 1367:error = Input_register_handler (&kbd_handler);
Then open the KEYBOARD.C, take it as an example, and analyze how this is registered.
static struct Input_handler Kbd_handler = {
. event = Kbd_event,
. connect = Kbd_connect,
. Disconnect = Kbd_disconnect,
. Start = Kbd_start,
. Name = "KBD",
. id_table = Kbd_ids,
};
int __init kbd_init (void)
{
Error = Input_register_handler (&kbd_handler);
}
Actually, it is. Kbd_handler This structure is passed to input_table;
Let's summarize:
int __init kbd_init (void)->error = Input_register_handler (&kbd_handler)
{Input_table[handler->minor >> 5] = handler;
List_add_tail (&handler->node, &input_handler_list);
List_for_each_entry (Dev, &input_dev_list, node)
Input_attach_handler (Dev, handler);
}
Analyze how to match the Input_attach_handler (Dev, Kbd_hander)
{
id = input_match_device (handler->id_table, dev); If the match returns an ID successfully
Error = Handler->connect (handler, Dev, id), then the device and Kbd_handler are connected based on the returned ID, and the Connect function is Kbd_handler->kbd_ Connect
}
Next detailed analysis Input_match_device
{
for (; Id->flags | | id->driver_info; id++) {
if (id->flags & Input_device_id_match_bus)
if (id->bustype! = Dev->id.bustype)
continue;
.......
For handler->id->flags, compare the different types if the comparison succeeds
Enter the following macro comparison, otherwise enter the next ID
Match_bit (Evbit, Ev_max);
.............
The type of event supported by the position comparison, only if all unmatched successes are successfully returned, otherwise enter the next ID
return ID;
}
return NULL;
}
If the match succeeds, it will enter the connection, analyze Kbd_connect
static int kbd_connect (struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
{
struct Input_handle *handle; define a Input_hanlde pointer
handle = Kzalloc (sizeof (struct input_handle), Gfp_kernel), allocating input_handle structural body space
Handle->dev = dev; make dev in assigned handle point and handler match Input_dev
Handle->handler = handler; make handler in handle point and Input_dev match Input_handler
Handle->name = "KBD";
Error = Input_register_handle (handle); Register this newly assigned handle;
Error = Input_open_device (handle);
}
Continue analysis
int Input_register_handle (struct input_handle *handle)
{
struct Input_handler *handler = handle->handler;
List_add_tail (&handle->d_node, &handle->dev->h_list); Hang the Handle->d_node on the input_dev->h_list.
List_add_tail (&handle->h_node, &handler->h_list); Handle->h_node Mount Handler->h_list on
This allows the handle to be found through h_list in Input_handler and then handle->dev to find a matching Input_dev
You can also find Handl by H_list in Input_dev, and then find a matching input_handler by Handle->handler
So Input_handler,input
if (Handler->start)
Handler->start (handle);
return 0;
} Continue Analysis
int Input_open_device (struct input_handle *handle)
{
struct Input_dev *dev = handle->dev;
int err;
Handle->open++;//handle Open Count plus 1, note and evdev the difference between open
if (!dev->users++ && dev->open)
Err = Dev->open (dev);//If this input-dev does not have a process reference and defines the open
method, you call the Open method,
if (err)//retval=1 description, did not open successfully,
handle->open--;
}
Summing up the role of Connect is to create a new struct input_handle based on the matching successful Input_dev and Input_handler, and then assign the dev and handler in the struct to Input_dev and input_ Handler
In this way, the Input_dev and the Input_hanlder can be connected by input_handle the structure;
static int __init input_init (void)->err = Register_chrdev (input_major, "input", &input_fops)->input_fops- > Input_open_file
{struct Input_handler *handler = Input_table[iminor (inode) >> 5];
if (!new_fops->open) {
Fops_put (New_fops);
Return-enodev;
}
Err = New_fops->open (inode, file), this open function is the open in Kbd_handler FoPs, which is not initialized fops in this keyboard;
}
For registered input devices:
Input_register_device
Put the list
List_add_tail (&dev->node, &input_dev_list);
For each of the Input_handler, call Input_attach_handler
List_for_each_entry (handler, &input_handler_list, node)
Input_attach_handler (Dev, handler); Judging by Input_handler's id_table, can you support this input_dev?
Input_attach_handler
id = input_match_device (handler->id_table, Dev);
Error = Handler->connect (handler, dev, id);
Similar to Input_handler, we analyze ourselves
Kernel Input Subsystem Analysis