Chinaunix首页 | 论坛 | 博客
  • 博客访问: 145406
  • 博文数量: 89
  • 博客积分: 71
  • 博客等级: 民兵
  • 技术积分: 490
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-19 19:39
文章分类
文章存档

2013年(3)

2012年(86)

分类:

2012-11-21 12:05:17

原文地址:测试rtc驱动 作者:mclovein

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系统时间里面去。
阅读(388) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~