input 서브시스템의 분석과 학습(二)
#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 서브시스템의 몇 가지 중요한 구조체를 계속 분석합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.