linux c监控rtc秒,Linux RTC驱动分析(二)----rtc-dev.c和interface.c

在第一部分中,rtc_device_register函数调用了rtc-dev.c中的rtc_dev_prepare。

void rtc_dev_prepare(struct rtc_device *rtc)

{

if (!rtc_devt)

return;

if (rtc->id >= RTC_DEV_MAX) {

pr_debug("%s: too many RTC devices\n", rtc->name);

return;

}

rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);

#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL

INIT_WORK(&rtc->uie_task, rtc_uie_task);

setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);

#endif

cdev_init(&rtc->char_dev, &rtc_dev_fops);

rtc->char_dev.owner = rtc->owner;

}

static const struct file_operations rtc_dev_fops = {

.owner        = THIS_MODULE,

.llseek        = no_llseek,

.read        = rtc_dev_read,

.poll        = rtc_dev_poll,

.unlocked_ioctl    = rtc_dev_ioctl,

.open        = rtc_dev_open,

.release    = rtc_dev_release,

.fasync        = rtc_dev_fasync,

};

RTC操作函数集,接下来一一讲述:

static int rtc_dev_open(struct inode *inode, struct file *file)

{

int err;

struct rtc_device *rtc = container_of(inode->i_cdev,

struct rtc_device, char_dev);//通过设备号找到结构体rtc

const struct rtc_class_ops *ops = rtc->ops;

if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))

return -EBUSY;

file->private_data = rtc;//赋给文件私有指针

err = ops->open ? ops->open(rtc->dev.parent) : 0;//ops中的open没有定义,对应一中的struct rtc_class_ops pcf8563_rtc_ops

if (err == 0) {

spin_lock_irq(&rtc->irq_lock);

rtc->irq_data = 0;

spin_unlock_irq(&rtc->irq_lock);

return 0;

}

/* something has gone wrong */

clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);

return err;

}

static int rtc_dev_release(struct inode *inode, struct file *file)

{

struct rtc_device *rtc = file->private_data;//对应rtc_dev_open中的file->private_data = rtc;

/* We shut down the repeating IRQs that userspace enabled,

* since nothing is listening to them.

*  - Update (UIE) ... currently only managed through ioctls

*  - Periodic (PIE) ... also used through rtc_*() interface calls

*

* Leave the alarm alone; it may be set to trigger a system wakeup

* later, or be used by kernel code, and is a one-shot event anyway.

*/

/* Keep ioctl until all drivers are converted */

rtc_dev_ioctl(file, RTC_UIE_OFF, 0);

rtc_update_irq_enable(rtc, 0);

rtc_irq_set_state(rtc, NULL, 0);

if (rtc->ops->release)

rtc->ops->release(rtc->dev.parent);

clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);

return 0;

}

static int rtc_dev_fasync(int fd, struct file *file, int on)

{

struct rtc_device *rtc = file->private_data;

return fasync_helper(fd, file, on, &rtc->async_queue);

}

static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)

{

struct rtc_device *rtc = file->private_data;

unsigned long data;

poll_wait(file, &rtc->irq_queue, wait);

data = rtc->irq_data;

return (data != 0) ? (POLLIN | POLLRDNORM) : 0;

}

static ssize_t

rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)

{

struct rtc_device *rtc = file->private_data;

DECLARE_WAITQUEUE(wait, current);

unsigned long data;

ssize_t ret;

if (count != sizeof(unsigned int) && count < sizeof(unsigned long))

return -EINVAL;

add_wait_queue(&rtc->irq_queue, &wait);

do {

__set_current_state(TASK_INTERRUPTIBLE);

spin_lock_irq(&rtc->irq_lock);

data = rtc->irq_data;

rtc->irq_data = 0;

spin_unlock_irq(&rtc->irq_lock);

if (data != 0) {

ret = 0;

break;

}

if (file->f_flags & O_NONBLOCK) {

ret = -EAGAIN;

break;

}

if (signal_pending(current)) {

ret = -ERESTARTSYS;

break;

}

schedule();

} while (1);

set_current_state(TASK_RUNNING);

remove_wait_queue(&rtc->irq_queue, &wait);

if (ret == 0) {

/* Check for any data updates */

if (rtc->ops->read_callback)

data = rtc->ops->read_callback(rtc->dev.parent,

data);

if (sizeof(int) != sizeof(long) &&

count == sizeof(unsigned int))

ret = put_user(data, (unsigned int __user *)buf) ?:

sizeof(unsigned int);

else

ret = put_user(data, (unsigned long __user *)buf) ?:

sizeof(unsigned long);

}

return ret;

}

这里的read不是应用程序用来获取时间的,而是有其他的作用,他帮助应用程序周期性的完成一些工作。如果要使用这个功能,应用程序首先保证RTC驱动程序提供这样的功能。这个功能是这样实现的:进程读取/dev/rtc(n),进程睡眠直到RTC中断将他唤醒。我们可以发现,这里的睡眠

是ldd3中提到的手工睡眠。这个函数的手工休眠过程如下:首先调用DECLARE_WAITQUEUE(wait,

current),声明一个等待队列入口,然后调用add_wait_queue将这个入口加入到RTC的irq等待队列里,然后进入循环。在循环里首先

把进程的状态改成TASK_INTERRUPTIBLE,这样进程就不能再被调度运行。但是现在进程还在运行,没有进入睡眠状态。程序然后读取RTC里面的irq_data,如果不是零,那么程序跳出这个循环,进程不会睡眠。因为这个irq_data在rtc的中断处理程序会被赋值,而读过之后就会清零,

所以如果数据不是零的话说明发生过一次中断。如果是零那么没有发生中断,调用schedule,进程会被调度出可运行队列,从而让出处理器,真正进入睡眠。跳出循环代表被唤醒,然后将进程状态改变为可运行,移除等待队列入口。最后将读回的数据传给用户空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值