RTC是一种典型的CDEV。
drivers/rtc/rtc-dev.c实现了RTC的通用驱动层,称为RTCCORE。
RTCCORE实现了FOPS,并向底层导出了一些结构体和API。
分层的结果是,底层RTC驱动无需关心RTC作为CDEV的功能实现,也无需关心通用的RTC控制逻辑。只需要专注于底层操作的实现。
RTCCORE定义了rtc_class_ops结构体,作为RTC的底层操作集。结构体如下。
struct rtc_class_ops{
int (*open)(struct device*);
int (*release)(struct device*);
int (*ioctl)(struct device*, unsigned int ,unsigned long);
int (*read_time)(struct device*, struct rtc_time*);
int (*set_time)(struct device*, struct rtc_time*);
...
};
RTCCORE负责调用这些RTCOPS。
我们注意到,这里面的struct rtc_time,它是一个描述符,
struct rtc_time{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
来看看RTCDEV是什么样的。
struct rtc_device{
struct cdev cdev;
struct device* dev;
char name[SIZE];
const struct rtc_class_ops* ops;
...
};
内核提供了RTC的API。
struct rtc_device* devm_rtc_device_register(struct device*dev,
const char* name,
const struct rtc_class_ops* ops,
struct module* owner);
void devm_rtc_device_unregister(struct device*dev,
struct rtc_device* rtc);
int rtc_valid_tm(struct rtc_time* tm);
显然,我们需要做的,就是实例化一个rtc_class_ops,并填充。然后编写对应的函数。
在probe中注册一个RTCDEV。
来看一个PDEV同时是一个RTCDEV的例子。
static const struct rtc_class_ops rtc_ops = {
.read_time = rtc_read_time,
.set_time = rtc_set_time,
};
....
static struct platform_driver rtc_drv = {
.driver = {
.name = "myrtc",
.owner = THIS_MODULE,
.of_match_table = of_match_prt(rtc_dt_ids),
};
.probe = rtc_probe,
.remove = rtc_remove,
};
module_platform_driver(rtc_drv);
static const struct of_device_id rtc_dt_ids[] = {
{.compatible = "packt, rtc-fake"},
{}
};
MODULE_DEVICE_TABLE(platform, rtc_dt_ids);
static int rtc_probe(struct platform_device* pdev)
{
struct rtc_device* rtc;
rtc = rtc_device_register(pdev->name, &pdev->dev, &rtc_ops, THIS_MODULE);
platform_set_drvdata(pdev, rtc);
...
return 0;
}