⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 input.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * The input core * * Copyright (c) 1999-2002 Vojtech Pavlik *//* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */#include <linux/init.h>#include <linux/input.h>#include <linux/module.h>#include <linux/random.h>#include <linux/major.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/poll.h>#include <linux/device.h>#include <linux/mutex.h>#include <linux/rcupdate.h>MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");MODULE_DESCRIPTION("Input core");MODULE_LICENSE("GPL");#define INPUT_DEVICES	256static LIST_HEAD(input_dev_list);static LIST_HEAD(input_handler_list);/* * input_mutex protects access to both input_dev_list and input_handler_list. * This also causes input_[un]register_device and input_[un]register_handler * be mutually exclusive which simplifies locking in drivers implementing * input handlers. */static DEFINE_MUTEX(input_mutex);static struct input_handler *input_table[8];static inline int is_event_supported(unsigned int code,				     unsigned long *bm, unsigned int max){	return code <= max && test_bit(code, bm);}static int input_defuzz_abs_event(int value, int old_val, int fuzz){	if (fuzz) {		if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)			return old_val;		if (value > old_val - fuzz && value < old_val + fuzz)			return (old_val * 3 + value) / 4;		if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)			return (old_val + value) / 2;	}	return value;}/* * Pass event through all open handles. This function is called with * dev->event_lock held and interrupts disabled. */static void input_pass_event(struct input_dev *dev,			     unsigned int type, unsigned int code, int value){	struct input_handle *handle;	rcu_read_lock();	handle = rcu_dereference(dev->grab);	if (handle)		handle->handler->event(handle, type, code, value);	else		list_for_each_entry_rcu(handle, &dev->h_list, d_node)			if (handle->open)				handle->handler->event(handle,							type, code, value);	rcu_read_unlock();}/* * Generate software autorepeat event. Note that we take * dev->event_lock here to avoid racing with input_event * which may cause keys get "stuck". */static void input_repeat_key(unsigned long data){	struct input_dev *dev = (void *) data;	unsigned long flags;	spin_lock_irqsave(&dev->event_lock, flags);	if (test_bit(dev->repeat_key, dev->key) &&	    is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {		input_pass_event(dev, EV_KEY, dev->repeat_key, 2);		if (dev->sync) {			/*			 * Only send SYN_REPORT if we are not in a middle			 * of driver parsing a new hardware packet.			 * Otherwise assume that the driver will send			 * SYN_REPORT once it's done.			 */			input_pass_event(dev, EV_SYN, SYN_REPORT, 1);		}		if (dev->rep[REP_PERIOD])			mod_timer(&dev->timer, jiffies +					msecs_to_jiffies(dev->rep[REP_PERIOD]));	}	spin_unlock_irqrestore(&dev->event_lock, flags);}static void input_start_autorepeat(struct input_dev *dev, int code){	if (test_bit(EV_REP, dev->evbit) &&	    dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&	    dev->timer.data) {		dev->repeat_key = code;		mod_timer(&dev->timer,			  jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));	}}#define INPUT_IGNORE_EVENT	0#define INPUT_PASS_TO_HANDLERS	1#define INPUT_PASS_TO_DEVICE	2#define INPUT_PASS_TO_ALL	(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)static void input_handle_event(struct input_dev *dev,			       unsigned int type, unsigned int code, int value){	int disposition = INPUT_IGNORE_EVENT;	switch (type) {	case EV_SYN:		switch (code) {		case SYN_CONFIG:			disposition = INPUT_PASS_TO_ALL;			break;		case SYN_REPORT:			if (!dev->sync) {				dev->sync = 1;				disposition = INPUT_PASS_TO_HANDLERS;			}			break;		}		break;	case EV_KEY:		if (is_event_supported(code, dev->keybit, KEY_MAX) &&		    !!test_bit(code, dev->key) != value) {			if (value != 2) {				__change_bit(code, dev->key);				if (value)					input_start_autorepeat(dev, code);			}			disposition = INPUT_PASS_TO_HANDLERS;		}		break;	case EV_SW:		if (is_event_supported(code, dev->swbit, SW_MAX) &&		    !!test_bit(code, dev->sw) != value) {			__change_bit(code, dev->sw);			disposition = INPUT_PASS_TO_HANDLERS;		}		break;	case EV_ABS:		if (is_event_supported(code, dev->absbit, ABS_MAX)) {			value = input_defuzz_abs_event(value,					dev->abs[code], dev->absfuzz[code]);			if (dev->abs[code] != value) {				dev->abs[code] = value;				disposition = INPUT_PASS_TO_HANDLERS;			}		}		break;	case EV_REL:		if (is_event_supported(code, dev->relbit, REL_MAX) && value)			disposition = INPUT_PASS_TO_HANDLERS;		break;	case EV_MSC:		if (is_event_supported(code, dev->mscbit, MSC_MAX))			disposition = INPUT_PASS_TO_ALL;		break;	case EV_LED:		if (is_event_supported(code, dev->ledbit, LED_MAX) &&		    !!test_bit(code, dev->led) != value) {			__change_bit(code, dev->led);			disposition = INPUT_PASS_TO_ALL;		}		break;	case EV_SND:		if (is_event_supported(code, dev->sndbit, SND_MAX)) {			if (!!test_bit(code, dev->snd) != !!value)				__change_bit(code, dev->snd);			disposition = INPUT_PASS_TO_ALL;		}		break;	case EV_REP:		if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {			dev->rep[code] = value;			disposition = INPUT_PASS_TO_ALL;		}		break;	case EV_FF:		if (value >= 0)			disposition = INPUT_PASS_TO_ALL;		break;	case EV_PWR:		disposition = INPUT_PASS_TO_ALL;		break;	}	if (type != EV_SYN)		dev->sync = 0;	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)		dev->event(dev, type, code, value);	if (disposition & INPUT_PASS_TO_HANDLERS)		input_pass_event(dev, type, code, value);}/** * 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. See also input_inject_event(). */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);		add_input_randomness(type, code, value);		input_handle_event(dev, type, code, value);		spin_unlock_irqrestore(&dev->event_lock, flags);	}}EXPORT_SYMBOL(input_event);/** * input_inject_event() - send input event from input handler * @handle: input handle to send event through * @type: type of the event * @code: event code * @value: value of the event * * Similar to input_event() but will ignore event if device is * "grabbed" and handle injecting event is not the one that owns * the device. */void input_inject_event(struct input_handle *handle,			unsigned int type, unsigned int code, int value){	struct input_dev *dev = handle->dev;	struct input_handle *grab;	unsigned long flags;	if (is_event_supported(type, dev->evbit, EV_MAX)) {		spin_lock_irqsave(&dev->event_lock, flags);		rcu_read_lock();		grab = rcu_dereference(dev->grab);		if (!grab || grab == handle)			input_handle_event(dev, type, code, value);		rcu_read_unlock();		spin_unlock_irqrestore(&dev->event_lock, flags);	}}EXPORT_SYMBOL(input_inject_event);/** * input_grab_device - grabs device for exclusive use * @handle: input handle that wants to own the device * * When a device is grabbed by an input handle all events generated by * the device are delivered only to this handle. Also events injected * by other input handles are ignored while device is grabbed. */int input_grab_device(struct input_handle *handle){	struct input_dev *dev = handle->dev;	int retval;	retval = mutex_lock_interruptible(&dev->mutex);	if (retval)		return retval;	if (dev->grab) {		retval = -EBUSY;		goto out;	}	rcu_assign_pointer(dev->grab, handle);	synchronize_rcu(); out:	mutex_unlock(&dev->mutex);	return retval;}EXPORT_SYMBOL(input_grab_device);static void __input_release_device(struct input_handle *handle){	struct input_dev *dev = handle->dev;	if (dev->grab == handle) {		rcu_assign_pointer(dev->grab, NULL);		/* Make sure input_pass_event() notices that grab is gone */		synchronize_rcu();		list_for_each_entry(handle, &dev->h_list, d_node)			if (handle->open && handle->handler->start)				handle->handler->start(handle);	}}/** * input_release_device - release previously grabbed device * @handle: input handle that owns the device * * Releases previously grabbed device so that other input handles can * start receiving input events. Upon release all handlers attached * to the device have their start() method called so they have a change * to synchronize device state with the rest of the system. */void input_release_device(struct input_handle *handle){	struct input_dev *dev = handle->dev;	mutex_lock(&dev->mutex);	__input_release_device(handle);	mutex_unlock(&dev->mutex);}EXPORT_SYMBOL(input_release_device);/** * input_open_device - open input device * @handle: handle through which device is being accessed * * This function should be called by input handlers when they * want to start receive events from given input device. */int input_open_device(struct input_handle *handle){	struct input_dev *dev = handle->dev;	int retval;	retval = mutex_lock_interruptible(&dev->mutex);	if (retval)		return retval;	if (dev->going_away) {		retval = -ENODEV;		goto out;	}	handle->open++;	if (!dev->users++ && dev->open)		retval = dev->open(dev);	if (retval) {		dev->users--;		if (!--handle->open) {			/*			 * Make sure we are not delivering any more events			 * through this handle			 */			synchronize_rcu();		}	} out:	mutex_unlock(&dev->mutex);	return retval;}EXPORT_SYMBOL(input_open_device);int input_flush_device(struct input_handle *handle, struct file *file){	struct input_dev *dev = handle->dev;	int retval;	retval = mutex_lock_interruptible(&dev->mutex);	if (retval)		return retval;	if (dev->flush)		retval = dev->flush(dev, file);	mutex_unlock(&dev->mutex);	return retval;}EXPORT_SYMBOL(input_flush_device);/** * input_close_device - close input device * @handle: handle through which device is being accessed * * This function should be called by input handlers when they * want to stop receive events from given input device. */void input_close_device(struct input_handle *handle){	struct input_dev *dev = handle->dev;	mutex_lock(&dev->mutex);	__input_release_device(handle);	if (!--dev->users && dev->close)		dev->close(dev);	if (!--handle->open) {		/*		 * synchronize_rcu() makes sure that input_pass_event()		 * completed and that no more input events are delivered		 * through this handle		 */		synchronize_rcu();	}	mutex_unlock(&dev->mutex);}EXPORT_SYMBOL(input_close_device);/* * Prepare device for unregistering */static void input_disconnect_device(struct input_dev *dev){	struct input_handle *handle;	int code;	/*	 * Mark device as going away. Note that we take dev->mutex here	 * not to protect access to dev->going_away but rather to ensure	 * that there are no threads in the middle of input_open_device()	 */	mutex_lock(&dev->mutex);	dev->going_away = 1;	mutex_unlock(&dev->mutex);	spin_lock_irq(&dev->event_lock);	/*	 * Simulate keyup events for all pressed keys so that handlers	 * are not left with "stuck" keys. The driver may continue	 * generate events even after we done here but they will not	 * reach any handlers.	 */	if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {		for (code = 0; code <= KEY_MAX; code++) {			if (is_event_supported(code, dev->keybit, KEY_MAX) &&			    test_bit(code, dev->key)) {				input_pass_event(dev, EV_KEY, code, 0);			}		}		input_pass_event(dev, EV_SYN, SYN_REPORT, 1);	}	list_for_each_entry(handle, &dev->h_list, d_node)		handle->open = 0;	spin_unlock_irq(&dev->event_lock);}static int input_fetch_keycode(struct input_dev *dev, int scancode){	switch (dev->keycodesize) {		case 1:			return ((u8 *)dev->keycode)[scancode];		case 2:			return ((u16 *)dev->keycode)[scancode];		default:			return ((u32 *)dev->keycode)[scancode];	}}static int input_default_getkeycode(struct input_dev *dev,				    int scancode, int *keycode){	if (!dev->keycodesize)		return -EINVAL;	if (scancode < 0 || scancode >= dev->keycodemax)		return -EINVAL;	*keycode = input_fetch_keycode(dev, scancode);	return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -