Chinaunix首页 | 论坛 | 博客
  • 博客访问: 181829
  • 博文数量: 44
  • 博客积分: 627
  • 博客等级: 中士
  • 技术积分: 345
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-20 21:55
文章分类

全部博文(44)

文章存档

2012年(44)

分类: LINUX

2012-08-08 17:17:04

RTC实时时钟驱动程序分析  

2010-07-22 20:05:57|  分类: arm linux设备驱 |  标签: |字号 

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);

}

阅读(1491) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~