9x25 PPS 驱动框架分析 2016.07.14

it2022-05-09  27

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, ¶ms, sizeof(struct pps_kparams)); case PPS_SETPARAMS: copy_from_user(¶ms, 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);

转载于:https://www.cnblogs.com/liushuhe1990/p/9608993.html


最新回复(0)