Input Subsystem - Kernel Driver - Android

android-goldfish-5.4-dev
AOSP > Documentation > Core Topics > Input

https://www.kernel.org/doc/Documentation/input/input.txt
https://www.kernel.org/doc/Documentation/input/event-codes.txt
https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt


1. Input subsystem related definitions

Insert image description here

1.1 Code location

Android_Kernel\goldfish\drivers\input
Android_Kernel\goldfish\include\linux\input.hDefines a set of standard event types and codes
Insert image description here

1.2 input_dev structure: represents the input device

Name: The name of the device
Phys: The physical path to the device in the system hierarchy
Uniq: The unique identifier of the device (if the device has one)
Id: The Id of the device ( struct input_Id)
Propbit: A bitmap of device properties and quirks.
Evbit: Bitmap of event types supported by the device ( EV_KEY,, EV_RELetc.)
Keybit: Bitmap that this device has Relbit: Relative axis bitmap of the device keys/buttonsAbsbit : Absolute axis bitmap of the device Mscbit: Bitmap of miscellaneous events supported by the device Ledbit: LED bitmap present on the device Sndbit: Sound effect bitmap supported by the device Ffbit: Force feedback effect bitmap supported by the device Swbit: Switch bitmap present on the device Hint_events_per_packet: The average number of events generated by the device in a data packet ( / of events between). Used by event handlers to estimate the buffer size required to accommodate the event. Keycodemax: The size of the key code table Keycodesize:







EV_SYNSYN_REPORT

The size of the element in the keycode table
Keycode: The scancode to keycode mapping for this device
Getkeycode: Optional legacy method for retrieving the current keymap.
Setkeycode: Optional method to change the current key mapping, used to implement sparse key mapping. If not provided, the default mechanism will be used. This method is called while event_lock is held and therefore cannot be hibernated
Ff: The force feedback structure associated with the device if the device supports force feedback effects
Poller: The poller structure associated with the device if the device is set to use polling mode
Repeat_key : stores the key code of the last key pressed; used to implement automatic software supervision
Timer: timer for software automatic recovery
Rep: current value of automatic playback parameters (delay, rate)
Mt: pointer to multi-touch state
Absinfo: contains absolute axis &struct input_AbsinfoElement array of information (current value, minimum value, maximum value, flat value, blur value, resolution)
Key: reflects the current state of the device key/button
Led: reflects the current state of the device Led
Snd: reflects the current state of the sound effect
Sw: Reflects the current state of the device switch
Open: when the first user callsinput_Open_device()This method is called when . The driver must prepare the device to start generating events (start polling thread, request IRQ, submit URB, etc.)
Close: This method is called when the last user calls input_Close_device().
Flush: clear the device. Most commonly used to eliminate the force feedback effects loaded into a device when disconnected from the device
Event: An event handler for events sent to the device, such as EV_LEDor EV_SND. The device should perform the requested action (turn on LED, play sound, etc.) Call protected
Event_lock: and cannot sleep
Grab: currently grabs the device's input handle (via EVIOCGRAB ioctl). When a handle grabs a device, it becomes the sole receiver of all input events from that device.
Event_lock: This spinlock is acquired when input corenew events for the device are received and processed ( in). Code that accesses and/or modifies device parameters (such as or , , etc.) must use this lock input_Event()after the device is registered with the input core . Mutex: Serializes calls to , and methods Users: Stores the number of users who have opened this device (input handlers). and use this to make sure it is only called when the first user opens the device and when the last user closes the devicekeymapabsminabsmaxabsfuzz
open()close()flush()
input_open_device()input_close_device()dev->open()dev->close()
Going_away: Mark the device being logged out and use -ENODEVto cause input_open_device*()failure.
Dev: Driver model view for this device
H_list: List of input handles associated with the device. When accessing the list, you must hold dev->mutex
Node: used to place the device on input_dev_listNum_vals
: the number of values ​​queued in the current frame
Max_vals: the maximum number of values ​​queued in the frame
Vals: the array of values ​​queued in the current frame
Devres_managed: represents the use of the device Devres框架for management , no explicit unregistration or release is required.
Timestamp:input_set_Timestamp stores the timestamp of settings called by the driver

include/linux/input.h

struct input_dev {
    
    
	const char *name;
	const char *phys;
	const char *uniq;
	struct input_id id;

	unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

	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 long ledbit[BITS_TO_LONGS(LED_CNT)];
	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

	unsigned int hint_events_per_packet;

	unsigned int keycodemax;
	unsigned int keycodesize;
	void *keycode;

	int (*setkeycode)(struct input_dev *dev,
			  const struct input_keymap_entry *ke,
			  unsigned int *old_keycode);
	int (*getkeycode)(struct input_dev *dev,
			  struct input_keymap_entry *ke);

	struct ff_device *ff;

	struct input_dev_poller *poller;

	unsigned int repeat_key;
	struct timer_list timer;

	int rep[REP_CNT];

	struct input_mt *mt;

	struct input_absinfo *absinfo;

	unsigned long key[BITS_TO_LONGS(KEY_CNT)];
	unsigned long led[BITS_TO_LONGS(LED_CNT)];
	unsigned long snd[BITS_TO_LONGS(SND_CNT)];
	unsigned long sw[BITS_TO_LONGS(SW_CNT)];

	int (*open)(struct input_dev *dev);
	void (*close)(struct input_dev *dev);
	int (*flush)(struct input_dev *dev, struct file *file);
	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

	struct input_handle __rcu *grab;

	spinlock_t event_lock;
	struct mutex mutex;

	unsigned int users;
	bool going_away;

	struct device dev;

	struct list_head	h_list;
	struct list_head	node;

	unsigned int num_vals;
	unsigned int max_vals;
	struct input_value *vals;

	bool devres_managed;

	ktime_t timestamp[INPUT_CLK_MAX];
};

1.3 input_handler结构体:struct input_handler - implements one of interfaces for input devices

Private: Driver-specific data
Event: Event handler. This method is called by the input core while disabling interrupts and holding the dev->event_lock spinlock, so it may not sleep
the Events: event sequence handler. This method is called by the input core while disabling interrupts and keeping the dev->event_lock spinlock, so it may not sleep
Filter: Similar to event; Detach normal event handlers with " Filter".
Match: Called after comparing the id of the device and the handler id_tablefor fine-grained matching between the device and the handler
Connect: Called when attaching the handler to the input device
Disconnect: Disconnect the handler from the input device
* *Start:**Start the handler for the given handle. This function is connect()called by the input core after the method, and also when the process that "grabbed" the device releases it
Legacy_minors: Set to Minor by a driver using the legacy minor range %true
: The 32 of the device that this driver can provide Start of the legacy secondary range
Name: The name of the handler, as shown in /proc/bus/input/handlersId_table
:input_device_Id Pointer to the tables this driver can handle
H_list:A list of input handlers associated with
the Node: used to place the driver onto, input_handler_listattach


Input handlersto input devicesand create input handles. There may be multiple handlers connected to any given input device simultaneously. All of them will get a copy of the input events generated by the device. Use the exact same structure to implement the input filter. Input coreFilters are allowed to run first, and if any filter indicates that the event should be filtered (by filter()returning from its method %true), the event will not be passed to the regular handler. Note that the input core serializes calls to connect()the and disconnect()methods.

include/linux/input.h

struct input_handler {
    
    

	void *private;

	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
	void (*events)(struct input_handle *handle,
		       const struct input_value *vals, unsigned int count);
	bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
	bool (*match)(struct input_handler *handler, struct input_dev *dev);
	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
	void (*disconnect)(struct input_handle *handle);
	void (*start)(struct input_handle *handle);

	bool legacy_minors;
	int minor;
	const char *name;

	const struct input_device_id *id_table;

	struct list_head	h_list;
	struct list_head	node;
};

1.4 input_handle structure: link input devices and input handlers

One input_devreported event can be input_handlerreceived and processed by multiple, and one input_handlercan also process multiple input_devreported events, so that multiple input_devand multiple input_handlermay form an intertwined network. In this case, a bridge is needed to build the connection between the two. Function calls on both sides can be made through this "intermediary", which input_handleis this bridge.

Private: Handler-specific data
Open: Counter showing whether the handle is "open", i.e. events should be delivered from its device
Name: The name given to the handle by the handler that created it
Dev: The input device to which the handle is connected
Handler: The handler through which the handle is connected A handle for the device to work with
D_node: used to place the handle in the device's additional handle list
H_node: used to place the handle in the handler's handle list from which to get events

include/linux/input.h

struct input_handle {
    
    

	void *private;

	int open;
	const char *name;

	struct input_dev *dev;
	struct input_handler *handler;

	struct list_head	d_node;
	struct list_head	h_node;
};

2. Input core initialization

include/linux/input.h
drivers/input/input.c

  • sybsys_initcallRegister and set the startup level to ensure that its initialization will be earlier than the registration of input device and input_handler
  • module_initway to register input设备andinput_handler
subsys_initcall(input_init);
module_exit(input_exit);

2.1 input_init initialization entry

drivers/input/input.c

class_register(&input_class)Input class registration is /sys/class
input_proc_init();mainly used for information viewing and input_handlerfile creation to register character devices.devicesProc
register_chrdev_region(MKDEV(INPUT_MAJOR, 0), INPUT_MAX_CHAR_DEVICES, "input")

static int __init input_init(void)
{
    
    
	int err;

	err = class_register(&input_class);
	if (err) {
    
    
		pr_err("unable to register input_dev class\n");
		return err;
	}

	err = input_proc_init();
	if (err)
		goto fail1;

	err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
				     INPUT_MAX_CHAR_DEVICES, "input");
	if (err) {
    
    
		pr_err("unable to register char major %d", INPUT_MAJOR);
		goto fail2;
	}

	return 0;

 fail2:	input_proc_exit();
 fail1:	class_unregister(&input_class);
	return err;
}

2.1.1 class_register

class_register(&input_class)Input class registration is placed in /sys/class
Insert image description here
the Linux kernel API class_register|Geek Notes

drivers/input/input.c

struct class input_class = {
    
    
	.name		= "input",
	.devnode	= input_devnode,
};
EXPORT_SYMBOL_GPL(input_class);

include/linux/device.h
drivers/base/class.c

/* This is a #define to keep the compiler from merging different
 * instances of the __key variable */
#define class_register(class)			\
({
      
      						\
	static struct lock_class_key __key;	\
	__class_register(class, &__key);	\
})

2.1.2 input_proc_init

input_proc_init()Mainly used input_handlerfor devicesinformation viewing and Procfile creation
Insert image description here

static int __init input_proc_init(void)
{
    
    
	struct proc_dir_entry *entry;

	proc_bus_input_dir = proc_mkdir("bus/input", NULL);
	if (!proc_bus_input_dir)
		return -ENOMEM;

	entry = proc_create("devices", 0, proc_bus_input_dir,
			    &input_devices_fileops);
	if (!entry)
		goto fail1;

	entry = proc_create("handlers", 0, proc_bus_input_dir,
			    &input_handlers_fileops);
	if (!entry)
		goto fail2;

	return 0;

 fail2:	remove_proc_entry("devices", proc_bus_input_dir);
 fail1: remove_proc_entry("bus/input", NULL);
	return -ENOMEM;
}

2.1.3 register_chrdev_region

register_chrdev_region(MKDEV(INPUT_MAJOR, 0), INPUT_MAX_CHAR_DEVICES, "input")Register character device; create an "input" device with primary device 13

include/uapi/linux/major.h

#define INPUT_MAJOR		13

drivers/input/input.c

#define INPUT_MAX_CHAR_DEVICES		1024

fs/char_dev.c

/**
 * register_chrdev_region() - register a range of device numbers
 * @from: the first in the desired range of device numbers; must include
 *        the major number.
 * @count: the number of consecutive device numbers required
 * @name: the name of the device or driver.
 *
 * Return value is zero on success, a negative error code on failure.
 */
int register_chrdev_region(dev_t from, unsigned count, const char *name)
{
    
    
	struct char_device_struct *cd;
	dev_t to = from + count;
	dev_t n, next;

	for (n = from; n < to; n = next) {
    
    
		next = MKDEV(MAJOR(n)+1, 0);
		if (next > to)
			next = to;
		cd = __register_chrdev_region(MAJOR(n), MINOR(n),
			       next - n, name);
		if (IS_ERR(cd))
			goto fail;
	}
	return 0;
fail:
	to = n;
	for (n = from; n < to; n = next) {
    
    
		next = MKDEV(MAJOR(n)+1, 0);
		kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
	}
	return PTR_ERR(cd);
}

3. input_dev device registration

3.1 input_allocate_device: allocate input_dev structure memory

input_allocate_device- allocate memory for the new input device
return a prepared structure input_devor %NULL.
Note: Use input_free_device()Release unregistered devices; input_unregister_device()applies to registered devices.

drivers/input/input.c

struct input_dev *devm_input_allocate_device(struct device *dev)
{
    
    
	struct input_dev *input;
	struct input_devres *devres;

	devres = devres_alloc(devm_input_device_release,
			      sizeof(*devres), GFP_KERNEL);
	if (!devres)
		return NULL;

	input = input_allocate_device();
	if (!input) {
    
    
		devres_free(devres);
		return NULL;
	}

	input->dev.parent = dev;
	input->devres_managed = true;

	devres->input = input;
	devres_add(dev, devres);

	return input;
}
EXPORT_SYMBOL(devm_input_allocate_device);
/**
 * input_allocate_device - allocate memory for new input device
 *
 * Returns prepared struct input_dev or %NULL.
 *
 * NOTE: Use input_free_device() to free devices that have not been
 * registered; input_unregister_device() should be used for already
 * registered devices.
 */
struct input_dev *input_allocate_device(void)
{
    
    
	static atomic_t input_no = ATOMIC_INIT(-1);
	struct input_dev *dev;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (dev) {
    
    
		dev->dev.type = &input_dev_type;
		dev->dev.class = &input_class;
		device_initialize(&dev->dev);
		mutex_init(&dev->mutex);
		spin_lock_init(&dev->event_lock);
		timer_setup(&dev->timer, NULL, 0);
		INIT_LIST_HEAD(&dev->h_list);
		INIT_LIST_HEAD(&dev->node);

		dev_set_name(&dev->dev, "input%lu",
			     (unsigned long)atomic_inc_return(&input_no));

		__module_get(THIS_MODULE);
	}

	return dev;
}

3.2 input_register_device: Register device with input core

This function registers the device to input core. Before registering, a device must be assigned input_allocate_device()and all of its capabilities included. If the function fails, the release device must be used input_free_device(). Once the device has successfully registered, it can be input_unregister_device()deregistered using; in this case it should not be called input_free_device(). Note that this function is also used to register managed input devices (using devm_input_allocate_device()assigned devices). Such managed input devices do not need to be explicitly unregistered or released, their removal is controlled by the devres infrastructure. It's also worth noting that deleting a managed input device is internally a two-step process: a registered managed input device is first unregistered, but remains in memory, and calls can still be handled (although the events are not delivered anywhere) input_event(). Later, when the devres stack is unwound to the point where device allocation is made, the managed input device is released.

  • device_add(&dev->dev): Register the device as a linux device
  • list_add_tail(&dev->node, &input_dev_list): Add device to linux kernel global listinput_dev_list
  • list_for_each_entry(handler, &input_handler_list, node)
    input_attach_handler(dev, handler);:Traverse input_handler_listand find your own for the devicehandler

drivers/input/input.c

int input_register_device(struct input_dev *dev)
{
    
    
	struct input_devres *devres = NULL;
	struct input_handler *handler;
	unsigned int packet_size;
	const char *path;
	int error;

	if (test_bit(EV_ABS, dev->evbit) && !dev->absinfo) {
    
    
		dev_err(&dev->dev,
			"Absolute device without dev->absinfo, refusing to register\n");
		return -EINVAL;
	}

	if (dev->devres_managed) {
    
    
		devres = devres_alloc(devm_input_device_unregister,
				      sizeof(*devres), GFP_KERNEL);
		if (!devres)
			return -ENOMEM;

		devres->input = dev;
	}

	/* Every input device generates EV_SYN/SYN_REPORT events. */
	__set_bit(EV_SYN, dev->evbit);

	/* KEY_RESERVED is not supposed to be transmitted to userspace. */
	__clear_bit(KEY_RESERVED, dev->keybit);

	/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
	input_cleanse_bitmasks(dev);

	packet_size = input_estimate_events_per_packet(dev);
	if (dev->hint_events_per_packet < packet_size)
		dev->hint_events_per_packet = packet_size;

	dev->max_vals = dev->hint_events_per_packet + 2;
	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
	if (!dev->vals) {
    
    
		error = -ENOMEM;
		goto err_devres_free;
	}

	/*
	 * If delay and period are pre-set by the driver, then autorepeating
	 * is handled by the driver itself and we don't do it in input.c.
	 */
	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
		input_enable_softrepeat(dev, 250, 33);

	if (!dev->getkeycode)
		dev->getkeycode = input_default_getkeycode;

	if (!dev->setkeycode)
		dev->setkeycode = input_default_setkeycode;

	if (dev->poller)
		input_dev_poller_finalize(dev->poller);

	error = device_add(&dev->dev);
	if (error)
		goto err_free_vals;

	path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
	pr_info("%s as %s\n",
		dev->name ? dev->name : "Unspecified device",
		path ? path : "N/A");
	kfree(path);

	error = mutex_lock_interruptible(&input_mutex);
	if (error)
		goto err_device_del;

	list_add_tail(&dev->node, &input_dev_list);

	list_for_each_entry(handler, &input_handler_list, node)
		input_attach_handler(dev, handler);

	input_wakeup_procfs_readers();

	mutex_unlock(&input_mutex);

	if (dev->devres_managed) {
    
    
		dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
			__func__, dev_name(&dev->dev));
		devres_add(dev->dev.parent, devres);
	}
	return 0;

err_device_del:
	device_del(&dev->dev);
err_free_vals:
	kfree(dev->vals);
	dev->vals = NULL;
err_devres_free:
	devres_free(devres);
	return error;
}
EXPORT_SYMBOL(input_register_device);

3.3 Case: "gpio-keys" device registration

Insert image description here

drivers/input/keyboard/gpio_keys.c
"gpio-keys": For other cases, please view the following directories:platform_driver_register(&gpio_keys_device_driver) -> gpio_keys_probe -> devm_input_allocate_device -> input_register_device



drivers/input/gameport
drivers/input/joystick
drivers/input/keyboard
drivers/input/misc
drivers/input/mouse
drivers/input/rmi4
drivers/input/serio
drivers/input/tablet
drivers/input/touchscreen

static struct platform_driver gpio_keys_device_driver = {
    
    
	.probe		= gpio_keys_probe,
	.shutdown	= gpio_keys_shutdown,
	.driver		= {
    
    
		.name	= "gpio-keys",
		.pm	= &gpio_keys_pm_ops,
		.of_match_table = gpio_keys_of_match,
		.dev_groups	= gpio_keys_groups,
	}
};

static int __init gpio_keys_init(void)
{
    
    
	return platform_driver_register(&gpio_keys_device_driver);
}
static int gpio_keys_probe(struct platform_device *pdev)
{
    
    
	struct device *dev = &pdev->dev;
	const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
	struct fwnode_handle *child = NULL;
	struct gpio_keys_drvdata *ddata;
	struct input_dev *input;
	int i, error;
	int wakeup = 0;

	if (!pdata) {
    
    
		pdata = gpio_keys_get_devtree_pdata(dev);
		if (IS_ERR(pdata))
			return PTR_ERR(pdata);
	}

	ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons),
			     GFP_KERNEL);
	if (!ddata) {
    
    
		dev_err(dev, "failed to allocate state\n");
		return -ENOMEM;
	}

	ddata->keymap = devm_kcalloc(dev,
				     pdata->nbuttons, sizeof(ddata->keymap[0]),
				     GFP_KERNEL);
	if (!ddata->keymap)
		return -ENOMEM;

	input = devm_input_allocate_device(dev);
	if (!input) {
    
    
		dev_err(dev, "failed to allocate input device\n");
		return -ENOMEM;
	}

	ddata->pdata = pdata;
	ddata->input = input;
	mutex_init(&ddata->disable_lock);

	platform_set_drvdata(pdev, ddata);
	input_set_drvdata(input, ddata);

	input->name = pdata->name ? : pdev->name;
	input->phys = "gpio-keys/input0";
	input->dev.parent = dev;
	input->open = gpio_keys_open;
	input->close = gpio_keys_close;

	input->id.bustype = BUS_HOST;
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0100;

	input->keycode = ddata->keymap;
	input->keycodesize = sizeof(ddata->keymap[0]);
	input->keycodemax = pdata->nbuttons;

	/* Enable auto repeat feature of Linux input subsystem */
	if (pdata->rep)
		__set_bit(EV_REP, input->evbit);

	for (i = 0; i < pdata->nbuttons; i++) {
    
    
		const struct gpio_keys_button *button = &pdata->buttons[i];

		if (!dev_get_platdata(dev)) {
    
    
			child = device_get_next_child_node(dev, child);
			if (!child) {
    
    
				dev_err(dev,
					"missing child device node for entry %d\n",
					i);
				return -EINVAL;
			}
		}

		error = gpio_keys_setup_key(pdev, input, ddata,
					    button, i, child);
		if (error) {
    
    
			fwnode_handle_put(child);
			return error;
		}

		if (button->wakeup)
			wakeup = 1;
	}

	fwnode_handle_put(child);

	error = input_register_device(input);
	if (error) {
    
    
		dev_err(dev, "Unable to register input device, error: %d\n",
			error);
		return error;
	}

	device_init_wakeup(dev, wakeup);

	return 0;
}

4. input_handler registration

4.1 Common input_handler

Generally input_handler注册it will be input_dev设备注册before, common input_handler:

  • evdev_handler: Respond to most events, default input processing events
  • mousedev_handler: Mouse input event
  • joydev_handler: Game remote sensing input event
  • kbd_handler:Keyboard event
  • input_leds_handler
  • apmpower_handler

drivers/input/evdev.c

static struct input_handler evdev_handler = {
    
    
	.event		= evdev_event,
	.events		= evdev_events,
	.connect	= evdev_connect,
	.disconnect	= evdev_disconnect,
	.legacy_minors	= true,
	.minor		= EVDEV_MINOR_BASE,
	.name		= "evdev",
	.id_table	= evdev_ids,
};

drivers/tty/vt/keyboard.c

static struct input_handler kbd_handler = {
    
    
	.event		= kbd_event,
	.match		= kbd_match,
	.connect	= kbd_connect,
	.disconnect	= kbd_disconnect,
	.start		= kbd_start,
	.name		= "kbd",
	.id_table	= kbd_ids,
};

drivers/input/mousedev.c

static struct input_handler mousedev_handler = {
    
    
	.event		= mousedev_event,
	.connect	= mousedev_connect,
	.disconnect	= mousedev_disconnect,
	.legacy_minors	= true,
	.minor		= MOUSEDEV_MINOR_BASE,
	.name		= "mousedev",
	.id_table	= mousedev_ids,
};

drivers/input/joydev.c

static struct input_handler joydev_handler = {
    
    
	.event		= joydev_event,
	.match		= joydev_match,
	.connect	= joydev_connect,
	.disconnect	= joydev_disconnect,
	.legacy_minors	= true,
	.minor		= JOYDEV_MINOR_BASE,
	.name		= "joydev",
	.id_table	= joydev_ids,
};

drivers/input/input-leds.c

static struct input_handler input_leds_handler = {
    
    
	.event =	input_leds_event,
	.connect =	input_leds_connect,
	.disconnect =	input_leds_disconnect,
	.name =		"leds",
	.id_table =	input_leds_ids,
};

drivers/input/apm-power.c

static struct input_handler apmpower_handler = {
    
    
	.event =	apmpower_event,
	.connect =	apmpower_connect,
	.disconnect =	apmpower_disconnect,
	.name =		"apm-power",
	.id_table =	apmpower_ids,
};

4.2 input_register_handler registration function

This function registers a new input_handler(interface) for the input device on the system and connects it to all that are compatible with this handler input devices.

  • INIT_LIST_HEAD(&handler->h_list): Initialize the kernel linked list in Linux
  • list_add_tail(&handler->node, &input_handler_list):Add handler to linux kernel global listinput_handler_list
  • list_for_each_entry(handler, &input_handler_list, node)
    input_attach_handler(dev, handler);:Traverse input_handler_listand find your own for the devicehandler
/**
 * input_register_handler - register a new input handler
 * @handler: handler to be registered
 *
 * This function registers a new input handler (interface) for input
 * devices in the system and attaches it to all input devices that
 * are compatible with the handler.
 */
int input_register_handler(struct input_handler *handler)
{
    
    
	struct input_dev *dev;
	int error;

	error = mutex_lock_interruptible(&input_mutex);
	if (error)
		return error;

	INIT_LIST_HEAD(&handler->h_list);

	list_add_tail(&handler->node, &input_handler_list);

	list_for_each_entry(dev, &input_dev_list, node)
		input_attach_handler(dev, handler);

	input_wakeup_procfs_readers();

	mutex_unlock(&input_mutex);
	return 0;
}
EXPORT_SYMBOL(input_register_handler);

5. input_dev and input_handler match input_handle

5.1 input_match_device matching

input_dev设备注册and input_handler注册will be calledinput_attach_handler

  • input_match_device: Matching is returned successfully handler->id_table, that isinput_device_id
  • handler->connect(handler, dev, id): Matches successfully called connectfunctions, such as drivers/input/evdev.c#evdev_connect,drivers/input/mousedev.c#mousedev_connect
static const struct input_device_id *input_match_device(struct input_handler *handler,
							struct input_dev *dev)
{
    
    
	const struct input_device_id *id;

	for (id = handler->id_table; id->flags || id->driver_info; id++) {
    
    
		if (input_match_device_id(dev, id) &&
		    (!handler->match || handler->match(handler, dev))) {
    
    
			return id;
		}
	}

	return NULL;
}

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
    
    
	const struct input_device_id *id;
	int error;

	id = input_match_device(handler, dev);
	if (!id)
		return -ENODEV;

	error = handler->connect(handler, dev, id);
	if (error && error != -ENODEV)
		pr_err("failed to attach handler %s to device %s, error: %d\n",
		       handler->name, kobject_name(&dev->dev.kobj), error);

	return error;
}

5.2 connect function

Such as drivers/input/evdev.c#evdev_connect, drivers/input/mousedev.c#mousedev_connectetc.; view general event processing evdev.c:

  • .driver_info = 1: which evdev_idsmatches all devices,
  • evdev_connect: Once registered evdev的connect;
    1》input_register_handleRegister a new one input_handle, which will be handlemainly mounted on the input_devand input_handlermember linked lists respectively;
    ( evdev->handle.dev = input_get_device(dev);, evdev->handle.handler = handler;)
    2》input_get_new_minorCan create up to 32 event devices #define EVDEV_MINORS 32;
    3》cdev_device_addFinal call device_add, create a new event device to the Linux system/dev/input/eventX
    Insert image description here

drivers/input/evdev.c

struct evdev {
    
    
	int open;
	struct input_handle handle;
	wait_queue_head_t wait;
	struct evdev_client __rcu *grab;
	struct list_head client_list;
	spinlock_t client_lock; /* protects client_list */
	struct mutex mutex;
	struct device dev;
	struct cdev cdev;
	bool exist;
};

/*
 * Create new evdev device. Note that input core serializes calls
 * to connect and disconnect.
 */
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
			 const struct input_device_id *id)
{
    
    
	struct evdev *evdev;
	int minor;
	int dev_no;
	int error;

	minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
	if (minor < 0) {
    
    
		error = minor;
		pr_err("failed to reserve new minor: %d\n", error);
		return error;
	}

	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
	if (!evdev) {
    
    
		error = -ENOMEM;
		goto err_free_minor;
	}

	INIT_LIST_HEAD(&evdev->client_list);
	spin_lock_init(&evdev->client_lock);
	mutex_init(&evdev->mutex);
	init_waitqueue_head(&evdev->wait);
	evdev->exist = true;

	dev_no = minor;
	/* Normalize device number if it falls into legacy range */
	if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
		dev_no -= EVDEV_MINOR_BASE;
	dev_set_name(&evdev->dev, "event%d", dev_no);

	evdev->handle.dev = input_get_device(dev);
	evdev->handle.name = dev_name(&evdev->dev);
	evdev->handle.handler = handler;
	evdev->handle.private = evdev;

	evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
	evdev->dev.class = &input_class;
	evdev->dev.parent = &dev->dev;
	evdev->dev.release = evdev_free;
	device_initialize(&evdev->dev);

	error = input_register_handle(&evdev->handle);
	if (error)
		goto err_free_evdev;

	cdev_init(&evdev->cdev, &evdev_fops);

	error = cdev_device_add(&evdev->cdev, &evdev->dev);
	if (error)
		goto err_cleanup_evdev;

	return 0;

 err_cleanup_evdev:
	evdev_cleanup(evdev);
	input_unregister_handle(&evdev->handle);
 err_free_evdev:
	put_device(&evdev->dev);
 err_free_minor:
	input_free_minor(minor);
	return error;
}

static const struct input_device_id evdev_ids[] = {
    
    
	{
    
     .driver_info = 1 },	/* Matches all devices */
	{
    
     },			/* Terminating zero entry */
};

MODULE_DEVICE_TABLE(input, evdev_ids);

static struct input_handler evdev_handler = {
    
    
	.event		= evdev_event,
	.events		= evdev_events,
	.connect	= evdev_connect,
	.disconnect	= evdev_disconnect,
	.legacy_minors	= true,
	.minor		= EVDEV_MINOR_BASE,
	.name		= "evdev",
	.id_table	= evdev_ids,
};

5.3 input_register_handle

input_register_handle-Register a new input handle


Handle: This function for registering Handle


places a new input handle in the list of input_devand input_handlerso that input_open_device()events can flow in it once it is opened with . This function should be called from the handler's connect()method.

/**
 * input_register_handle - register a new input handle
 * @handle: handle to register
 *
 * This function puts a new input handle onto device's
 * and handler's lists so that events can flow through
 * it once it is opened using input_open_device().
 *
 * This function is supposed to be called from handler's
 * connect() method.
 */
int input_register_handle(struct input_handle *handle)
{
    
    
	struct input_handler *handler = handle->handler;
	struct input_dev *dev = handle->dev;
	int error;

	/*
	 * We take dev->mutex here to prevent race with
	 * input_release_device().
	 */
	error = mutex_lock_interruptible(&dev->mutex);
	if (error)
		return error;

	/*
	 * Filters go to the head of the list, normal handlers
	 * to the tail.
	 */
	if (handler->filter)
		list_add_rcu(&handle->d_node, &dev->h_list);
	else
		list_add_tail_rcu(&handle->d_node, &dev->h_list);

	mutex_unlock(&dev->mutex);

	/*
	 * Since we are supposed to be called from ->connect()
	 * which is mutually exclusive with ->disconnect()
	 * we can't be racing with input_unregister_handle()
	 * and so separate lock is not needed here.
	 */
	list_add_tail_rcu(&handle->h_node, &handler->h_list);

	if (handler->start)
		handler->start(handle);

	return 0;
}
EXPORT_SYMBOL(input_register_handle);

5.4 input_dev \ input_handler \ input_handle 关系

Insert image description here

input_devIt is the hardware driver layer, representing an input device.
input_handlerIt is the event processing layer, representing an event processor. It
input_handlebelongs to the core layer, representing a paired input device and input event processor.

input_devlinked together globally input_dev_list. This operation is implemented when the device is registered.
input_handlerlinked together globally input_handler_list. This operation is implemented when the event handler is registered.

input_handeThere is no global linked list. When it was registered, it hung itself on input_devand input_handlerrespectively h_list. You can find it
through input_devand In the device registration and event handler, pairing work must be done when registering, and the link will be implemented after pairing. and can also be found via .input_handlerinput_handle
input_handleinput_devinput_handler

6. Report input events

input事件Generally, 中断方式reporting, related methods input_report_abs, input_report_key, input_syncetc. are used. Finally input_sync, it means that an event is reported and input_eventthe processing is finally called.

6.1 Reporting of underlying Input events

AOSP > Documentation > Core Topics > Keyboard Devices , AOSP > Documentation > Core Topics > Touch Devices

Different input设备reporting input事件formats are different, commonly used 按键or 触摸屏adopted 中断方式reporting.
For example, when reporting on a touch screen, input事件it is generally necessary to report the finger's id, x coordinate, y coordinate and other information.


https://www.kernel.org/doc/Documentation/input/input.txt
https://www.kernel.org/doc/Documentation/input/event-codes.txt
https://www.kernel.org/ doc/Documentation/input/multi-touch-protocol.txt

input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
input_sync(input);
- type code value
Point 1 EV_ABS ABS_MT_SLOT 0
\ EV_ABS ABS_MT_TRACKING_ID id
\ EV_ABS ABS_MT_POSITION_X x
\ EV_ABS ABS_MT_POSITION_Y y
Point 2 EV_ABS ABS_MT_SLOT n
\ EV_ABS ABS_MT_TRACKING_ID id
\ EV_ABS ABS_MT_POSITION_X x
\ EV_ABS ABS_MT_POSITION_Y y

6.2 input_event reports new input events

Drivers that implement various input devices should use this function to report input events. See also input_inject_event().
NOTE: input_event()It is input_allocate_device()safe to use an input device immediately after using it, or even before using input_register_device()registration, but the event will not reach any input handler. input_event()This early call of can be used to "seed" the initial state of a switch or the initial position of an absolute axis, etc.

  • input_handle_event: Each event reporting is input_eventcompleted through the interface. After determining whether the event type is supported, it is mainly input_handle_eventcompleted by calling
  • input_get_disposition: Determine what to do based on the reported information
  • handler->events()/handler->event(): input_devCorresponding input_handler, such as evdev_handleretc( input_event -> input_handle_event -> input_pass_values -> input_to_handler -> handler->events()/handler->event())

drivers/input/input.c

/*
 * Pass event first through all filters and then, if event has not been
 * filtered out, through all open handles. This function is called with
 * dev->event_lock held and interrupts disabled.
 */
static unsigned int input_to_handler(struct input_handle *handle,
			struct input_value *vals, unsigned int count)
{
    
    
	struct input_handler *handler = handle->handler;
	struct input_value *end = vals;
	struct input_value *v;

	if (handler->filter) {
    
    
		for (v = vals; v != vals + count; v++) {
    
    
			if (handler->filter(handle, v->type, v->code, v->value))
				continue;
			if (end != v)
				*end = *v;
			end++;
		}
		count = end - vals;
	}

	if (!count)
		return 0;

	if (handler->events)
		handler->events(handle, vals, count);
	else if (handler->event)
		for (v = vals; v != vals + count; v++)
			handler->event(handle, v->type, v->code, v->value);

	return count;
}


/*
 * Pass values first through all filters and then, if event has not been
 * filtered out, through all open handles. This function is called with
 * dev->event_lock held and interrupts disabled.
 */
static void input_pass_values(struct input_dev *dev,
			      struct input_value *vals, unsigned int count)
{
    
    
	struct input_handle *handle;
	struct input_value *v;

	if (!count)
		return;

	rcu_read_lock();

	handle = rcu_dereference(dev->grab);
	if (handle) {
    
    
		count = input_to_handler(handle, vals, count);
	} else {
    
    
		list_for_each_entry_rcu(handle, &dev->h_list, d_node)
			if (handle->open) {
    
    
				count = input_to_handler(handle, vals, count);
				if (!count)
					break;
			}
	}

	rcu_read_unlock();

	/* trigger auto repeat for key events */
	if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) {
    
    
		for (v = vals; v != vals + count; v++) {
    
    
			if (v->type == EV_KEY && v->value != 2) {
    
    
				if (v->value)
					input_start_autorepeat(dev, v->code);
				else
					input_stop_autorepeat(dev);
			}
		}
	}
}


/**
 * input_event() - report new input event
 * @dev: device that generated the event
 * @type: type of the event
 * @code: event code
 * @value: value of the event
 *
 * This function should be used by drivers implementing various input
 * devices to report input events. See also input_inject_event().
 *
 * NOTE: input_event() may be safely used right after input device was
 * allocated with input_allocate_device(), even before it is registered
 * with input_register_device(), but the event will not reach any of the
 * input handlers. Such early invocation of input_event() may be used
 * to 'seed' initial state of a switch or initial position of absolute
 * axis, etc.
 */
void input_event(struct input_dev *dev,
		 unsigned int type, unsigned int code, int value)
{
    
    
	unsigned long flags;

	if (is_event_supported(type, dev->evbit, EV_MAX)) {
    
    

		spin_lock_irqsave(&dev->event_lock, flags);
		input_handle_event(dev, type, code, value);
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}
}
EXPORT_SYMBOL(input_event);


static void input_handle_event(struct input_dev *dev,
			       unsigned int type, unsigned int code, int value)
{
    
    
	int disposition = input_get_disposition(dev, type, code, &value);

	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
		add_input_randomness(type, code, value);

	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
		dev->event(dev, type, code, value);

	if (!dev->vals)
		return;

	if (disposition & INPUT_PASS_TO_HANDLERS) {
    
    
		struct input_value *v;

		if (disposition & INPUT_SLOT) {
    
    
			v = &dev->vals[dev->num_vals++];
			v->type = EV_ABS;
			v->code = ABS_MT_SLOT;
			v->value = dev->mt->slot;
		}

		v = &dev->vals[dev->num_vals++];
		v->type = type;
		v->code = code;
		v->value = value;
	}

	if (disposition & INPUT_FLUSH) {
    
    
		if (dev->num_vals >= 2)
			input_pass_values(dev, dev->vals, dev->num_vals);
		dev->num_vals = 0;
		/*
		 * Reset the timestamp on flush so we won't end up
		 * with a stale one. Note we only need to reset the
		 * monolithic one as we use its presence when deciding
		 * whether to generate a synthetic timestamp.
		 */
		dev->timestamp[INPUT_CLK_MONO] = ktime_set(0, 0);
	} else if (dev->num_vals >= dev->max_vals - 2) {
    
    
		dev->vals[dev->num_vals++] = input_value_sync;
		input_pass_values(dev, dev->vals, dev->num_vals);
		dev->num_vals = 0;
	}

}

6.3 evdev_events processing in evdev_handler

evdev_eventsPass incoming events to all connected client
evdev_event/evdev_events -> evdev_pass_values -> __pass_event ->


input events and store them in client->buffer; kill_fasyncused to send notification events to tell the upper layer client->bufferthat data can be read.

drivers/input/evdev.c

static void __pass_event(struct evdev_client *client,
			 const struct input_event *event)
{
    
    
	client->buffer[client->head++] = *event;
	client->head &= client->bufsize - 1;

	if (unlikely(client->head == client->tail)) {
    
    
		/*
		 * This effectively "drops" all unconsumed events, leaving
		 * EV_SYN/SYN_DROPPED plus the newest event in the queue.
		 */
		client->tail = (client->head - 2) & (client->bufsize - 1);

		client->buffer[client->tail] = (struct input_event) {
    
    
			.input_event_sec = event->input_event_sec,
			.input_event_usec = event->input_event_usec,
			.type = EV_SYN,
			.code = SYN_DROPPED,
			.value = 0,
		};

		client->packet_head = client->tail;
	}

	if (event->type == EV_SYN && event->code == SYN_REPORT) {
    
    
		client->packet_head = client->head;
		kill_fasync(&client->fasync, SIGIO, POLL_IN);
	}
}

static void evdev_pass_values(struct evdev_client *client,
			const struct input_value *vals, unsigned int count,
			ktime_t *ev_time)
{
    
    
	struct evdev *evdev = client->evdev;
	const struct input_value *v;
	struct input_event event;
	struct timespec64 ts;
	bool wakeup = false;

	if (client->revoked)
		return;

	ts = ktime_to_timespec64(ev_time[client->clk_type]);
	event.input_event_sec = ts.tv_sec;
	event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;

	/* Interrupts are disabled, just acquire the lock. */
	spin_lock(&client->buffer_lock);

	for (v = vals; v != vals + count; v++) {
    
    
		if (__evdev_is_filtered(client, v->type, v->code))
			continue;

		if (v->type == EV_SYN && v->code == SYN_REPORT) {
    
    
			/* drop empty SYN_REPORT */
			if (client->packet_head == client->head)
				continue;

			wakeup = true;
		}

		event.type = v->type;
		event.code = v->code;
		event.value = v->value;
		__pass_event(client, &event);
	}

	spin_unlock(&client->buffer_lock);

	if (wakeup)
		wake_up_interruptible(&evdev->wait);
}

/*
 * Pass incoming events to all connected clients.
 */
static void evdev_events(struct input_handle *handle,
			 const struct input_value *vals, unsigned int count)
{
    
    
	struct evdev *evdev = handle->private;
	struct evdev_client *client;
	ktime_t *ev_time = input_get_timestamp(handle->dev);

	rcu_read_lock();

	client = rcu_dereference(evdev->grab);

	if (client)
		evdev_pass_values(client, vals, count, ev_time);
	else
		list_for_each_entry_rcu(client, &evdev->client_list, node)
			evdev_pass_values(client, vals, count, ev_time);

	rcu_read_unlock();
}

/*
 * Pass incoming event to all connected clients.
 */
static void evdev_event(struct input_handle *handle,
			unsigned int type, unsigned int code, int value)
{
    
    
	struct input_value vals[] = {
    
     {
    
     type, code, value } };

	evdev_events(handle, vals, 1);
}

7. Input event kernel space is passed to user space

  • EventHub::getEvents -> resd: input事件Stored in client->buffer, when the application layer or framework layer calls to read函数read /dev/input/event*the file, for example, the return data evdev.cwill be called evdev_read,
  • event_fetch_next_event: Determine client->bufferwhether the head and tail pointers in this circular buffer are equal (if equal, there is no data in the buffer), if not equal, take out a input_eventtype of event and put it into the event;
  • input_event_to_user: Copy this event to the application layer. input_event_sizeThe function is used to obtain input_eventthe size of an event and copy the event in a loop client->bufferto the buffer of the application layer.

frameworks/native/services/inputflinger/reader/EventHub.cpp

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    
    
    ALOG_ASSERT(bufferSize >= 1);

    std::scoped_lock _l(mLock);

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
    
    
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        // Reopen input devices if needed.
        if (mNeedToReopenDevices) {
    
    
            mNeedToReopenDevices = false;

            ALOGI("Reopening all input devices due to a configuration change.");

            closeAllDevicesLocked();
            mNeedToScanDevices = true;
            break; // return to the caller before we actually rescan
        }

        // Report any devices that had last been added/removed.
        for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {
    
    
            std::unique_ptr<Device> device = std::move(*it);
            ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
            event->when = now;
            event->deviceId = (device->id == mBuiltInKeyboardId)
                    ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
                    : device->id;
            event->type = DEVICE_REMOVED;
            event += 1;
            it = mClosingDevices.erase(it);
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
    
    
                break;
            }
        }

        if (mNeedToScanDevices) {
    
    
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }

        while (!mOpeningDevices.empty()) {
    
    
            std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());
            mOpeningDevices.pop_back();
            ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED;
            event += 1;

            // Try to find a matching video device by comparing device names
            for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();
                 it++) {
    
    
                std::unique_ptr<TouchVideoDevice>& videoDevice = *it;
                if (tryAddVideoDeviceLocked(*device, videoDevice)) {
    
    
                    // videoDevice was transferred to 'device'
                    it = mUnattachedVideoDevices.erase(it);
                    break;
                }
            }

            auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));
            if (!inserted) {
    
    
                ALOGW("Device id %d exists, replaced.", device->id);
            }
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
    
    
                break;
            }
        }

        if (mNeedToSendFinishedDeviceScan) {
    
    
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
    
    
                break;
            }
        }

        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
    
    
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            if (eventItem.data.fd == mINotifyFd) {
    
    
                if (eventItem.events & EPOLLIN) {
    
    
                    mPendingINotify = true;
                } else {
    
    
                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }

            if (eventItem.data.fd == mWakeReadPipeFd) {
    
    
                if (eventItem.events & EPOLLIN) {
    
    
                    ALOGV("awoken after wake()");
                    awoken = true;
                    char wakeReadBuffer[16];
                    ssize_t nRead;
                    do {
    
    
                        nRead = read(mWakeReadPipeFd, wakeReadBuffer, sizeof(wakeReadBuffer));
                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(wakeReadBuffer));
                } else {
    
    
                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
                          eventItem.events);
                }
                continue;
            }

            Device* device = getDeviceByFdLocked(eventItem.data.fd);
            if (device == nullptr) {
    
    
                ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
                      eventItem.data.fd);
                ALOG_ASSERT(!DEBUG);
                continue;
            }
            if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {
    
    
                if (eventItem.events & EPOLLIN) {
    
    
                    size_t numFrames = device->videoDevice->readAndQueueFrames();
                    if (numFrames == 0) {
    
    
                        ALOGE("Received epoll event for video device %s, but could not read frame",
                              device->videoDevice->getName().c_str());
                    }
                } else if (eventItem.events & EPOLLHUP) {
    
    
                    // TODO(b/121395353) - consider adding EPOLLRDHUP
                    ALOGI("Removing video device %s due to epoll hang-up event.",
                          device->videoDevice->getName().c_str());
                    unregisterVideoDeviceFromEpollLocked(*device->videoDevice);
                    device->videoDevice = nullptr;
                } else {
    
    
                    ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
                          device->videoDevice->getName().c_str());
                    ALOG_ASSERT(!DEBUG);
                }
                continue;
            }
            // This must be an input event
            if (eventItem.events & EPOLLIN) {
    
    
                int32_t readSize =
                        read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
    
    
                    // Device was removed before INotify noticed.
                    ALOGW("could not get event, removed? (fd: %d size: %" PRId32
                          " bufferSize: %zu capacity: %zu errno: %d)\n",
                          device->fd, readSize, bufferSize, capacity, errno);
                    deviceChanged = true;
                    closeDeviceLocked(*device);
                } else if (readSize < 0) {
    
    
                    if (errno != EAGAIN && errno != EINTR) {
    
    
                        ALOGW("could not get event (errno=%d)", errno);
                    }
                } else if ((readSize % sizeof(struct input_event)) != 0) {
    
    
                    ALOGE("could not get event (wrong size: %d)", readSize);
                } else {
    
    
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
    
    
                        struct input_event& iev = readBuffer[i];
                        event->when = processEventTimestamp(iev);
                        event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                    if (capacity == 0) {
    
    
                        // The result buffer is full.  Reset the pending event index
                        // so we will try to read the device again on the next iteration.
                        mPendingEventIndex -= 1;
                        break;
                    }
                }
            } else if (eventItem.events & EPOLLHUP) {
    
    
                ALOGI("Removing device %s due to epoll hang-up event.",
                      device->identifier.name.c_str());
                deviceChanged = true;
                closeDeviceLocked(*device);
            } else {
    
    
                ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
                      device->identifier.name.c_str());
            }
        }

        // readNotify() will modify the list of devices so this must be done after
        // processing all other events to ensure that we read all remaining events
        // before closing the devices.
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
    
    
            mPendingINotify = false;
            readNotifyLocked();
            deviceChanged = true;
        }

        // Report added or removed devices immediately.
        if (deviceChanged) {
    
    
            continue;
        }

        // Return now if we have collected any events or if we were explicitly awoken.
        if (event != buffer || awoken) {
    
    
            break;
        }

        // Poll for events.
        // When a device driver has pending (unread) events, it acquires
        // a kernel wake lock.  Once the last pending event has been read, the device
        // driver will release the kernel wake lock, but the epoll will hold the wakelock,
        // since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait
        // is called again for the same fd that produced the event.
        // Thus the system can only sleep if there are no events pending or
        // currently being processed.
        //
        // The timeout is advisory only.  If the device is asleep, it will not wake just to
        // service the timeout.
        mPendingEventIndex = 0;

        mLock.unlock(); // release lock before poll

        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

        mLock.lock(); // reacquire lock after poll

        if (pollResult == 0) {
    
    
            // Timed out.
            mPendingEventCount = 0;
            break;
        }

        if (pollResult < 0) {
    
    
            // An error occurred.
            mPendingEventCount = 0;

            // Sleep after errors to avoid locking up the system.
            // Hopefully the error is transient.
            if (errno != EINTR) {
    
    
                ALOGW("poll failed (errno=%d)\n", errno);
                usleep(100000);
            }
        } else {
    
    
            // Some events occurred.
            mPendingEventCount = size_t(pollResult);
        }
    }

    // All done, return the number of events we read.
    return event - buffer;
}

drivers/input/evdev.c

static ssize_t evdev_read(struct file *file, char __user *buffer,
			  size_t count, loff_t *ppos)
{
    
    
	struct evdev_client *client = file->private_data;
	struct evdev *evdev = client->evdev;
	struct input_event event;
	size_t read = 0;
	int error;

	if (count != 0 && count < input_event_size())
		return -EINVAL;

	for (;;) {
    
    
		if (!evdev->exist || client->revoked)
			return -ENODEV;

		if (client->packet_head == client->tail &&
		    (file->f_flags & O_NONBLOCK))
			return -EAGAIN;

		/*
		 * count == 0 is special - no IO is done but we check
		 * for error conditions (see above).
		 */
		if (count == 0)
			break;

		while (read + input_event_size() <= count &&
		       evdev_fetch_next_event(client, &event)) {
    
    

			if (input_event_to_user(buffer + read, &event))
				return -EFAULT;

			read += input_event_size();
		}

		if (read)
			break;

		if (!(file->f_flags & O_NONBLOCK)) {
    
    
			error = wait_event_interruptible(evdev->wait,
					client->packet_head != client->tail ||
					!evdev->exist || client->revoked);
			if (error)
				return error;
		}
	}

	return read;
}

7.1 evdev_fetch_next_event

event_fetch_next_event: Determine client->bufferwhether the head and tail pointers in this circular buffer are equal (if they are equal, there is no data in the buffer), if they are not equal, take out a input_eventtype of event and put it into the event.

drivers/input/evdev.c

static int evdev_fetch_next_event(struct evdev_client *client,
				  struct input_event *event)
{
    
    
	int have_event;

	spin_lock_irq(&client->buffer_lock);

	have_event = client->packet_head != client->tail;
	if (have_event) {
    
    
		*event = client->buffer[client->tail++];
		client->tail &= client->bufsize - 1;
	}

	spin_unlock_irq(&client->buffer_lock);

	return have_event;
}

7.2 input_event_to_user

input_event_to_user: Send this event copyto the application layer. input_event_sizeThe function is used to obtain input_eventthe size of an event and loop to copy client->bufferthe event to the buffer of the application layer.

drivers/input/input-compat.c

#ifdef CONFIG_COMPAT

int input_event_to_user(char __user *buffer,
			const struct input_event *event)
{
    
    
	if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
    
    
		struct input_event_compat compat_event;

		compat_event.sec = event->input_event_sec;
		compat_event.usec = event->input_event_usec;
		compat_event.type = event->type;
		compat_event.code = event->code;
		compat_event.value = event->value;

		if (copy_to_user(buffer, &compat_event,
				 sizeof(struct input_event_compat)))
			return -EFAULT;

	} else {
    
    
		if (copy_to_user(buffer, event, sizeof(struct input_event)))
			return -EFAULT;
	}

	return 0;
}

#else

int input_event_to_user(char __user *buffer,
			const struct input_event *event)
{
    
    
	if (copy_to_user(buffer, event, sizeof(struct input_event)))
		return -EFAULT;

	return 0;
}

#endif /* CONFIG_COMPAT */

references

https://www.kernel.org/doc/Documentation/input/input.txt
Linux value input subsystem analysis (detailed explanation)
input input subsystem

Guess you like

Origin blog.csdn.net/qq_23452385/article/details/132859426