1074 lines · 23.9 KB · C
RawDownload
			BITS_TO_LONGS(maxbit) * sizeof(long); 	if (len > maxlen)		len = maxlen; 	return copy_to_user(p, bits, len) ? -EFAULT : len;}#endif /* __BIG_ENDIAN */ #else static int bits_to_user(unsigned long *bits, unsigned int maxbit,			unsigned int maxlen, void __user *p, int compat){	int len = BITS_TO_LONGS(maxbit) * sizeof(long); 	if (len > maxlen)		len = maxlen; 	return copy_to_user(p, bits, len) ? -EFAULT : len;} #endif /* CONFIG_COMPAT */ static int str_to_user(const char *str, unsigned int maxlen, void __user *p){	int len; 	if (!str)		return -ENOENT; 	len = strlen(str) + 1;	if (len > maxlen)		len = maxlen; 	return copy_to_user(p, str, len) ? -EFAULT : len;} #define OLD_KEY_MAX	0x1ffstatic int handle_eviocgbit(struct input_dev *dev,			    unsigned int type, unsigned int size,			    void __user *p, int compat_mode){	static unsigned long keymax_warn_time;	unsigned long *bits;	int len; 	switch (type) { 	case      0: bits = dev->evbit;  len = EV_MAX;  break;	case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;	case EV_REL: bits = dev->relbit; len = REL_MAX; break;	case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;	case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;	case EV_LED: bits = dev->ledbit; len = LED_MAX; break;	case EV_SND: bits = dev->sndbit; len = SND_MAX; break;	case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;	case EV_SW:  bits = dev->swbit;  len = SW_MAX;  break;	default: return -EINVAL;	} 	/*	 * Work around bugs in userspace programs that like to do	 * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'	 * should be in bytes, not in bits.	 */	if (type == EV_KEY && size == OLD_KEY_MAX) {		len = OLD_KEY_MAX;		if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))			pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "				   "limiting output to %zu bytes. See "				   "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",				   OLD_KEY_MAX,				   BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));	} 	return bits_to_user(bits, len, size, p, compat_mode);}#undef OLD_KEY_MAX static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p){	struct input_keymap_entry ke = {		.len	= sizeof(unsigned int),		.flags	= 0,	};	int __user *ip = (int __user *)p;	int error; 	/* legacy case */	if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))		return -EFAULT; 	error = input_get_keycode(dev, &ke);	if (error)		return error; 	if (put_user(ke.keycode, ip + 1))		return -EFAULT; 	return 0;} static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p){	struct input_keymap_entry ke;	int error; 	if (copy_from_user(&ke, p, sizeof(ke)))		return -EFAULT; 	error = input_get_keycode(dev, &ke);	if (error)		return error; 	if (copy_to_user(p, &ke, sizeof(ke)))		return -EFAULT; 	return 0;} static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p){	struct input_keymap_entry ke = {		.len	= sizeof(unsigned int),		.flags	= 0,	};	int __user *ip = (int __user *)p; 	if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))		return -EFAULT; 	if (get_user(ke.keycode, ip + 1))		return -EFAULT; 	return input_set_keycode(dev, &ke);} static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p){	struct input_keymap_entry ke; 	if (copy_from_user(&ke, p, sizeof(ke)))		return -EFAULT; 	if (ke.len > sizeof(ke.scancode))		return -EINVAL; 	return input_set_keycode(dev, &ke);} static int evdev_handle_mt_request(struct input_dev *dev,				   unsigned int size,				   int __user *ip){	const struct input_mt_slot *mt = dev->mt;	unsigned int code;	int max_slots;	int i; 	if (get_user(code, &ip[0]))		return -EFAULT;	if (!input_is_mt_value(code))		return -EINVAL; 	max_slots = (size - sizeof(__u32)) / sizeof(__s32);	for (i = 0; i < dev->mtsize && i < max_slots; i++)		if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i]))			return -EFAULT; 	return 0;} static long evdev_do_ioctl(struct file *file, unsigned int cmd,			   void __user *p, int compat_mode){	struct evdev_client *client = file->private_data;	struct evdev *evdev = client->evdev;	struct input_dev *dev = evdev->handle.dev;	struct input_absinfo abs;	struct ff_effect effect;	int __user *ip = (int __user *)p;	unsigned int i, t, u, v;	unsigned int size;	int error; 	/* First we check for fixed-length commands */	switch (cmd) { 	case EVIOCGVERSION:		return put_user(EV_VERSION, ip); 	case EVIOCGID:		if (copy_to_user(p, &dev->id, sizeof(struct input_id)))			return -EFAULT;		return 0; 	case EVIOCGREP:		if (!test_bit(EV_REP, dev->evbit))			return -ENOSYS;		if (put_user(dev->rep[REP_DELAY], ip))			return -EFAULT;		if (put_user(dev->rep[REP_PERIOD], ip + 1))			return -EFAULT;		return 0; 	case EVIOCSREP:		if (!test_bit(EV_REP, dev->evbit))			return -ENOSYS;		if (get_user(u, ip))			return -EFAULT;		if (get_user(v, ip + 1))			return -EFAULT; 		input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);		input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); 		return 0; 	case EVIOCRMFF:		return input_ff_erase(dev, (int)(unsigned long) p, file); 	case EVIOCGEFFECTS:		i = test_bit(EV_FF, dev->evbit) ?				dev->ff->max_effects : 0;		if (put_user(i, ip))			return -EFAULT;		return 0; 	case EVIOCGRAB:		if (p)			return evdev_grab(evdev, client);		else			return evdev_ungrab(evdev, client); 	case EVIOCSCLOCKID:		if (copy_from_user(&i, p, sizeof(unsigned int)))			return -EFAULT;		if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME)			return -EINVAL;		client->clkid = i;		return 0; 	case EVIOCGKEYCODE:		return evdev_handle_get_keycode(dev, p); 	case EVIOCSKEYCODE:		return evdev_handle_set_keycode(dev, p); 	case EVIOCGKEYCODE_V2:		return evdev_handle_get_keycode_v2(dev, p); 	case EVIOCSKEYCODE_V2:		return evdev_handle_set_keycode_v2(dev, p);	} 	size = _IOC_SIZE(cmd); 	/* Now check variable-length commands */#define EVIOC_MASK_SIZE(nr)	((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))	switch (EVIOC_MASK_SIZE(cmd)) { 	case EVIOCGPROP(0):		return bits_to_user(dev->propbit, INPUT_PROP_MAX,				    size, p, compat_mode); 	case EVIOCGMTSLOTS(0):		return evdev_handle_mt_request(dev, size, ip); 	case EVIOCGKEY(0):		return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode); 	case EVIOCGLED(0):		return bits_to_user(dev->led, LED_MAX, size, p, compat_mode); 	case EVIOCGSND(0):		return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode); 	case EVIOCGSW(0):		return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode); 	case EVIOCGNAME(0):		return str_to_user(dev->name, size, p); 	case EVIOCGPHYS(0):		return str_to_user(dev->phys, size, p); 	case EVIOCGUNIQ(0):		return str_to_user(dev->uniq, size, p); 	case EVIOC_MASK_SIZE(EVIOCSFF):		if (input_ff_effect_from_user(p, size, &effect))			return -EFAULT; 		error = input_ff_upload(dev, &effect, file); 		if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))			return -EFAULT; 		return error;	} 	/* Multi-number variable-length handlers */	if (_IOC_TYPE(cmd) != 'E')		return -EINVAL; 	if (_IOC_DIR(cmd) == _IOC_READ) { 		if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))			return handle_eviocgbit(dev,						_IOC_NR(cmd) & EV_MAX, size,						p, compat_mode); 		if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { 			if (!dev->absinfo)				return -EINVAL; 			t = _IOC_NR(cmd) & ABS_MAX;			abs = dev->absinfo[t]; 			if (copy_to_user(p, &abs, min_t(size_t,					size, sizeof(struct input_absinfo))))				return -EFAULT; 			return 0;		}	} 	if (_IOC_DIR(cmd) == _IOC_WRITE) { 		if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { 			if (!dev->absinfo)				return -EINVAL; 			t = _IOC_NR(cmd) & ABS_MAX; 			if (copy_from_user(&abs, p, min_t(size_t,					size, sizeof(struct input_absinfo))))				return -EFAULT; 			if (size < sizeof(struct input_absinfo))				abs.resolution = 0; 			/* We can't change number of reserved MT slots */			if (t == ABS_MT_SLOT)				return -EINVAL; 			/*			 * Take event lock to ensure that we are not			 * changing device parameters in the middle			 * of event.			 */			spin_lock_irq(&dev->event_lock);			dev->absinfo[t] = abs;			spin_unlock_irq(&dev->event_lock); 			return 0;		}	} 	return -EINVAL;} static long evdev_ioctl_handler(struct file *file, unsigned int cmd,				void __user *p, int compat_mode){	struct evdev_client *client = file->private_data;	struct evdev *evdev = client->evdev;	int retval; 	retval = mutex_lock_interruptible(&evdev->mutex);	if (retval)		return retval; 	if (!evdev->exist) {		retval = -ENODEV;		goto out;	} 	retval = evdev_do_ioctl(file, cmd, p, compat_mode);  out:	mutex_unlock(&evdev->mutex);	return retval;} static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg){	return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);} #ifdef CONFIG_COMPATstatic long evdev_ioctl_compat(struct file *file,				unsigned int cmd, unsigned long arg){	return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);}#endif static const struct file_operations evdev_fops = {	.owner		= THIS_MODULE,	.read		= evdev_read,	.write		= evdev_write,	.poll		= evdev_poll,	.open		= evdev_open,	.release	= evdev_release,	.unlocked_ioctl	= evdev_ioctl,#ifdef CONFIG_COMPAT	.compat_ioctl	= evdev_ioctl_compat,#endif	.fasync		= evdev_fasync,	.flush		= evdev_flush,	.llseek		= no_llseek,}; static int evdev_install_chrdev(struct evdev *evdev){	/*	 * No need to do any locking here as calls to connect and	 * disconnect are serialized by the input core	 */	evdev_table[evdev->minor] = evdev;	return 0;} static void evdev_remove_chrdev(struct evdev *evdev){	/*	 * Lock evdev table to prevent race with evdev_open()	 */	mutex_lock(&evdev_table_mutex);	evdev_table[evdev->minor] = NULL;	mutex_unlock(&evdev_table_mutex);} /* * Mark device non-existent. This disables writes, ioctls and * prevents new users from opening the device. Already posted * blocking reads will stay, however new ones will fail. */static void evdev_mark_dead(struct evdev *evdev){	mutex_lock(&evdev->mutex);	evdev->exist = false;	mutex_unlock(&evdev->mutex);} static void evdev_cleanup(struct evdev *evdev){	struct input_handle *handle = &evdev->handle; 	evdev_mark_dead(evdev);	evdev_hangup(evdev);	evdev_remove_chrdev(evdev); 	/* evdev is marked dead so no one else accesses evdev->open */	if (evdev->open) {		input_flush_device(handle, NULL);		input_close_device(handle);	}} /* * Create new evdev device. Note that input core serializes calls * to connect and disconnect so we don't need to lock evdev_table here. */static int evdev_connect(struct input_handler *handler, struct input_dev *dev,			 const struct input_device_id *id){	struct evdev *evdev;	int minor;	int error; 	for (minor = 0; minor < EVDEV_MINORS; minor++)		if (!evdev_table[minor])			break; 	if (minor == EVDEV_MINORS) {		pr_err("no more free evdev devices\n");		return -ENFILE;	} 	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);	if (!evdev)		return -ENOMEM; 	INIT_LIST_HEAD(&evdev->client_list);	spin_lock_init(&evdev->client_lock);	mutex_init(&evdev->mutex);	init_waitqueue_head(&evdev->wait); 	dev_set_name(&evdev->dev, "event%d", minor);	evdev->exist = true;	evdev->minor = minor; 	evdev->handle.dev = input_get_device(dev);	evdev->handle.name = dev_name(&evdev->dev);	evdev->handle.handler = handler;

Lines 501–1000 of 1074. Previous lines