标签:
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字符设备,因为rtc就是个字符设备 unsigned long flags; //rtc的状态标志,例如RTC_DEV_BUSY unsigned long irq_data; //rtc中断数据 spinlock_t irq_lock; //访问数据是要互斥,需要spin_lock wait_queue_head_t irq_queue; //数据查询中用到rtc队列 struct fasync_struct *async_queue; //异步队列 struct rtc_task *irq_task; //在中断中使用task传输数据 spinlock_t irq_task_lock; //task传输互斥 int irq_freq; //rtc的中断频率 int max_user_freq; //rtc的最大中断频率 struct timerqueue_head timerqueue; //定时器队列 struct rtc_timer aie_timer; //aie(alaram interrupt enable)定时器 struct rtc_timer uie_rtctimer; //uie(update interrupt enable)定时器 struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */ //pie(periodic interrupt enable)定时器 int pie_enabled; //pie使能标志 struct work_struct irqwork; /* Some hardware can't support UIE mode */ int uie_unsupported; //uie使能标志 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL //RTC UIE emulation on dev interface配置项,目前没有开启 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驱动的核心结构,当驱动程序使用rtc_device_register函数传递正确的参数,然后就返回struct rtc_deivce给驱动程序。而在这个结构中rtc_class_ops函数需要驱动程序实现。
struct rtc_class_ops { int (*open)(struct device *); void (*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 *); 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); int (*read_callback)(struct device *, int data); int (*alarm_irq_enable)(struct device *, unsigned int enabled); };这些函数中大部分需要驱动程序实现,比如open, read_time, set_time等。这些函数大多数都是和rtc芯片的操作有关。
void __init rtc_dev_init(void) { int err; err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); if (err < 0) pr_err("failed to allocate char dev region\n"); }动态分配一个次设备号为0,相同设备的最大个数为16的字符设备。该函数会在rtc_init函数中被调用。
void rtc_dev_prepare(struct rtc_device *rtc) { if (!rtc_devt) return; if (rtc->id >= RTC_DEV_MAX) { //合法性判断,如果id大于16个,说明rtc设备个数太多 dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name); return; } rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL //UIE模拟配置相关,不做过多介绍 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->char_dev.owner = rtc->owner; }该函数主要是初始化字符设备,设置rtc相关的file operation函数集合。
void rtc_dev_add_device(struct rtc_device *rtc) { if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1)) dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n", rtc->name, MAJOR(rtc_devt), rtc->id); else dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name, MAJOR(rtc_devt), rtc->id); }调用cdev_add函数将rtc字符设备加入到内核中。这样以来rtc字符设备已经加入到系统中,就等待应用程序的调用。应用程序操作之前还需要实现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, };以上就是rtc字符设备驱动对应的file operation操作函数集合。接下来一个一个分析。
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); const struct rtc_class_ops *ops = rtc->ops; //获得驱动的rtc ops if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) //检测rtc是否现在在使用,如果没有使用即可open return -EBUSY; file->private_data = rtc; //将rtc放入到private_data变量中 err = ops->open ? ops->open(rtc->dev.parent) : 0; //如果驱动实现open函数,就调用驱动的open,如果没有实现返回0 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); //离开的时候将rtc设备为不忙 return err; }
/** * test_and_set_bit_lock - Set a bit and return its old value, for lock * @nr: Bit to set * @addr: Address to count from * * This operation is atomic and provides acquire barrier semantics. * It can be used to implement bit locks. */ #define test_and_set_bit_lock(nr, addr) test_and_set_bit(nr, addr)设置一个bit然后返回以前的值, 用于检测是设备是否在使用。
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; //从private_data域取出rtc数据,在open中设置的private_data DECLARE_WAITQUEUE(wait, current); //声明一个等待队列wait 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; //读取irq_date的数据,在中断中有数据的时候会设置irq_date的值 rtc->irq_data = 0; spin_unlock_irq(&rtc->irq_lock); if (data != 0) { //data不等于0,说明有数据,跳出while循环 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); //执行到这里说明是从上述3种情况break出来的,然后将进程状态设置为running remove_wait_queue(&rtc->irq_queue, &wait); //从等待队列移除wait if (ret == 0) { //ret等于0,说明是rtc中断触发导致退出while循环 /* Check for any data updates */ if (rtc->ops->read_callback) //驱动程序是否实现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; }该函数一般可以用来判断是否有rtc中断发生,如果有read读就不会blocked。 而此read不是用来读取具体时间的函数。
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); //使用poll系统调用,一直等待有数据是否到来 data = rtc->irq_data; return (data != 0) ? (POLLIN | POLLRDNORM) : 0; //返回结果(有数据可读|有普通数据可读) }接下来分析rtc的重点函数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; 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; /* RTC_ALM_SET alarms may be up to 24 hours in the future. * Rather than expecting every RTC to implement "don't care" * for day/month/year fields, just force the alarm to have * the right values for those fields. * * RTC_WKALM_SET should be used instead. Not only does it * eliminate the need for a separate RTC_AIE_ON call, it * doesn't have the "alarm 23:59:59 in the future" race. * * NOTE: some legacy code may have used invalid fields as * wildcards, exposing hardware "periodic alarm" capabilities. * Not supported here. */ { 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: //Enable the periodic interrupt err = rtc_irq_set_state(rtc, NULL, 1); break; case RTC_PIE_OFF: //Disable the periodic interrupt err = rtc_irq_set_state(rtc, NULL, 0); break; case RTC_AIE_ON: //Enable the alarm interrupt mutex_unlock(&rtc->ops_lock); return rtc_alarm_irq_enable(rtc, 1); case RTC_AIE_OFF: //Disable the alarm interrupt mutex_unlock(&rtc->ops_lock); return rtc_alarm_irq_enable(rtc, 0); case RTC_UIE_ON: //Enable the interrupt on every clock update mutex_unlock(&rtc->ops_lock); return rtc_update_irq_enable(rtc, 1); case RTC_UIE_OFF: //Disable the interrupt on every clock update mutex_unlock(&rtc->ops_lock); return rtc_update_irq_enable(rtc, 0); case RTC_IRQP_SET: //Set IRQ rate err = rtc_irq_set_freq(rtc, NULL, arg); break; case RTC_IRQP_READ: //Read IRQ rate err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); break; case RTC_WKALM_SET: //Set wakeup alarm 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: //Get wakeup alarm 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: //默认操作,如果驱动不实现上述操作,可以实现自己的命令,然后走这里分支。 /* Finally try the driver's ioctl interface */ if (ops->ioctl) { err = ops->ioctl(rtc->dev.parent, cmd, arg); if (err == -ENOIOCTLCMD) err = -ENOTTY; } else err = -ENOTTY; break; } done: mutex_unlock(&rtc->ops_lock); return err; }以上就是全部ioctl的操作,大多数rtc的功能都在这个函数中的case当中被调用。
static int rtc_dev_release(struct inode *inode, struct file *file) { struct rtc_device *rtc = file->private_data; /* Keep ioctl until all drivers are converted */ rtc_dev_ioctl(file, RTC_UIE_OFF, 0); //关闭rtc的uie中断 rtc_update_irq_enable(rtc, 0); //disable rtc中断 rtc_irq_set_state(rtc, NULL, 0); if (rtc->ops->release) rtc->ops->release(rtc->dev.parent); //调用驱动的release函数 clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); //将rtc的状态设置为空闲,也就是不忙。 return 0; }
标签:
原文地址:http://blog.csdn.net/longwang155069/article/details/52302383