LDM上层建筑----补充1

在really_probe函数中有如下一段:

if (dev->bus->probe) {
    ret = dev->bus->probe(dev);
    if (ret)
        goto probe_failed;
} else if (drv->probe) {
    ret = drv->probe(dev);
    if (ret)
        goto probe_failed;
}这里我们会调用drv->probe,对于rtc这个例子即是s3c_rtc_probe这个函数。

这个函数很重要,正是这个函数进行rtc中中断、寄存器的地址映射以及s3c_rtcops打交道,这个

static const struct rtc_class_ops s3c_rtcops = {
    .open        = s3c_rtc_open,
    .release    = s3c_rtc_release,
    .ioctl        = s3c_rtc_ioctl,
    .read_time    = s3c_rtc_gettime,
    .set_time    = s3c_rtc_settime,
    .read_alarm    = s3c_rtc_getalarm,
    .set_alarm    = s3c_rtc_setalarm,
    .proc            = s3c_rtc_proc,
};

是字符驱动的关键    从这个结构中看出rtc的基本操作都有了

 

 

static int s3c_rtc_probe(struct platform_device *pdev)
{
    struct rtc_device *rtc;
    struct resource *res;
    int ret;

    pr_debug("%s: probe=%p/n", __FUNCTION__, 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 */  第二部分:寄存器的映射

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

    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 */      第三部分:检查

    s3c_rtc_enable(pdev, 1);

     pr_debug("s3c2410_rtc: RTCCON=%02x/n",
         readb(s3c_rtc_base + S3C2410_RTCCON));

    s3c_rtc_setfreq(s3c_rtc_freq);

    /* register RTC and exit */                                                   第四部分:注册rtc

    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;

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

第一部分:中断资源的获取:

因为已经定义了:

static struct resource s3c_rtc_resource[] = {
    [0] = {
        .start = S3C24XX_PA_RTC,
        .end   = S3C24XX_PA_RTC + 0xff,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = IRQ_RTC,
        .end   = IRQ_RTC,
        .flags = IORESOURCE_IRQ,
    },
    [2] = {
        .start = IRQ_TICK,
        .end   = IRQ_TICK,
        .flags = IORESOURCE_IRQ
    }
};

所以根据flags可以获取s3c_rtc_tickno 和s3c_rtc_alarmno

第二部分:寄存器的映射:

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

最关键是利用ioremap函数进行地址的映射

第三部分:检查

将rtc启用斌而过设置RTC的tick

第四部分:主要看rtc_device_register函数

/**
* rtc_device_register - register w/ RTC class
* @dev: the device to register
*
* rtc_device_unregister() must be called when the class device is no
* longer needed.
*
* Returns the pointer to the new struct class device.
*/
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;

    if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
        err = -ENOMEM;
        goto exit;
    }

    mutex_lock(&idr_lock);
    err = idr_get_new(&rtc_idr, NULL, &id);
    mutex_unlock(&idr_lock);

    if (err < 0)
        goto exit;

    id = id & MAX_ID_MASK;

    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;            //对rtc这个rtc_device 结构体进行一些定义

    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);    //rtc 的name为’s3c’
    snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id);   //rtc->dev.bus_id为rtc0

    rtc_dev_prepare(rtc);                 //设备号的获取  字符设备的初始化   cdev_init(&rtc->char_dev, &rtc_dev_fops);

    err = device_register(&rtc->dev);    

//pdev->dev是 &s3c_device_rtc,所以rtc->dev.parent = s3c_device_rtc,class 是 rtc_class,
dev->bus_id是 “rtc+id",这里假设是”rtc0"。这样在get_device_parent()中新创建的kobj(k)对应
的目录是/sys/devices/platform/s3c2410-rtc/rtc,而 rtc->dev.kobj生成的目录是/sys/devices/platform/s3c2410-rtc/rtc/rtc0。


    if (err)
        goto exit_kfree;

    rtc_dev_add_device(rtc);

//前面有字符设备的初始化,在这个函数中进行字符设备的add动作:


    rtc_sysfs_add_device(rtc);

///sys/devices/platform/s3c2410-rtc/rtc/rtc0下生成wakealarm属性文件
    rtc_proc_add_device(rtc);

//在proc目录下建立driver/rtc等接口

    dev_info(dev, "rtc core: registered %s as %s/n",
            rtc->name, rtc->dev.bus_id);

    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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值