input 서브시스템의 분석과 학습(二)

10236 단어
다음은 자신이 실현한 광센서의 구동을 분석해 보겠습니다.먼저 코드를 첨부합니다.
 
#include    
#include    
#include    
#include    
#include    
#include    
#include    
#include 
#include 

#define EVENT_TYPE_LIGHT  ABS_MISC
#define LIGHTSENSOR_NAME  "lightsensor"
#define S5PV210_SENSOR_CHANNEL   2
#define INIT_POLL_INTERVAL  10000

#define sensor_dbg(format, arg...) do {		\
		printk("%s : " format , __func__,  ## arg) ;\
} while (0)

static DEFINE_MUTEX(sensor_mutex);


MODULE_LICENSE("GPL");  
MODULE_DESCRIPTION("Light Sensor Driver");  

struct lightsensor_data {
		struct input_polled_dev *input_poll_dev;
		atomic_t enabled;
		int  light_value;
};
static struct lightsensor_data *sensor_data;
static int poll_cnt = 0;

static int lightsensor_set_value(struct lightsensor_data *sensor, int value)
{
	mutex_lock(&sensor_mutex);
	sensor->light_value =  value;
	mutex_unlock(&sensor_mutex);
	return 0;
}

static int lightsensor_get_value(struct lightsensor_data *sensor)
{
	printk("%s  %d
", __func__, sensor->light_value); int ret; mutex_lock(&sensor_mutex); ret = sensor->light_value ; mutex_unlock(&sensor_mutex); return ret; } void lightsensor_input_poll_func(struct input_polled_dev *input) { struct lightsensor_data *sensor = input->private; u32 enabled = atomic_read(&sensor->enabled); printk("%s, sensor %p enabled: %u, light_value: %d poll_rate: %d
", __func__, sensor, enabled, sensor->light_value, sensor->input_poll_dev->poll_interval); if(enalbed) { // int value = mini2440_adc_get_light(); int value = poll_cnt++; input_event(input->input, EV_FF, EVENT_TYPE_LIGHT, value); input_sync(input->input); sensor_dbg("input_report
"); // lightsensor_set_value( sensor, value); } //else // sensor_dbg("input_not report
"); } static int lightsensor_enable(struct lightsensor_data *sensor) { // open the input dev struct input_dev* input = sensor->input_poll_dev->input; atomic_cmpxchg(&sensor->enabled, 0, 1); return 0; } static int lightsensor_disable(struct lightsensor_data *sensor) { // close the input dev struct input_dev* input = sensor->input_poll_dev->input; atomic_cmpxchg(&sensor->enabled, 1, 0) ; return 0; } static ssize_t attr_polling_rate_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned int val; struct lightsensor_data *sensor = sensor_data; mutex_lock(&sensor_mutex); val = sensor->input_poll_dev->poll_interval; mutex_unlock(&sensor_mutex); return sprintf(buf, "%u
", val); } static ssize_t attr_polling_rate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct lightsensor_data *sensor = sensor_data; long interval_ms; if (strict_strtol(buf, 10, &interval_ms)) return -EINVAL; if (!interval_ms) return -EINVAL; mutex_lock(&sensor_mutex); sensor->input_poll_dev->poll_interval = interval_ms; mutex_unlock(&sensor_mutex); return size; } static ssize_t attr_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lightsensor_data *sensor = sensor_data; u32 val = atomic_read(&sensor->enabled); return sprintf(buf, "%d
", val); } static ssize_t attr_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct lightsensor_data *sensor = sensor_data; unsigned long val; if (strict_strtoul(buf, 10, &val)) return -EINVAL; if (val) lightsensor_enable(sensor); else lightsensor_disable(sensor); return size; } static ssize_t attr_light_value_show(struct device *dev, struct device_attribute *attr, char *buf) { //input_get_drvdata is obidient here, because input_get_drvdata = sensor_data->input_poll_dev struct lightsensor_data *sensor = sensor_data; int val = lightsensor_get_value(sensor); printk("%s: sensor_data %p, sensor %p val %d
", __func__, sensor_data, sensor, val); return sprintf(buf, "%d
", val); } static struct device_attribute attributes[] = { __ATTR(pollrate_ms, 0666, attr_polling_rate_show, attr_polling_rate_store), __ATTR(enable_device, 0666, attr_enable_show, attr_enable_store), __ATTR(light_value, 0444, attr_light_value_show, NULL), }; static int create_sysfs_interfaces(struct device *dev) { int i; for (i = 0; i < ARRAY_SIZE(attributes); i++) if (device_create_file(dev, attributes + i)) goto error; return 0; error: printk("%s error, i = %d
", __func__, i ); for ( ; i >= 0; i--) device_remove_file(dev, attributes + i); dev_err(dev, "%s:Unable to create interface
", __func__); return -1; } static int remove_sysfs_interfaces(struct device *dev) { int i; for (i = 0; i < ARRAY_SIZE(attributes); i++) device_remove_file(dev, attributes + i); return 0; } static int __init lightsensor_init(void) { int ret = -1; struct input_dev *input; sensor_data= kmalloc(sizeof(struct lightsensor_data), GFP_KERNEL) ; if(!sensor_data) { printk("kmalloc
"); goto kmalloc_error; } sensor_data->input_poll_dev = input_allocate_polled_device(); if(! sensor_data->input_poll_dev) { sensor_dbg("error
"); goto alloc_error; } sensor_data->input_poll_dev->private = sensor_data; sensor_data->input_poll_dev->poll = lightsensor_input_poll_func; sensor_data->input_poll_dev->poll_interval = INIT_POLL_INTERVAL; input = sensor_data->input_poll_dev->input; input->name = LIGHTSENSOR_NAME; //input_set_drvdata(sensor_data->input_poll_dev->input, sensor_data); set_bit(EV_FF, input->evbit); ret = input_register_polled_device(sensor_data->input_poll_dev); if(ret) { printk("input_register_polled_device error
"); return ret; } sensor_dbg("
"); atomic_set(&sensor_data->enabled, 0); sensor_data->light_value = 88; printk("%s sensor->light_value:%d
", __func__, sensor_data->light_value); if ( create_sysfs_interfaces(&input->dev) ) { printk("create_sysfs_interface failed
"); goto sys_error; } return ret; sys_error: input_unregister_polled_device(sensor_data->input_poll_dev); alloc_error: kfree(sensor_data); kmalloc_error: return ret; } static void __exit lightsensor_exit(void) { remove_sysfs_interfaces( &sensor_data->input_poll_dev->input->dev); input_unregister_polled_device(sensor_data->input_poll_dev); input_free_polled_device(sensor_data->input_poll_dev); kfree(sensor_data); } module_init(lightsensor_init); module_exit(lightsensor_exit);

나는 이 장치를 하나의 input 로 실현했다poll_dev, 이 설비의 구체적인 실현은driver/input/input-polldev입니다.c 중의.우리는 여기에 그것의 모형을 하나 썼다.우리의 광센서가 해야 할 일은 주기적으로 응용 프로그램에 빛의 값을 보고하는 것이기 때문이다.한편, input-polldev는 바로 이 기능을 실현했다. 구체적으로 말하자면 우리의 광센서는 주로 Poll이라는 함수를 실현해야 한다.이 광센서를 제어하기 위해sysfs의 인터페이스enable,pollrate,light 추가value.Inut 서브시스템을 활용하면 드라이브를 쓸 때 매우 편리함을 볼 수 있습니다.
 
사용자 상태에 해당하는 응용 프로그램은 다음과 같습니다.
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INPUTFILE "/dev/input/event0"
int gotdata=0;
void sighandler(int signo)
{
	if (signo==SIGIO)
		gotdata++;
	return;
}

char buffer[4096];

int main(int argc, char **argv)
{
	int count;
	struct sigaction action;
	struct input_event event;
    int fd = open(INPUTFILE, O_RDONLY);
	memset(&action, 0, sizeof(action));
	action.sa_handler = sighandler;
	action.sa_flags = 0;

	sigaction(SIGIO, &action, NULL);

	fcntl(fd, F_SETOWN, getpid());
	fcntl(fd, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);

	while(1) {
		/* this only returns if a signal arrives */
		sleep(86400); /* one day */
		if (!gotdata)
			continue;
		count=read(fd, &event, sizeof(event));
		printf("event: %d %d %d
", event.type, event.code, event.value); /* buggy: if avail data is more than 4kbytes... */ gotdata=0; } }

 
처음에 이 input 서브시스템을 보았을 때 리포트가 이벤트를 구동하는 것을 알았지만 어디로 읽어야 할지 몰라서 반나절 동안 연구를 했습니다.드디어 실행 가능한 파일을 찾았습니다./dev/input/inputX 파일입니다.그 중에서/dev/input/는/dev 시스템에 디렉터리를 만들었고 device 를 사용했을 것입니다create 인터페이스에서 만들었지만, 현재/dev 아래에서directory를 만드는 방법은 명확하지 않습니다.내일 봐요.
 
이렇게 input 서브시스템을 이용하여 광센서의 구동을 다 썼다.부호량이 매우 적다.
또한 input 서브시스템에서 이벤트의 보고는 비동기적인 메커니즘을 사용한다. 즉, 리포트 이벤트를 할 때도 응용 프로그램에 SIGIO 신호를 보내기 때문에 응용 프로그램에서 file를 비동기 모드로 설정하면 SIGNO 신호를 읽고 인터럽트 프로그램에서 신호를 읽을 수 있다.이벤트는 예측할 수 없기 때문에 비동기적인 방식으로 더욱 과학적이다.
 
내가 이 드라이브를 쓸 때 저지른 실수를 기록해 봐. 내가 오랫동안 디버깅을 했어.
1. 우선lightsensor를 쓰고 있습니다.c시, inputdev에서 자체 read\write 함수를 등록했습니다.폴 함수를 등록하는 것처럼
sensor_data->input_poll_dev->read = lightsensor_input_read_func;그러나 이 함수들은 항상 호출되지 않는다.나중에 보니 input 을 호출하고 있었어요.register_polled_device(sensor data->input poll dev)일 때 새 open\read\write 함수를 등록하고 open 시 delayd work queue를 만듭니다.그래서 저희가 인풋으로...poll_dev시 poll 함수만 실현하면 됩니다. 다른 함수를 등록하고 inpu 를 바꾸면 됩니다.poll_dev 자체의 함수는 이 장치가 정상적으로 작동하지 못하게 할 수 있습니다.
2.sysfs에 대한 오류, 이 오류는 자신도 오랫동안 디버깅을 했습니다.사실 인풋 때문에...get_drvdata와 inputset_drvdata의 사용이 잘못되었습니다.라이트센스에 있습니다.c에서 dev의private를 설정, inputset_drvdata(sensor_data->input_poll_dev->input, sensor_data); 그리고 sysfs의 static ssizet attr_polling_rate_store(struct device *dev, struct device attribute *attr, const char *buf, size t size) 함수에서 input 호출get_drvdata, 그러나 얻은 바늘이 가리키는 것은sensor 가 아닙니다data. 나는sysfs의 사용 오류인 줄 알고 오랫동안 디버깅을 했다.결국 input에서poll_dev에서도 이 함수를 사용했습니다. 이 바늘을 다른 곳으로 가리켰습니다.그래서 이것은 더욱 설명한다. 우리가 input을 바탕으로 하는poll_dev 구현된 장치 중 input 을 사용할 수 없습니다poll_dev에 사용되는 inputdev 방법.프로그래밍을 할 때는 매우 주의해야 한다. 그렇지 않으면 작은 실수로 인해 디버깅을 오랫동안 할 수 있다.
 
내일 INPUT 서브시스템의 몇 가지 중요한 구조체를 계속 분석합니다.
 

좋은 웹페이지 즐겨찾기