linux RTC设备驱动

一. RTC设备结构体

struct rtc_device
{
	struct device dev;		//设备文件
	struct module *owner;	//模块所有者
	int id;			//RTC次设备
	char name[RTC_DEVICE_NAME_SIZE];	//RTC设备名
	const struct rtc_class_ops *ops;	//RTC类操作函数集
	struct mutex ops_lock;
	struct cdev char_dev;	//RTC字符设备
	unsigned long flags;	//忙标志位
	unsigned long irq_data;
	spinlock_t irq_lock;
	wait_queue_head_t irq_queue;	//等待队列头
	struct fasync_struct *async_queue;
	struct rtc_task *irq_task;
	spinlock_t irq_task_lock;
	int irq_freq;	//中断频率
	int max_user_freq;		//最大频率
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
	struct work_struct uie_task;
	struct timer_list uie_timer;
	/* Those fields are protected by rtc->irq_lock */
	unsigned int oldsecs;
	unsigned int uie_irq_active:1;
	unsigned int stop_uie_polling:1;
	unsigned int uie_task_active:1;
	unsigned int uie_timer_active:1;
#endif
};

二. RTC时间结构体

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


三. 闹钟相关结构体

struct rtc_wkalrm {
	unsigned char enabled;/* 0 = alarm disabled, 1 = alarm enabled */	//是否支持闹钟功能
	unsigned char pending;/* 0 = alarm not pending, 1 = alarm pending */	//是否等待
	struct rtc_time time;·/* time the alarm is set to */	//闹钟时间
};

 

四. RTC 类操作函数集

struct rtc_class_ops {
	int (*open)(struct device *);	//open方法
	void (*release)(struct device *);	//release方法
	int (*ioctl)(struct device *, unsigned int, unsigned long);	//控制
	int (*read_time)(struct device *, struct rtc_time *);	//读取时间
	int (*set_time)(struct device *, struct rtc_time *);	//设置时间
	int (*read_alarm)(struct device *, struct rtc_wkalrm *);	//读取闹钟
	int (*set_alarm)(struct device *, struct rtc_wkalrm *);	//设置闹钟
	int (*proc)(struct device *, struct seq_file *);
	int (*set_mmss)(struct device *, unsigned long secs);	//秒装换为rtc_time
	int (*irq_set_state)(struct device *, int enabled);	//设置中断状态
	int (*irq_set_freq)(struct device *, int freq);	//设置中断频率
	int (*read_callback)(struct device *, int data);
	int (*alarm_irq_enable)(struct device *, unsigned int enabled);	//闹钟使能禁用
	int (*update_irq_enable)(struct device *, unsigned int enabled);//更新中断使能开关
};


五. RTC系统初始化
     5.1 rtc系统的初始化

static int __init rtc_init(void)
{
	rtc_class = class_create(THIS_MODULE, "rtc");		//创建rtc_class类"/sys/class/rtc"
	if (IS_ERR(rtc_class)) {
		printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
		return PTR_ERR(rtc_class);
	}
	rtc_class->suspend = rtc_suspend;	//RTC挂起
	rtc_class->resume = rtc_resume;	//RTC唤醒
	rtc_dev_init();	//RTC字符设备初始化
	rtc_sysfs_init(rtc_class);
	return 0;
}

     5.2 作为字符设备的初始化

void __init rtc_dev_init(void)
{
	int err;

	err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");	//RTC_DEV_MAX=16 系统最大支持16个rtc
	if (err < 0)
		printk(KERN_ERR "%s: failed to allocate char dev region\n",__FILE__);
}

这里rtc_devt记录了分配的第一个RTC设备的设备号,同样它也可以作为rtc类的主设备号

     5.3 RTC在sysfs下的初始化

     5.3.1

void __init rtc_sysfs_init(struct class *rtc_class)
{
	rtc_class->dev_attrs = rtc_attrs;
}

     5.3.2

static struct device_attribute rtc_attrs[] = {
	__ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),	//“/sys/class/rtc/rtcX/name“
	__ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),	//“/sys/class/rtc/rtcX/date“
	__ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),	//“/sys/class/rtc/rtcX/time“
	__ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),	//“/sys/class/rtc/rtcX/since_epoch“
	__ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,rtc_sysfs_set_max_user_freq),	//.../max_user_freq
	__ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),//"/sys/class/rtc/rtcX/hctosys"	
	{ },
};

     5.3.3 /sys/class/rtc文件的运用

定义的这些属性文件会在调用rtc_device_register->device_register(&rtc->dev)注册rtc设备后在/sys/class/rtc/下对应的rtcX文件夹出现,通过cat命令会调用第三个参数值定义的函数,可以查看其相关信息

例如:

cat /sys/class/rtc/rtc0/name 查看设备名
rtc_cmos
cat /sys/class/rtc/rtc0/time 查看当前时间
05:35:11
cat /sys/class/rtc/rtc0/date 查看日期
2012-12-19
cat /sys/class/rtc/rtc0/since_epoch 
1355895483
cat /sys/class/rtc/rtc0/max_user_freq 查看最大频率
64
cat /sys/class/rtc/rtc0/hctosys 
1

 

 六. RTC设备的注册与注销

     6.1 RTC设备的注册rtc_device_register

 参数:RTC->name名字 ; RTC->parent父设备 ; RTC类的操作函数集 ; 模块所有者THIS_MODULES

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);	//利用idr机制获得新的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类操作函数集
	rtc->owner = owner;			//模块所有者
	rtc->max_user_freq = 64;			//最大频率
	rtc->dev.parent = dev;			//父设备
	rtc->dev.class = rtc_class;			//设备所属的类
	rtc->dev.release = rtc_device_release;	//设备的release方法

	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设备名
	dev_set_name(&rtc->dev, "rtc%d", id);	//RTC字符设备名

	rtc_dev_prepare(rtc);	//初始化字符设备

	err = device_register(&rtc->dev);	//注册设备
	if (err) {
		put_device(&rtc->dev);
		goto exit_kfree;
	}

	rtc_dev_add_device(rtc);	//添加RTC字符设备
	rtc_sysfs_add_device(rtc);	//添加sysfs下的rtc文件
	rtc_proc_add_device(rtc);	//添加procfs下的rtc文件

	dev_info(dev, "rtc core: registered %s as %s\n",rtc->name, dev_name(&rtc->dev));

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

     6.2  RTC字符设备相关的操作

     6.2.1 rtc_dev_prepare 字符设备的初始化

void rtc_dev_prepare(struct rtc_device *rtc)
{
	if (!rtc_devt)
		return;

	if (rtc->id >= RTC_DEV_MAX) {	//判断RTC个数是否大于16个
		pr_debug("%s: too many RTC devices\n", rtc->name);
		return;
	}

	rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);	//根据主次设备号计算出某个RTC设备号

#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
	INIT_WORK(&rtc->uie_task, rtc_uie_task);
	setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
#endif

	cdev_init(&rtc->char_dev, &rtc_dev_fops);	//初始化RTC字符设备,并捆绑rtc_dev_fops
	rtc->char_dev.owner = rtc->owner;	//统一RTC设备及其字符设备的模块所有者
}

     6.2.2 rtc_dev_fops 具体的函数集后面分析

static const struct file_operations rtc_dev_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.read		= rtc_dev_read,	//读
	.poll		= rtc_dev_poll,	//轮询
	.unlocked_ioctl	= rtc_dev_ioctl,	//控制
	.open		= rtc_dev_open,	//打开
	.release	= rtc_dev_release,		//释放
	.fasync		= rtc_dev_fasync,	//同步
};


     6.2.3 rtc_dev_add_device 字符设备添加

void rtc_dev_add_device(struct rtc_device *rtc)
{
	if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))	//添加字符设备
		printk(KERN_WARNING "%s: failed to add char device %d:%d\n",rtc->name, MAJOR(rtc_devt), rtc->id);
	else
		pr_debug("%s: dev (%d:%d)\n", rtc->name,MAJOR(rtc_devt), rtc->id);
}


    6.3 sysfs文件系统相关

void rtc_sysfs_add_device(struct rtc_device *rtc)
{
	int err;

	/* not all RTCs support both alarms and wakeup */
	if (!rtc_does_wakealarm(rtc))	//若RTC设备支持闹钟唤醒功能
		return;

	err = device_create_file(&rtc->dev, &dev_attr_wakealarm);	//则在"/sys/class/rtc/rtcXXX/"添加闹钟属性文件
	if (err)
		dev_err(rtc->dev.parent,"failed to create alarm attribute, %d\n", err);
}


     6.4 procfs文件系统相关

     6.4.1 创建文件

void rtc_proc_add_device(struct rtc_device *rtc)
{
	if (rtc->id == 0)
		proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);	//创建"/proc/driver/rtc"文件
}

    6.4.2 rtc_proc_fops

static const struct file_operations rtc_proc_fops = {
	.open		= rtc_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= rtc_proc_release,
};

     6.4.3 /proc/driver/rtc文件的运用

cat 文件时可以显示时间 日期闹钟等信息

cat /proc/driver/rtc 
rtc_time	: 05:43:48
rtc_date	: 2012-12-19
alrm_time	: 00:00:00
alrm_date	: ****-**-**
alarm_IRQ	: no
alrm_pending	: no
24hr		: yes
periodic_IRQ	: no
update_IRQ	: no
HPET_emulated	: no
DST_enable	: no
periodic_freq	: 1024
batt_status	: okay

其实现的方式是cat的时候,会打开/proc/driver/rtc调用其open方法执行rtc_proc_open函数,然后调用其read方法执行seq_read函数

static int rtc_proc_open(struct inode *inode, struct file *file)
{
	struct rtc_device *rtc = PDE(inode)->data;

	if (!try_module_get(THIS_MODULE))
		return -ENODEV;

	return single_open(file, rtc_proc_show, rtc);	//接着调用rtc_proc_show函数
}

rtc_proc_show函数

static int rtc_proc_show(struct seq_file *seq, void *offset)	
{
	int err;
	struct rtc_device *rtc = seq->private;
	const struct rtc_class_ops *ops = rtc->ops;
	struct rtc_wkalrm alrm;
	struct rtc_time tm;

	err = rtc_read_time(rtc, &tm);	//读取时间,打印时间相关信息
	if (err == 0) {
		seq_printf(seq,
			"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);
	}

	err = rtc_read_alarm(rtc, &alrm);	//读取闹钟,打印闹钟相关信息
	if (err == 0) {
		seq_printf(seq, "alrm_time\t: ");
		if ((unsigned int)alrm.time.tm_hour <= 24)
			seq_printf(seq, "%02d:", alrm.time.tm_hour);
		else
			seq_printf(seq, "**:");
		if ((unsigned int)alrm.time.tm_min <= 59)
			seq_printf(seq, "%02d:", alrm.time.tm_min);
		else
			seq_printf(seq, "**:");
		if ((unsigned int)alrm.time.tm_sec <= 59)
			seq_printf(seq, "%02d\n", alrm.time.tm_sec);
		else
			seq_printf(seq, "**\n");

		seq_printf(seq, "alrm_date\t: ");
		if ((unsigned int)alrm.time.tm_year <= 200)
			seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
		else
			seq_printf(seq, "****-");
		if ((unsigned int)alrm.time.tm_mon <= 11)
			seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
		else
			seq_printf(seq, "**-");
		if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31)
			seq_printf(seq, "%02d\n", alrm.time.tm_mday);
		else
			seq_printf(seq, "**\n");
		seq_printf(seq, "alarm_IRQ\t: %s\n",alrm.enabled ? "yes" : "no");
		seq_printf(seq, "alrm_pending\t: %s\n",alrm.pending ? "yes" : "no");
	}

	seq_printf(seq, "24hr\t\t: yes\n");

	if (ops->proc)
		ops->proc(rtc->dev.parent, seq);	//如果自定义了proc方法会执行该proc方法

	return 0;
}

这里的打印是打印到文件的私有数据段,而seq_read函数则将其信息从文件读取出来并复制到用户空间的buf里


     6.5 RTC设备的注销 rtc_device_unregister

void rtc_device_unregister(struct rtc_device *rtc)
{
	if (get_device(&rtc->dev) != NULL) {
		mutex_lock(&rtc->ops_lock);
		/* remove innards of this RTC, then disable it, before
		 * letting any rtc_class_open() users access it again
		 */
		rtc_sysfs_del_device(rtc);	//sysfs删除相关文件
		rtc_dev_del_device(rtc);	//移除字符设备
		rtc_proc_del_device(rtc);	//procfs删除相关文件
		device_unregister(&rtc->dev);	//注销设备
		rtc->ops = NULL;
		mutex_unlock(&rtc->ops_lock);
		put_device(&rtc->dev);
	}
}

七. rtc_dev_fops

     7.1 /dev/rtcX的设备文件是由RTC的字符设备去构建的,自然去打开,读取,操作该设备文件时,调用的是rtc_dev_fops的函数集

     7.2 open方法

static int rtc_dev_open(struct inode *inode, struct file *file)
{
	int err;
	struct rtc_device *rtc = container_of(inode->i_cdev,struct rtc_device, char_dev);	//用container_of宏获取rtc_device
	const struct rtc_class_ops *ops = rtc->ops;	//获取器rtc_class_ops函数集指针

	if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))	//测试并设置忙标志
		return -EBUSY;

	file->private_data = rtc;

	err = ops->open ? ops->open(rtc->dev.parent) : 0;	//rtc类函数集存在open方法,则调用其方法
	if (err == 0) {
		spin_lock_irq(&rtc->irq_lock);
		rtc->irq_data = 0;
		spin_unlock_irq(&rtc->irq_lock);

		return 0;
	}

	/* something has gone wrong */
	clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);	//清除忙标志
	return err;
}

     7.3 read方法

static ssize_t rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	struct rtc_device *rtc = file->private_data;

	DECLARE_WAITQUEUE(wait, current);		//声明一个等待队列
	unsigned long data;
	ssize_t ret;

	if (count != sizeof(unsigned int) && count < sizeof(unsigned long))
		return -EINVAL;

	add_wait_queue(&rtc->irq_queue, &wait);	//添加该等待队列到RTC等待队列中
	do {
		__set_current_state(TASK_INTERRUPTIBLE);	//设置当前进程为可中断

		spin_lock_irq(&rtc->irq_lock);
		data = rtc->irq_data;		//获取中断数据
		rtc->irq_data = 0;
		spin_unlock_irq(&rtc->irq_lock);

		if (data != 0) {			//若有中断数据跳出循环
			ret = 0;
			break;
		}
		if (file->f_flags & O_NONBLOCK) {
			ret = -EAGAIN;
			break;
		}
		if (signal_pending(current)) {	//当前进程等待
			ret = -ERESTARTSYS;
			break;
		}
		schedule();			//调度
	} while (1);
	set_current_state(TASK_RUNNING);		//设置当前进程为运行态
	remove_wait_queue(&rtc->irq_queue, &wait);	//移除等待队列

	if (ret == 0) {
		/* Check for any data updates */
		if (rtc->ops->read_callback)	//若RTC类存在read_callback方法
			data = rtc->ops->read_callback(rtc->dev.parent,data);	//则调用

		if (sizeof(int) != sizeof(long) && count == sizeof(unsigned int))
			ret = put_user(data, (unsigned int __user *)buf) ?:sizeof(unsigned int);
		else
			ret = put_user(data, (unsigned long __user *)buf) ?:sizeof(unsigned long);
	}
	return ret;
}

    7.4 unlocked_ioctl方法

static long rtc_dev_ioctl(struct file *file,unsigned int cmd, unsigned long arg)
{
	int err = 0;
	struct rtc_device *rtc = file->private_data;
	const struct rtc_class_ops *ops = rtc->ops;
	struct rtc_time tm;
	struct rtc_wkalrm alarm;
	void __user *uarg = (void __user *) arg;

	err = mutex_lock_interruptible(&rtc->ops_lock);
	if (err)
		return err;

	switch (cmd) {
	case RTC_EPOCH_SET:
	case RTC_SET_TIME:
		if (!capable(CAP_SYS_TIME))
			err = -EACCES;
		break;

	case RTC_IRQP_SET:
		if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
			err = -EACCES;
		break;

	case RTC_PIE_ON:
		if (rtc->irq_freq > rtc->max_user_freq &&
				!capable(CAP_SYS_RESOURCE))
			err = -EACCES;
		break;
	}

	if (err)
		goto done;

	/* try the driver's ioctl interface */
	if (ops->ioctl) {
		err = ops->ioctl(rtc->dev.parent, cmd, arg);
		if (err != -ENOIOCTLCMD) {
			mutex_unlock(&rtc->ops_lock);
			return err;
		}
	}

	switch (cmd) {
	case RTC_ALM_READ:		//闹钟读
		mutex_unlock(&rtc->ops_lock);

		err = rtc_read_alarm(rtc, &alarm);
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
			err = -EFAULT;
		return err;

	case RTC_ALM_SET:		//闹钟设置
		mutex_unlock(&rtc->ops_lock);

		if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
			return -EFAULT;

		alarm.enabled = 0;
		alarm.pending = 0;
		alarm.time.tm_wday = -1;
		alarm.time.tm_yday = -1;
		alarm.time.tm_isdst = -1;

		{
			unsigned long now, then;

			err = rtc_read_time(rtc, &tm);
			if (err < 0)
				return err;
			rtc_tm_to_time(&tm, &now);

			alarm.time.tm_mday = tm.tm_mday;
			alarm.time.tm_mon = tm.tm_mon;
			alarm.time.tm_year = tm.tm_year;
			err  = rtc_valid_tm(&alarm.time);
			if (err < 0)
				return err;
			rtc_tm_to_time(&alarm.time, &then);

			/* alarm may need to wrap into tomorrow */
			if (then < now) {
				rtc_time_to_tm(now + 24 * 60 * 60, &tm);
				alarm.time.tm_mday = tm.tm_mday;
				alarm.time.tm_mon = tm.tm_mon;
				alarm.time.tm_year = tm.tm_year;
			}
		}

		return rtc_set_alarm(rtc, &alarm);

	case RTC_RD_TIME:		//读时间
		mutex_unlock(&rtc->ops_lock);

		err = rtc_read_time(rtc, &tm);
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &tm, sizeof(tm)))
			err = -EFAULT;
		return err;

	case RTC_SET_TIME:		//设置时间
		mutex_unlock(&rtc->ops_lock);

		if (copy_from_user(&tm, uarg, sizeof(tm)))
			return -EFAULT;

		return rtc_set_time(rtc, &tm);

	case RTC_PIE_ON:		//开启全局中断
		err = rtc_irq_set_state(rtc, NULL, 1);
		break;

	case RTC_PIE_OFF:		//关闭全局中断
		err = rtc_irq_set_state(rtc, NULL, 0);
		break;

	case RTC_AIE_ON:		//开启闹钟中断
		mutex_unlock(&rtc->ops_lock);
		return rtc_alarm_irq_enable(rtc, 1);

	case RTC_AIE_OFF:		//关闭闹钟中断
		mutex_unlock(&rtc->ops_lock);
		return rtc_alarm_irq_enable(rtc, 0);

	case RTC_UIE_ON:		//开启更新中断
		mutex_unlock(&rtc->ops_lock);
		return rtc_update_irq_enable(rtc, 1);

	case RTC_UIE_OFF:		//关闭更新中断
		mutex_unlock(&rtc->ops_lock);
		return rtc_update_irq_enable(rtc, 0);

	case RTC_IRQP_SET:		//设置中断频率
		err = rtc_irq_set_freq(rtc, NULL, arg);
		break;

	case RTC_IRQP_READ:	//获取中断频率
		err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
		break;

	case RTC_WKALM_SET:	//设置闹钟唤醒
		mutex_unlock(&rtc->ops_lock);
		if (copy_from_user(&alarm, uarg, sizeof(alarm)))
			return -EFAULT;

		return rtc_set_alarm(rtc, &alarm);

	case RTC_WKALM_RD:		//获取闹钟唤醒
		mutex_unlock(&rtc->ops_lock);
		err = rtc_read_alarm(rtc, &alarm);
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &alarm, sizeof(alarm)))
			err = -EFAULT;
		return err;

	default:
		err = -ENOTTY;
		break;
	}

done:
	mutex_unlock(&rtc->ops_lock);
	return err;
}

     7.5 poll方法

static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
{
	struct rtc_device *rtc = file->private_data;
	unsigned long data;

	poll_wait(file, &rtc->irq_queue, wait);

	data = rtc->irq_data;	//获取中断数据

	return (data != 0) ? (POLLIN | POLLRDNORM) : 0;
}


     7.6 release方法

static int rtc_dev_release(struct inode *inode, struct file *file)
{
	struct rtc_device *rtc = file->private_data;
	rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
	rtc_update_irq_enable(rtc, 0);	//关闭更新中断
	rtc_irq_set_state(rtc, NULL, 0);	//关闭全局中断

	if (rtc->ops->release)	//若RTC类操作函数集有release方法
		rtc->ops->release(rtc->dev.parent);	//则调用其方法

	clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
	return 0;
}

     7.7 fasync方法

static int rtc_dev_fasync(int fd, struct file *file, int on)
{
	struct rtc_device *rtc = file->private_data;
	return fasync_helper(fd, file, on, &rtc->async_queue);
}


八. 编写RTC驱动的方法

1.定义个rtc_class_ops结构体,并完成其函数功能

2.调用rtc_device_register注册一个rtc_device即可

 

九. 时间相关的一些方法

     9.1 系统时间

显示系统时间date
修改系统时间date -s hh:mm[:ss] / [YYYY.]MM.DD-hh:mm[:ss] / YYYY-MM-DD hh:mm[:ss] / MMDDhhmm[[YY]YY][.ss]

     9.2 rtc时间
hwclock --show 显示硬件时钟时间
hwclock --hctosys 根据硬件时钟修改系统时间
hwclock --systohc 根据系统时间修改硬件时钟

 

 

 

 



 

 

 

你可能感兴趣的:(linux设备驱动,linux设备驱动)