rtc是平台设备,属于混杂设备,主设备号10,次设备号135。
[root@FriendlyARM /]# ls -l /dev/misc/
crw-r----- 1 root root 10, 134 Jan 1 00:00 apm_bios
crw-r----- 1 root root 10, 135 Jan 1 00:00 rtc
rtc驱动涉及到s3c2410-rtc.c和arch/arm/common/rtctime.c文件,rtctime.c是对arm平台下rtc驱动的更高一层的抽象
s3c2410-rtc.c 中
static struct rtc_ops s3c2410_rtcops = {
.owner = THIS_MODULE,
.open = s3c2410_rtc_open,
.release = s3c2410_rtc_release,
.ioctl = s3c2410_rtc_ioctl,
.read_time = s3c2410_rtc_gettime,
.set_time = s3c2410_rtc_settime,
.read_alarm = s3c2410_rtc_getalarm,
.set_alarm = s3c2410_rtc_setalarm,
.proc = s3c2410_rtc_proc,
};
rtc驱动要实现的就是rtc_ops结构体中的函数。这个结构体在/include/asm-arm/rtc.h中
struct rtc_ops {
struct module *owner;
int (*open)(void);
void (*release)(void);
int (*ioctl)(unsigned int, unsigned long);
int (*read_time)(struct rtc_time *);
int (*set_time)(struct rtc_time *);
int (*read_alarm)(struct rtc_wkalrm *);
int (*set_alarm)(struct rtc_wkalrm *);
int (*proc)(char *buf);
};
对rtc的操作就限制为这些操作。
在s3c2410-rtc.c 中
register_rtc(&s3c2410_rtcops);
这条语句用来注册rtc底层驱动到rtctime.c抽象出的更高一层驱动。
int register_rtc(struct rtc_ops *ops)
{
int ret = -EBUSY;
down(&rtc_sem);
if (rtc_ops == NULL) {
rtc_ops = ops;
ret = misc_register(&rtc_miscdev);
if (ret == 0)
create_proc_read_entry("driver/rtc", 0, NULL,
rtc_read_proc, ops);
}
up(&rtc_sem);
return ret;
}
EXPORT_SYMBOL(register_rtc);
这样就不需要在s3c2410-rtc.c中(rtc最底层的驱动)注册misc设备了,也不能。
register_rtc()完成了混杂设备的注册,并且还创建了proc/driver/rtc这个内存文件。
可以cat /proc/driver/rtc查看他的内容。
这个函数的最主要操作之一是
rtc_ops = ops;
其中rtc_ops是本文件中的全局量
static struct rtc_ops *rtc_ops;
在同文件的 rtc_open 函数中,
file->private_data = rtc_ops;
这样就可以通过file->private_data来使用最底层注册的操作rtc的函数了。
同文件中,有:
static struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_read,
.poll = rtc_poll,
.ioctl = rtc_ioctl,
.open = rtc_open,
.release = rtc_release,
.fasync = rtc_fasync,
};
static struct miscdevice rtc_miscdev = {
.minor = RTC_MINOR,
.name = "rtc",
.fops = &rtc_fops,
};
这里的rtc_fops才是我们在应用程序中可以使用的系统调用。
其中
read的主要操作句子是:
data = rtc_irq_data;
ret = put_user(data, (unsigned long __user *)buf);
他只是取得全局量rtc_irq_data,返回给用户。
ioctl是能对rtc操作的功能集合
包括
RTC_ALM_READ
RTC_ALM_SET
RTC_RD_TIME
RTC_SET_TIME
RTC_EPOCH_SET
RTC_EPOCH_READ
RTC_WKALM_SET
RTC_WKALM_RD
这些命令,不能处理的,交给s3c2410_rtc_ioctl处理,代码如下。
default:
if (ops->ioctl)
ret = ops->ioctl(cmd, arg);
break;
可以看出,对rtc的操作主要就是ioctl了。
#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */
#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */
#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */
#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */
#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */
#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */
#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */
#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */
#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */
#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */
#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */
#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */
#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */
#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */
#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */
他们定义在include/linux/rtc.h中,是rtc的操作集合
测试下:
[root@FriendlyARM /]# cat /proc/driver/rtc
rtc_time : 09:33:33
rtc_date : 2154-18-03
rtc_epoch : 1900
alrm_time : **:**:**
alrm_date : ****-**-**
alrm_wakeup : no
alrm_pending : no
alarm_IRQ : no
periodic_IRQ : no
periodic_freq : 1
时间不正确,设置正确。代码如下:
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
struct linux_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;
};
#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */
#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */
int main(int argc, char **argv)
{
struct linux_rtc_time tm;
int fd,val,ret;
fd = open("/dev/misc/rtc", O_RDWR);
if (fd < 0) {
perror("open device rtc");
exit(1);
}
tm.tm_year = 2009-1900;
tm.tm_mon = 10;
tm.tm_mday = 3;
tm.tm_hour = 11;
tm.tm_min = 15;
tm.tm_sec = 0; //起初我没有写这句,忘记了系统只为全局量初始化为0,这个量的不合法导致了写rtc的失败,害的我找了一大圈。
val = ioctl(fd, RTC_SET_TIME, &tm); //设置rtc时间,成功返回0
printf("set time %s\n",val?"error":"ok");
val = ioctl(fd, RTC_RD_TIME, &tm);
printf("get time %s\n",val?"error":"ok");
printf( "linux_rtc_time\t: %02d:%02d:%02d\n"
"rtc_date\t: %04d-%02d-%02d\n",
tm.tm_hour, tm.tm_min, tm.tm_sec,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
return 0;
}
”起初我没有写这句“导致的问题是ioctl返回数值不是你想象的-22。
为什么返回值不是任何你想的那样呢,而是-1,
#define EPERM 1 /* Operation not permitted */
操作不被允许,我猜想大概是ioctl系统调用处理返回数值时,当出错为 -22时,自动调整为-1??? # date 110313172009.05
Tue Nov 3 13:17:05 MST 2009
# hwclock -w
# hwclock
Tue Nov 3 13:18:33 2009 0.000000 seconds
# hwclock
Tue Nov 3 13:18:41 2009 0.000000 seconds当然,知道了具体用法后,你可以再次去试试其他的,比如将硬件hwclock里面的时间设置了,
用hwclock -s把rtc时间写到Linux系统时间里面去。
阅读(5296) | 评论(1) | 转发(3) |