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