9x25 PPS 驱动框架分析 2016.07.14

9x25 PPS 驱动框架分析 2016.07.14

Device Drivers --->
PPS support --->
[*] GPIO support
[*] PPS kernel consumer support
< > PPS line discipline (NEW)
在内核搜索 grep "PPS kernel consumer support" * -nR
drivers/pps/Kconfig:34: bool "PPS kernel consumer support"
查看Kconfig
config NTP_PPS
bool "PPS kernel consumer support"
depends on PPS && !NO_HZ
help
This option adds support for direct in-kernel time
synchronization using an external PPS signal.
搜索 grep "NTP_PPS" * -nR
drivers/pps/Makefile:6:pps_core-$(CONFIG_NTP_PPS) += kc.o

再次搜索 grep "GPIO support" * -nR
drivers/pps/clients/Kconfig:19: bool "GPIO support"
查看Kconfig
config PPS_CLIENT_GPIO
bool "GPIO support"
help
If you say yes here you get support for a PPS source based
on a gpio pin(must support IRQ).

搜索 gerp "PPS_CLIENT_GPIO" * -nR
drivers/pps/clients/Makefile:8:obj-$(CONFIG_PPS_CLIENT_GPIO) += pps-gpio.o

再次搜索 grep "PPS line discipline" * -nR
drivers/pps/clients/Kconfig:28: tristate "PPS line discipline"
查看Kconfig
config PPS_CLIENT_LDISC
tristate "PPS line discipline"
depends on PPS && !PPS_CLIENT_GPIO
help
If you say yes here you get support for a PPS source connected
with the CD (Carrier Detect) pin of your serial port.
搜索 grep "PPS_CLIENT_LDISC" * -nR
drivers/pps/clients/Makefile:6:obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o

可以看出PPS 一共调用3个文件
[*] PPS kernel consumer support 调用 drivers/pps/clients/kc.c
< > PPS line discipline (NEW) 调用 drivers/pps/clients/pps-ldisc.c
[*] GPIO support 王工写的 调用 drivers/pps/clients/pps-gpio.c

分析 kc.c

查看源码发现,kc.c应该是PPS总线核心层,它只提供PPS相关的函数,并不是驱动
PPS核心层 kc.c 定义的函数如下:
//根据传入的参数绑定或取消内核线程,在中断上下文这个函数不能被调用
int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)

//移除内核绑定的pps线程
void pps_kc_remove(struct pps_device *pps)

//绑定PPS源事件时发生,这个函数调用hardpps()
void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts,int event)
hardpps(&ts->ts_real, &ts->ts_raw);
注:hardpps 在\kernel\time\Ntp.c 里定义,这里先不分析

分析PPS的核心层,谁在调用pps_kc_bind ,source insight 搜索发现 只有一个文件调用
\drivers\pps\Pps.c
static const struct file_operations pps_cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.poll = pps_cdev_poll,
.fasync = pps_cdev_fasync,
.unlocked_ioctl = pps_cdev_ioctl,
.open = pps_cdev_open,
.release = pps_cdev_release,
};
调用过程
pps_cdev_ioctl
switch (cmd)
case PPS_GETPARAMS:
copy_to_user(uarg, &params, sizeof(struct pps_kparams));
case PPS_SETPARAMS:
copy_from_user(&params, uarg, sizeof(struct pps_kparams));
case PPS_GETCAP:
put_user(pps->info.mode, iuarg);
case PPS_FETCH:
copy_from_user(&fdata, uarg, sizeof(struct pps_fdata))
wait_event_interruptible
wait_event_interruptible_timeout
copy_to_user(uarg, &fdata, sizeof(struct pps_fdata))
case PPS_KC_BIND:
copy_from_user
pps_kc_bind(pps, &bind_args); //这个函数就是向内核注册一个PPS线程

pps_cdev_ioctl 是在 pps_cdev_fops里定义,他是在pps_register_cdev里调用
//这个函数在\drivers\pps\Kapi.c里调用
pps_register_source
pps_register_cdev(pps);
cdev_init(&pps->cdev, &pps_cdev_fops);
//pps驱动层,初始化
__init pps_init(void)
pps_class = class_create(THIS_MODULE, "pps");
alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");

分析PPS的核心层,谁在调用pps_kc_remove ,source insight 搜索发现 只有一个文件调用
\drivers\pps\Kapi.c
void pps_unregister_source(struct pps_device *pps)
{
pps_kc_remove(pps);
pps_unregister_cdev(pps);
}
分析PPS的核心层,谁在调用pps_kc_event ,source insight 搜索发现 只有一个文件调用
\drivers\pps\Kapi.c
void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
pps_kc_event(pps, ts, event);
/* Wake up if captured something */
if (captured) {
pps->last_ev++;
wake_up_interruptible_all(&pps->queue);

kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
}
搜索pps_register_source ,发现一共有4个设备调用
drivers\pps\clients\Pps-gpio.c 王工所写
\drivers\pps\clients\Pps-ktimer.c
\drivers\pps\clients\Pps-ldisc.c
\drivers\pps\clients\Pps_parport.c


通过上面的分析,kc.c应该是PPS的核心层,kapi.c、pps.c是pps驱动层,Pps-gpio.c、Pps-ktimer.c、Pps-ldisc.c、Pps_parport.c是PPS设备层
//kc.c 提供3个函数,供驱动调用
pps_kc_bind
pps_kc_remove
pps_kc_event
//kapi.c 是驱动层,提供4个函数
pps_register_source
pps_unregister_source
pps_event
pps_add_offset
//pps.c是驱动层,提供1个函数,1个file_operations结构体
static const struct file_operations pps_cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.poll = pps_cdev_poll,
.fasync = pps_cdev_fasync,
.unlocked_ioctl = pps_cdev_ioctl,
.open = pps_cdev_open,
.release = pps_cdev_release,
};

pps_register_cdev
pps_device_destruct
pps_unregister_cdev

//对于PPS设备层,基本调用pps_register_source函数即可,这里分析 王工的Pps-gpio.c
//Pps-gpio.c
static struct pps_source_info pps_gpio_info = {
.name = "pps-gpio",
.path = "",
/* .mode = PPS_CAPTUREBOTH | \
PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
PPS_ECHOASSERT | PPS_ECHOCLEAR | \
PPS_CANWAIT | \
PPS_TSFMT_TSPEC, */
.mode = PPS_CAPTUREASSERT | \
PPS_OFFSETASSERT | \
PPS_ECHOASSERT | \
PPS_CANWAIT | \
PPS_TSFMT_TSPEC,
.echo = pps_gpio_echo,
.owner = THIS_MODULE,
.dev = NULL,
};

pps_gpio_init
pps_register_source(&pps_gpio_info, PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
struct pps_device *pps;
pps_register_cdev(pps);

static const struct file_operations pps_cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.poll = pps_cdev_poll,
.fasync = pps_cdev_fasync,
.unlocked_ioctl = pps_cdev_ioctl,
.open = pps_cdev_open,
.release = pps_cdev_release,
};

devt = MKDEV(MAJOR(pps_devt), pps->id);
cdev_init(&pps->cdev, &pps_cdev_fops);
err = cdev_add(&pps->cdev, devt, 1);
pps->dev = device_create(pps_class, pps->info.dev, devt, pps,"pps%d", pps->id);

at91_set_gpio_input(AT91_PIN_PB17, 0);
at91_set_deglitch(AT91_PIN_PB17, 1);
ret = request_irq(AT91_PIN_PB17, pps_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "PPS-GPIO", NULL);

//PPS中断
pps_gpio_isr
pps_get_ts(&ts);
at91_get_gpio_value(AT91_PIN_PB17)
pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);

//struct file_operations pps_cdev_fops定义的open函数怎么被调用呢
//用户空间调用open会在内核产生一个软件中断 swi handler ,
这个需要分析内核源代码
\arch\arm\kernel\entry-common.S
.type sys_call_table, #object
ENTRY(sys_call_table)
#include "calls.S"
打开 calls.S
CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
CALL(sys_open)
CALL(sys_close)
可见内核会调用 sys_open
SYSCALL_DEFINE3
do_sys_open
char *tmp = getname(filename);
get_unused_fd_flags(flags);
alloc_fd
find_next_zero_bit
do_filp_open
path_openat
do_last
nameidata_to_filp
__dentry_open
if (!open && f->f_op)
open = f->f_op->open;
//这里就是调用系统之前注册的file_operations里面的open函数
fd_install(fd, f);



















posted on 2018-09-08 13:36  紫枫术河  阅读(1775)  评论(0编辑  收藏  举报

导航