uinput.c
来自「linux 内核源代码」· C语言 代码 · 共 661 行 · 第 1/2 页
C
661 行
memcpy(dev->absflat, user_dev->absflat, size); /* check if absmin/absmax/absfuzz/absflat are filled as * told in Documentation/input/input-programming.txt */ if (test_bit(EV_ABS, dev->evbit)) { retval = uinput_validate_absbits(dev); if (retval < 0) goto exit; } udev->state = UIST_SETUP_COMPLETE; retval = count; exit: kfree(user_dev); return retval;}static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count){ struct input_event ev; if (count != sizeof(struct input_event)) return -EINVAL; if (copy_from_user(&ev, buffer, sizeof(struct input_event))) return -EFAULT; input_event(udev->dev, ev.type, ev.code, ev.value); return sizeof(struct input_event);}static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos){ struct uinput_device *udev = file->private_data; int retval; retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; retval = udev->state == UIST_CREATED ? uinput_inject_event(udev, buffer, count) : uinput_setup_device(udev, buffer, count); mutex_unlock(&udev->mutex); return retval;}static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos){ struct uinput_device *udev = file->private_data; int retval = 0; if (udev->state != UIST_CREATED) return -ENODEV; if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; retval = wait_event_interruptible(udev->waitq, udev->head != udev->tail || udev->state != UIST_CREATED); if (retval) return retval; retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; if (udev->state != UIST_CREATED) { retval = -ENODEV; goto out; } while (udev->head != udev->tail && retval + sizeof(struct input_event) <= count) { if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) { retval = -EFAULT; goto out; } udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; retval += sizeof(struct input_event); } out: mutex_unlock(&udev->mutex); return retval;}static unsigned int uinput_poll(struct file *file, poll_table *wait){ struct uinput_device *udev = file->private_data; poll_wait(file, &udev->waitq, wait); if (udev->head != udev->tail) return POLLIN | POLLRDNORM; return 0;}static int uinput_release(struct inode *inode, struct file *file){ struct uinput_device *udev = file->private_data; uinput_destroy_device(udev); kfree(udev); return 0;}#define uinput_set_bit(_arg, _bit, _max) \({ \ int __ret = 0; \ if (udev->state == UIST_CREATED) \ __ret = -EINVAL; \ else if ((_arg) > (_max)) \ __ret = -EINVAL; \ else set_bit((_arg), udev->dev->_bit); \ __ret; \})static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ int retval; struct uinput_device *udev; void __user *p = (void __user *)arg; struct uinput_ff_upload ff_up; struct uinput_ff_erase ff_erase; struct uinput_request *req; int length; char *phys; udev = file->private_data; retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; if (!udev->dev) { retval = uinput_allocate_device(udev); if (retval) goto out; } switch (cmd) { case UI_DEV_CREATE: retval = uinput_create_device(udev); break; case UI_DEV_DESTROY: uinput_destroy_device(udev); break; case UI_SET_EVBIT: retval = uinput_set_bit(arg, evbit, EV_MAX); break; case UI_SET_KEYBIT: retval = uinput_set_bit(arg, keybit, KEY_MAX); break; case UI_SET_RELBIT: retval = uinput_set_bit(arg, relbit, REL_MAX); break; case UI_SET_ABSBIT: retval = uinput_set_bit(arg, absbit, ABS_MAX); break; case UI_SET_MSCBIT: retval = uinput_set_bit(arg, mscbit, MSC_MAX); break; case UI_SET_LEDBIT: retval = uinput_set_bit(arg, ledbit, LED_MAX); break; case UI_SET_SNDBIT: retval = uinput_set_bit(arg, sndbit, SND_MAX); break; case UI_SET_FFBIT: retval = uinput_set_bit(arg, ffbit, FF_MAX); break; case UI_SET_SWBIT: retval = uinput_set_bit(arg, swbit, SW_MAX); break; case UI_SET_PHYS: if (udev->state == UIST_CREATED) { retval = -EINVAL; goto out; } length = strnlen_user(p, 1024); if (length <= 0) { retval = -EFAULT; break; } kfree(udev->dev->phys); udev->dev->phys = phys = kmalloc(length, GFP_KERNEL); if (!phys) { retval = -ENOMEM; break; } if (copy_from_user(phys, p, length)) { udev->dev->phys = NULL; kfree(phys); retval = -EFAULT; break; } phys[length - 1] = '\0'; break; case UI_BEGIN_FF_UPLOAD: if (copy_from_user(&ff_up, p, sizeof(ff_up))) { retval = -EFAULT; break; } req = uinput_request_find(udev, ff_up.request_id); if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { retval = -EINVAL; break; } ff_up.retval = 0; memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); if (req->u.upload.old) memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); else memset(&ff_up.old, 0, sizeof(struct ff_effect)); if (copy_to_user(p, &ff_up, sizeof(ff_up))) { retval = -EFAULT; break; } break; case UI_BEGIN_FF_ERASE: if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { retval = -EFAULT; break; } req = uinput_request_find(udev, ff_erase.request_id); if (!(req && req->code == UI_FF_ERASE)) { retval = -EINVAL; break; } ff_erase.retval = 0; ff_erase.effect_id = req->u.effect_id; if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { retval = -EFAULT; break; } break; case UI_END_FF_UPLOAD: if (copy_from_user(&ff_up, p, sizeof(ff_up))) { retval = -EFAULT; break; } req = uinput_request_find(udev, ff_up.request_id); if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { retval = -EINVAL; break; } req->retval = ff_up.retval; uinput_request_done(udev, req); break; case UI_END_FF_ERASE: if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { retval = -EFAULT; break; } req = uinput_request_find(udev, ff_erase.request_id); if (!(req && req->code == UI_FF_ERASE)) { retval = -EINVAL; break; } req->retval = ff_erase.retval; uinput_request_done(udev, req); break; default: retval = -EINVAL; } out: mutex_unlock(&udev->mutex); return retval;}static const struct file_operations uinput_fops = { .owner = THIS_MODULE, .open = uinput_open, .release = uinput_release, .read = uinput_read, .write = uinput_write, .poll = uinput_poll, .unlocked_ioctl = uinput_ioctl,};static struct miscdevice uinput_misc = { .fops = &uinput_fops, .minor = UINPUT_MINOR, .name = UINPUT_NAME,};static int __init uinput_init(void){ return misc_register(&uinput_misc);}static void __exit uinput_exit(void){ misc_deregister(&uinput_misc);}MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");MODULE_DESCRIPTION("User level driver support for input subsystem");MODULE_LICENSE("GPL");MODULE_VERSION("0.3");module_init(uinput_init);module_exit(uinput_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?