/* * Event char devices, giving access to raw input device events. * * Copyright (c) 1999-2002 Vojtech Pavlik * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt#define EVDEV_MINOR_BASE 64#define EVDEV_MINORS 32#define EVDEV_MIN_BUFFER_SIZE 64U#define EVDEV_BUF_PACKETS 8#include<linux/poll.h>#include<linux/sched.h>#include<linux/slab.h>#include<linux/vmalloc.h>#include<linux/mm.h>#include<linux/module.h>#include<linux/init.h>#include<linux/input/mt.h>#include<linux/major.h>#include<linux/device.h>#include<linux/cdev.h>#include"input-compat.h"structevdev{intopen;structinput_handlehandle;wait_queue_head_twait;structevdev_client__rcu*grab;structlist_headclient_list;spinlock_tclient_lock;/* protects client_list */structmutexmutex;structdevicedev;structcdevcdev;boolexist;};structevdev_client{unsignedinthead;unsignedinttail;unsignedintpacket_head;/* [future] position of the first element of next packet */spinlock_tbuffer_lock;/* protects access to buffer, head and tail */structfasync_struct*fasync;structevdev*evdev;structlist_headnode;intclkid;boolrevoked;unsignedintbufsize;structinput_eventbuffer[];};/* flush queued events of type @type, caller must hold client->buffer_lock */staticvoid__evdev_flush_queue(structevdev_client*client,unsignedinttype){unsignedinti,head,num;unsignedintmask=client->bufsize-1;boolis_report;structinput_event*ev;BUG_ON(type==EV_SYN);head=client->tail;client->packet_head=client->tail;/* init to 1 so a leading SYN_REPORT will not be dropped */num=1;for(i=client->tail;i!=client->head;i=(i+1)&mask){ev=&client->buffer[i];is_report=ev->type==EV_SYN&&ev->code==SYN_REPORT;if(ev->type==type){/* drop matched entry */continue;}elseif(is_report&&!num){/* drop empty SYN_REPORT groups */continue;}elseif(head!=i){/* move entry to fill the gap */client->buffer[head].time=ev->time;client->buffer[head].type=ev->type;client->buffer[head].code=ev->code;client->buffer[head].value=ev->value;}num++;head=(head+1)&mask;if(is_report){num=0;client->packet_head=head;}}client->head=head;}/* queue SYN_DROPPED event */staticvoidevdev_queue_syn_dropped(structevdev_client