最近工作中用的一个features需要在native层监听kernel层的interrupt上报,最开始使用的方式是最简单的轮询方式,native层开一个线程通过ioctrl的方式去不断的check 驱动的状态,返回check到的data,不过后面发现这样效率有些低下,而且不断的ioctrl操作驱动,功耗方面会比较大,所以就学习了使用异步通知fasync的方式+阻塞来做,下面简单总结下用法:
Kernel层:
1、定义
fasync_struct 结构体指针:
1
|
static
struct
fasync_struct *
fasync_queue
= NULL;
|
2、填充fasync_helper回调函数:
1
2
3
4
5
|
static
int
elan_fp_fasync(
int
fd,
struct
file * filp,
int
on)
{
printk(
"%s enter \n"
,__func__);
return
fasync_helper(fd, filp, on, &
fasync_queue
);
}
|
3、增加fasync回调函数到文件操作接口:
1
2
3
4
5
6
7
8
9
10
11
12
|
static
const
struct
file_operations efsa120s_fops = {
.owner = THIS_MODULE,
.open = efsa120s_open,
.read = efsa120s_read,
.write = efsa120s_write,
.unlocked_ioctl = efsa120s_ioctl,
.compat_ioctl = efsa120s_compat_ioctl,
.release = efsa120s_close,
.poll = efsa120s_poll,
.
fasync
=
elan_fp_fasync
,
};
|
4、发送异步通知:
1
2
3
4
5
6
7
8
|
static
void
efsa120s_fp_work_func(
struct
work_struct *work)
{
...
if
(fasync_queue) {
kill_fasync
(&
fasync_queue
, SIGIO, POLL_IN);
}
...
}
|
Native层:
1、fasync信号
SIGIO注册函数实现:
1
2
3
4
5
6
7
8
9
10
11
|
void
register_fasync_notify(
int
fd)
{
int
flag;
LOGD(TAG
"[%s]\n"
, __func__);
signal
(SIGIO,
fasync_input_handler
);
flag = fcntl(fd, F_GETFL);
flag |= FASYNC;
fcntl(fd, F_SETFL, flag);
fcntl(fd, F_SETOWN, getpid());
}
|
2、fasync 信号响应回调函数实现:
1
2
3
4
5
|
void
fasync_input_handler
(
int
signum)
{
LOGD(TAG
"[%s] : %d \n"
, __func__, signum);
sem_post
(&wk_sem);
//解除阻塞
}
|
3、初始化注册fasync信号监听:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
int
elan_dev_init(
void
)
{
int
fd;
int
ret;
LOGD(TAG
"-->[%s]\n"
,__func__);
if
((fd = open(DRV_ELAN, O_RDWR)) < 0)
{
LOGD(TAG
"open:%s err!\n"
, DRV_GOODIX);
return
-1;
}
register_fasync_notify
(fd);
if
(pthread_create(&thd_id, NULL, thread_update_callback, NULL) )
{
LOGD(TAG
" thd_id thread create failed.!\n"
);
return
-1;
}
...
|
4、最后是业务处理线程函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
static
void
*thread_update_callback(
void
*arg)
{
int
state = 0;
int
ret = 0;
LOGD(TAG
"[%s]\n"
,__func__);
while
(1)
{
LOGD(TAG
"sem_wait(wk_sem)...\n"
);
sem_wait
(&wk_sem);
//阻塞等待.
//do you want do anything...
}
pthread_exit(NULL);
return
NULL;
}
|