/* Atomically allocate an ID for the given request. Returns 0 on success. */ staticbool uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request)
{ unsignedint id; bool reserved = false;
spin_lock(&udev->requests_lock);
for (id = 0; id < UINPUT_NUM_REQUESTS; id++) { if (!udev->requests[id]) {
request->id = id;
udev->requests[id] = request;
reserved = true; break;
}
}
staticstruct uinput_request *uinput_request_find(struct uinput_device *udev, unsignedint id)
{ /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ if (id >= UINPUT_NUM_REQUESTS) return NULL;
return udev->requests[id];
}
staticint uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request)
{ /* Allocate slot. If none are available right away, wait. */ return wait_event_interruptible(udev->requests_waitq,
uinput_request_alloc_id(udev, request));
}
staticvoid uinput_request_release_slot(struct uinput_device *udev, unsignedint id)
{ /* Mark slot as available */
spin_lock(&udev->requests_lock);
udev->requests[id] = NULL;
spin_unlock(&udev->requests_lock);
wake_up(&udev->requests_waitq);
}
staticint uinput_request_send(struct uinput_device *udev, struct uinput_request *request)
{ int retval;
retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval;
/* * Tell our userspace application about this new request * by queueing an input event.
*/
uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
out:
mutex_unlock(&udev->mutex); return retval;
}
staticint uinput_request_submit(struct uinput_device *udev, struct uinput_request *request)
{ int retval;
retval = uinput_request_reserve_slot(udev, request); if (retval) return retval;
retval = uinput_request_send(udev, request); if (retval) goto out;
/* * Fail all outstanding requests so handlers don't wait for the userspace * to finish processing them.
*/ staticvoid uinput_flush_requests(struct uinput_device *udev)
{ struct uinput_request *request; int i;
spin_lock(&udev->requests_lock);
for (i = 0; i < UINPUT_NUM_REQUESTS; i++) {
request = udev->requests[i]; if (request) {
request->retval = -ENODEV;
complete(&request->done);
}
}
/* * uinput driver does not currently support periodic effects with * custom waveform since it does not have a way to pass buffer of * samples (custom_data) to userspace. If ever there is a device * supporting custom waveforms we would need to define an additional * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out.
*/ if (effect->type == FF_PERIODIC &&
effect->u.periodic.waveform == FF_CUSTOM) return -EINVAL;
staticint uinput_dev_flush(struct input_dev *dev, struct file *file)
{ /* * If we are called with file == NULL that means we are tearing * down the device, and therefore we can not handle FF erase * requests: either we are handling UI_DEV_DESTROY (and holding * the udev->mutex), or the file descriptor is closed and there is * nobody on the other side anymore.
*/ return file ? input_ff_flush(dev, file) : 0;
}
if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",
UINPUT_NAME);
error = -EINVAL; goto fail1;
}
if (udev->ff_effects_max) {
error = input_ff_create(dev, udev->ff_effects_max); if (error) goto fail1;
dev->ff->upload = uinput_dev_upload_effect;
dev->ff->erase = uinput_dev_erase_effect;
dev->ff->playback = uinput_dev_playback;
dev->ff->set_gain = uinput_dev_set_gain;
dev->ff->set_autocenter = uinput_dev_set_autocenter; /* * The standard input_ff_flush() implementation does * not quite work for uinput as we can't reasonably * handle FF requests during device teardown.
*/
dev->flush = uinput_dev_flush;
}
dev->event = uinput_dev_event;
input_set_drvdata(udev->dev, udev);
error = input_register_device(udev->dev); if (error) goto fail2;
if ((min != 0 || max != 0) && max < min) {
printk(KERN_DEBUG "%s: invalid abs[%02x] min:%d max:%d\n",
UINPUT_NAME, code, min, max); return -EINVAL;
}
if (!check_sub_overflow(max, min, &range) && abs->flat > range) {
printk(KERN_DEBUG "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
UINPUT_NAME, code, abs->flat, min, max); return -EINVAL;
}
/* * Limit number of contacts to a reasonable value (100). This * ensures that we need less than 2 pages for struct input_mt * (we are not using in-kernel slot assignment so not going to * allocate memory for the "red" table), and we should have no * trouble getting this much memory.
*/ if (code == ABS_MT_SLOT && max > 99) {
printk(KERN_DEBUG "%s: unreasonably large number of slots requested: %d\n",
UINPUT_NAME, max); return -EINVAL;
}
return 0;
}
staticint uinput_validate_absbits(struct input_dev *dev)
{ unsignedint cnt; int error;
if (!test_bit(EV_ABS, dev->evbit)) return 0;
/* * Check if absmin/absmax/absfuzz/absflat are sane.
*/
for_each_set_bit(cnt, dev->absbit, ABS_CNT) { if (!dev->absinfo) return -EINVAL;
error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]); if (error) return error;
}
for (i = 0; i < ABS_CNT; i++) {
input_abs_set_max(dev, i, user_dev->absmax[i]);
input_abs_set_min(dev, i, user_dev->absmin[i]);
input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]);
input_abs_set_flat(dev, i, user_dev->absflat[i]);
}
retval = uinput_validate_absbits(dev); if (retval < 0) gotoexit;
/* * Returns true if the given timestamp is valid (i.e., if all the following * conditions are satisfied), false otherwise. * 1) given timestamp is positive * 2) it's within the allowed offset before the current time * 3) it's not in the future
*/ staticbool is_valid_timestamp(const ktime_t timestamp)
{
ktime_t zero_time;
ktime_t current_time;
ktime_t min_time;
ktime_t offset;
zero_time = ktime_set(0, 0); if (ktime_compare(zero_time, timestamp) >= 0) returnfalse;
if (count != 0 && count < input_event_size()) return -EINVAL;
while (bytes + input_event_size() <= count) { /* * Note that even if some events were fetched successfully * we are still going to return EFAULT instead of partial * count to let userspace know that it got it's buffers * all wrong.
*/ if (input_event_from_user(buffer + bytes, &ev)) return -EFAULT;
timestamp = ktime_set(ev.input_event_sec, ev.input_event_usec * NSEC_PER_USEC); if (is_valid_timestamp(timestamp))
input_set_timestamp(udev->dev, timestamp);
memset(&ff_up_compat, 0, sizeof(ff_up_compat));
ff_up_compat.request_id = ff_up->request_id;
ff_up_compat.retval = ff_up->retval; /* * It so happens that the pointer that gives us the trouble * is the last field in the structure. Since we don't support * custom waveforms in uinput anyway we can just copy the whole * thing (to the compat size) and ignore the pointer.
*/
memcpy(&ff_up_compat.effect, &ff_up->effect, sizeof(struct ff_effect_compat));
memcpy(&ff_up_compat.old, &ff_up->old, sizeof(struct ff_effect_compat));
if (copy_to_user(buffer, &ff_up_compat, sizeof(struct uinput_ff_upload_compat))) return -EFAULT;
} else { if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) return -EFAULT;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.