Hi
On Sat, Apr 19, 2014 at 11:16 PM, Dmitry Torokhov
<[email protected]> wrote:
>> +static size_t evdev_get_mask_cnt(unsigned int type)
>> +{
>> + switch (type) {
>> + case 0:
>> + /* 0 is special (EV-bits instead of EV_SYN) like EVIOCGBIT */
>> + return EV_CNT;
>> + case EV_KEY:
>> + return KEY_CNT;
>> + case EV_REL:
>> + return REL_CNT;
>> + case EV_ABS:
>> + return ABS_CNT;
>> + case EV_MSC:
>> + return MSC_CNT;
>> + case EV_SW:
>> + return SW_CNT;
>> + case EV_LED:
>> + return LED_CNT;
>> + case EV_SND:
>> + return SND_CNT;
>> + case EV_FF:
>> + return FF_CNT;
>> + }
>
> Maybe we need a static array of code->count mapping instead of a switch?
Sure, I can change that.
>> +
>> + return 0;
>> +}
>> +
>> +/* must be called with evdev-mutex held */
>> +static int evdev_set_mask(struct evdev_client *client,
>> + unsigned int type,
>> + const void __user *codes,
>> + u32 codes_size)
>> +{
>> + unsigned long flags, *mask, *oldmask;
>> + size_t cnt, size;
>> +
>> + /* unknown masks are simply ignored for forward-compat */
>> + cnt = evdev_get_mask_cnt(type);
>> + if (!cnt)
>> + return 0;
>> +
>> + /* we allow 'codes_size > size' for forward-compat */
>> + size = sizeof(unsigned long) * BITS_TO_LONGS(cnt);
>> +
>> + mask = kzalloc(size, GFP_KERNEL);
>> + if (!mask)
>> + return -ENOMEM;
>> +
>> + if (copy_from_user(mask, codes, min_t(size_t, codes_size, size))) {
>> + kfree(mask);
>> + return -EFAULT;
>> + }
>> +
>> + spin_lock_irqsave(&client->buffer_lock, flags);
>> + oldmask = client->evmasks[type];
>> + client->evmasks[type] = mask;
>> + spin_unlock_irqrestore(&client->buffer_lock, flags);
>> +
>> + kfree(oldmask);
>> +
>> + return 0;
>> +}
>> +
>> +/* must be called with evdev-mutex held */
>> +static int evdev_get_mask(struct evdev_client *client,
>> + unsigned int type,
>> + void __user *codes,
>> + u32 codes_size)
>> +{
>> + unsigned long *mask;
>> + size_t cnt, size, min, i;
>> + u8 __user *out;
>> +
>> + /* we allow unknown types and 'codes_size > size' for forward-compat */
>> + cnt = evdev_get_mask_cnt(type);
>> + size = sizeof(unsigned long) * BITS_TO_LONGS(cnt);
>> + min = min_t(size_t, codes_size, size);
>> +
>> + if (cnt > 0) {
>> + mask = client->evmasks[type];
>> + if (mask) {
>> + if (copy_to_user(codes, mask, min))
>> + return -EFAULT;
>> + } else {
>> + /* fake mask with all bits set */
>> + out = (u8 __user*)codes;
>> + for (i = 0; i < min; ++i) {
>> + if (put_user((u8)0xff, out + i))
>> + return -EFAULT;
>> + }
>> + }
>> + }
>> +
>> + codes = (u8 __user*)codes + min;
>> + codes_size -= min;
>> +
>> + if (codes_size > 0 && clear_user(codes, codes_size))
>> + return -EFAULT;
>> +
>> + return 0;
>> +}
>> +
>> +/* requires the buffer lock to be held */
>> +static bool __evdev_is_masked(struct evdev_client *client,
>> + unsigned int type,
>> + unsigned int code)
>> +{
>> + unsigned long *mask;
>> + size_t cnt;
>> +
>> + /* EV_SYN and unknown codes are never masked */
>
> So won't this mean that client is still woken up by "empty" packet if we
> filter out everything but EV_SYN?
Whoops, indeed. I will skip SYN_REPORT events if the queue is empty or
if the previous event was already a SYN_REPORT.
Thanks
David
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html