class/rtc建立过程

http://hi.baidu.com/renling456000/item/93f9e7117d84dc483b176e5c

RTC实时时钟驱动程序分析

 

在文件interface.c中对函数集s3c_rtcops中的各函数进行包装,以供上层函数调用。

rtc-dev.c :该文件主要实现了RTC字符设备的操作函数集:

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,

                           };

文件interface.c对函数集s3c_rtcops中的各函数进行包装,RTC字符设备函数集rtc_dev_fops 中的操作函数就是通过调用这些被包装后的函数实现对硬件的操作的。

RTC设备建立流程

//为RTC设备分配设备号,该函数在文件class.c中调用在文件rtc-dev.c

//中实现。

void __init rtc_dev_init(void)

{

int err;

err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");

if (err < 0)

printk(KERN_ERR "%s: failed to allocate char dev region\n",

__FILE__);

}

/****************************************************************************/

static int __init rtc_init(void)

{

//创建一个名为"rtc"的类。

rtc_class = class_create(THIS_MODULE, "rtc");

if (IS_ERR(rtc_class)) {

printk(KERN_ERR "%s: couldn't create class\n", __FILE__);

return PTR_ERR(rtc_class);

}

rtc_class->suspend = rtc_suspend;

rtc_class->resume = rtc_resume;

rtc_dev_init();//*****//注册一个设备号

rtc_sysfs_init(rtc_class); //*****//添加类属性

return 0;

}

//"rtc"作为子系统而添加到内核。

subsys_initcall(rtc_init);

/****************************************************************************/

//驱动s3c2410_rtc_driver的设备探测函数。该函数在文件rtc-s3c.c中实现。

static int __devinit s3c_rtc_probe(struct platform_device *pdev)

{

struct rtc_device *rtc;

struct resource *res;

int ret;

pr_debug("%s: probe=%p\n", __func__, pdev);

/* find the IRQs */

//获取节拍中断的中断号

s3c_rtc_tickno = platform_get_irq(pdev, 1);

if (s3c_rtc_tickno < 0) {

dev_err(&pdev->dev, "no irq for rtc tick\n");

return -ENOENT;

}

//获取定时报警中断的中断号

s3c_rtc_alarmno = platform_get_irq(pdev, 0);

if (s3c_rtc_alarmno < 0) {

dev_err(&pdev->dev, "no irq for alarm\n");

return -ENOENT;

}

pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",

 s3c_rtc_tickno, s3c_rtc_alarmno);

/* get the memory region */

//获取RTC寄存器物理存储地址

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

if (res == NULL) {

dev_err(&pdev->dev, "failed to get memory region resource\n");

return -ENOENT;

}

//申请一片存储空间

s3c_rtc_mem = request_mem_region(res->start,

 res->end-res->start+1,

 pdev->name);

if (s3c_rtc_mem == NULL) {

dev_err(&pdev->dev, "failed to reserve memory region\n");

ret = -ENOENT;

goto err_nores;

}

//映射一片IO内存。

s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);

if (s3c_rtc_base == NULL) {

dev_err(&pdev->dev, "failed ioremap()\n");

ret = -EINVAL;

goto err_nomap;

}

/* check to see if everything is setup correctly */

//使能RTC

s3c_rtc_enable(pdev, 1);

  pr_debug("s3c2410_rtc: RTCCON=%02x\n",

 readb(s3c_rtc_base + S3C2410_RTCCON));

//设置节拍频率

s3c_rtc_setfreq(&pdev->dev, 1);

//电源管理。。。。。

device_init_wakeup(&pdev->dev, 1);

/* register RTC and exit */

/*

函数rtc_device_register主要完成以下工作。

(1)为RTC设备结构体rtc_device分配存储空间并初始化该结构各字段。

(2)为rtc->dev创建设备节点。将该RTC设备结构体rtc_devic对应的字符设备rtc->char_dev 

添加到内核。(一个rtc_devic结构对应一个字符设备,rtc->dev与rtc->char_dev同用一个设备号)。

(3)在proc文件系统中创建目录。

*/

rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,

  THIS_MODULE);

if (IS_ERR(rtc)) {

dev_err(&pdev->dev, "cannot attach rtc\n");

ret = PTR_ERR(rtc);

goto err_nortc;

}

rtc->max_user_freq = 128;

//将RTC设备结构体rtc_device置为平台设备pdev的drvdata。

platform_set_drvdata(pdev, rtc);

return 0;

 err_nortc:

s3c_rtc_enable(pdev, 0);

iounmap(s3c_rtc_base);

 err_nomap:

release_resource(s3c_rtc_mem);

 err_nores:

return ret;

}

/****************************************************************************/

//函数rtc_device_register在文件class.c中实现

struct rtc_device *rtc_device_register(const char *name, struct device *dev,

const struct rtc_class_ops *ops,

struct module *owner)

{

struct rtc_device *rtc;

int id, err;

//为idr(rtc_idr)分配内存

if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {

err = -ENOMEM;

goto exit;

}

mutex_lock(&idr_lock);

//分配ID号存于id中,该ID号最终将作为该RTC设备的次设备号。

    err = idr_get_new(&rtc_idr, NULL, &id);

mutex_unlock(&idr_lock);

if (err < 0)

goto exit;

id = id & MAX_ID_MASK;

//为RTC结构体分配内存

rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);

if (rtc == NULL) {

err = -ENOMEM;

goto exit_idr;

}

rtc->id = id;

rtc->ops = ops;//指向原始设备操作函数集

rtc->owner = owner;

rtc->max_user_freq = 64;

rtc->dev.parent = dev;

rtc->dev.class = rtc_class;

rtc->dev.release = rtc_device_release;

mutex_init(&rtc->ops_lock);

spin_lock_init(&rtc->irq_lock);

spin_lock_init(&rtc->irq_task_lock);

init_waitqueue_head(&rtc->irq_queue);

strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);

dev_set_name(&rtc->dev, "rtc%d", id);

//为RTC设备添加设备号rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);和

//初始化该RTC设备对应的字符设备cdev_init(&rtc->char_dev, &rtc_dev_fops);

rtc_dev_prepare(rtc);

//注册该RTC设备rtc->dev。

err = device_register(&rtc->dev);

if (err)

goto exit_kfree;

//将RTC设备对应的字符设备添加到内核cdev_add(&rtc->char_dev, rtc->dev.devt, 1)

rtc_dev_add_device(rtc);

//为rtc->dev添加设备属性。

rtc_sysfs_add_device(rtc);

//在Pproc文件系统中创建目录"driver/rtc"。

rtc_proc_add_device(rtc);

dev_info(dev, "rtc core: registered %s as %s\n",

rtc->name, dev_name(&rtc->dev));

return rtc;

exit_kfree:

kfree(rtc);

exit_idr:

mutex_lock(&idr_lock);

idr_remove(&rtc_idr, id);

mutex_unlock(&idr_lock);

exit:

dev_err(dev, "rtc core: unable to register %s, err = %d\n",

name, err);

return ERR_PTR(err);

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值