711 lines · 17.0 KB · C
RawDownload
		default: 			if (_IOC_TYPE(cmd) != 'E')				return -EINVAL; 			if (_IOC_DIR(cmd) == _IOC_READ) { 				if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { 					long *bits;					int len; 					switch (_IOC_NR(cmd) & EV_MAX) {						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;					}					return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);				} 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))					return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),							    p, compat_mode); 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))					return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),							    p, compat_mode); 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))					return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),							    p, compat_mode); 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))					return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),							    p, compat_mode); 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))					return str_to_user(dev->name, _IOC_SIZE(cmd), p); 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))					return str_to_user(dev->phys, _IOC_SIZE(cmd), p); 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))					return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); 				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { 					int t = _IOC_NR(cmd) & ABS_MAX; 					abs.value = dev->abs[t];					abs.minimum = dev->absmin[t];					abs.maximum = dev->absmax[t];					abs.fuzz = dev->absfuzz[t];					abs.flat = dev->absflat[t]; 					if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))						return -EFAULT; 					return 0;				} 			} 			if (_IOC_DIR(cmd) == _IOC_WRITE) { 				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { 					int t = _IOC_NR(cmd) & ABS_MAX; 					if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))						return -EFAULT; 					dev->abs[t] = abs.value;					dev->absmin[t] = abs.minimum;					dev->absmax[t] = abs.maximum;					dev->absfuzz[t] = abs.fuzz;					dev->absflat[t] = abs.flat; 					return 0;				}			}	}	return -EINVAL;} 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 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}; static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id){	struct evdev *evdev;	struct class_device *cdev;	int minor; 	for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);	if (minor == EVDEV_MINORS) {		printk(KERN_ERR "evdev: no more free evdev devices\n");		return NULL;	} 	if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))		return NULL; 	INIT_LIST_HEAD(&evdev->list);	init_waitqueue_head(&evdev->wait); 	evdev->exist = 1;	evdev->minor = minor;	evdev->handle.dev = dev;	evdev->handle.name = evdev->name;	evdev->handle.handler = handler;	evdev->handle.private = evdev;	sprintf(evdev->name, "event%d", minor); 	evdev_table[minor] = evdev; 	cdev = class_device_create(&input_class, &dev->cdev,			MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),			dev->cdev.dev, evdev->name); 	/* temporary symlink to keep userspace happy */	sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,			  evdev->name); 	return &evdev->handle;} static void evdev_disconnect(struct input_handle *handle){	struct evdev *evdev = handle->private;	struct evdev_list *list; 	sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);	class_device_destroy(&input_class,			MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));	evdev->exist = 0; 	if (evdev->open) {		input_close_device(handle);		wake_up_interruptible(&evdev->wait);		list_for_each_entry(list, &evdev->list, node)			kill_fasync(&list->fasync, SIGIO, POLL_HUP);	} else		evdev_free(evdev);} static 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,	.connect =	evdev_connect,	.disconnect =	evdev_disconnect,	.fops =		&evdev_fops,	.minor =	EVDEV_MINOR_BASE,	.name =		"evdev",	.id_table =	evdev_ids,}; static int __init evdev_init(void){	input_register_handler(&evdev_handler);	return 0;} static void __exit evdev_exit(void){	input_unregister_handler(&evdev_handler);} module_init(evdev_init);module_exit(evdev_exit); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");MODULE_DESCRIPTION("Input driver event char devices");MODULE_LICENSE("GPL");

Lines 501–711 of 711. Previous lines