当前位置: 首页 > news >正文

购物网站开店免费wordpress 客户端源码

购物网站开店免费,wordpress 客户端源码,免费logo设计生成器免费试用,注册网站流程linux RTC 驱动模型分析RTC(real time clock)实时时钟#xff0c;主要作用是给Linux系统提供时间。RTC因为是电池供电的#xff0c;所以掉电后时间不丢失。Linux内核把RTC用作“离线”的时间与日期维护器。当Linux内核启动时#xff0c;它从RTC中读取时间与日期#xff0c;…linux RTC 驱动模型分析RTC(real time clock)实时时钟主要作用是给Linux系统提供时间。RTC因为是电池供电的所以掉电后时间不丢失。Linux内核把RTC用作“离线”的时间与日期维护器。当Linux内核启动时它从RTC中读取时间与日期作为基准值。在运行期间内核完全抛开RTC以软件的形式维护系统的当前时间与日期并在需要时将时间回写RTC芯片。另外如果RTC提供了IRQ中断并且可以定时那么RTC还可以作为内核睡眠时唤醒内核的闹钟。应用程序可以用RTC提供的周期中断做一些周期的任务。 linux有两种rtc驱动的接口一个是老的接口专门用在PC机上的。另外一钟新接口是基于linux设备驱动程序的。这个新的接口创建了一个RTC驱动模型实现了RTC的大部分基本功能。而底层驱动无须考虑一些功能的实现只需将自己注册的RTC核心中其他工作由RTC核心来完成。下面分析RTC新接口的驱动模型。一. 驱动模型结构与RTC核心有关的文件有/drivers/rtc/class.c          这个文件向linux设备模型核心注册了一个类RTC然后向驱动程序提供了注册/注销接口/drivers/rtc/rtc-dev.c       这个文件定义了基本的设备文件操作函数如open,read等/drivers/rtc/interface.c     顾名思义这个文件主要提供了用户程序与RTC驱动的接口函数用户程序一般通过ioctl与RTC驱动交互这里定义了每个ioctl命令需要调用的函数/drivers/rtc/rtc-sysfs.c     与sysfs有关/drivers/rtc/rtc-proc.c      与proc文件系统有关/include/linux/rtc.h         定义了与RTC有关的数据结构RTC驱动模型结构如下图二. 基本数据结构1. struct rtc_device 结构[cpp] view plaincopystruct rtc_device  {      struct device dev;      struct module *owner;        int id;      char name[RTC_DEVICE_NAME_SIZE];        const struct rtc_class_ops *ops;      struct mutex ops_lock;        struct cdev char_dev;      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驱动程序的基本数据结构但是他不像其他核心的基本结构一样驱动程序以他为参数调用注册函数注册到核心。这个结构是由注册函数返回给驱动程序的。2. struct rtc_class_ops 结构[cpp] view plaincopystruct 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 (*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驱动程序要实现的基本操作函数注意这里的操作不是文件操作。驱动程序通过初始化这样一个结构将自己实现的函数与RTC核心联系起来。这里面的大部分函数都要驱动程序来实现。而且这些函数都是操作底层硬件的属于最底层的函数。3. struct rtc_time 结构[cpp] view plaincopystruct 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;  };  代表了时间与日期从RTC设备读回的时间和日期就保存在这个结构体中三. class.c 1. 模块初始化函数rtc_init[cpp] view plaincopystatic int __init rtc_init(void)  {      rtc_class  class_create(THIS_MODULE, rtc);      if (IS_ERR(rtc_class)) {          printk(KERN_ERR %s: couldnt create class\n, __FILE__);          return PTR_ERR(rtc_class);      }      rtc_class-suspend  rtc_suspend;      rtc_class-resume  rtc_resume;      rtc_dev_init();      rtc_sysfs_init(rtc_class);      return 0;  }  rtc_init首先调用class_create创建了一个类--rtc。我们知道类是一个设备的高层视图他抽象出了底层的实现细节。类的作用就是向用户空间提供设备的信息驱动程序不需要直接处理类。然后初始化类结构的相应成员rtc_suspendrtc_resume这两个函数也是在class.c中实现的。接下来调用rtc_dev_init()这个函数为RTC设备动态分配设备号保存在rtc_devt中。最后调用rtc_sysfs_init初始化rtc_class的属性。2. 为底层驱动提供接口rtc_device_registerrtc_device_unregister[cpp] view plaincopystruct 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);      mutex_unlock(idr_lock);  /*--------------------(1)---------------------*/      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-owner  owner;      rtc-max_user_freq  64;      rtc-dev.parent  dev;      rtc-dev.class  rtc_class;      rtc-dev.release  rtc_device_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);      dev_set_name(rtc-dev, rtc%d, id);  /*-------------------(2)--------------------*/      rtc_dev_prepare(rtc);          err  device_register(rtc-dev);      if (err)          goto exit_kfree;  /*-------------------(3)--------------------*/      rtc_dev_add_device(rtc);      rtc_sysfs_add_device(rtc);      rtc_proc_add_device(rtc);        dev_info(dev, rtc core: registered %s as %s\n,              rtc-name, dev_name(rtc-dev));  /*-------------------(4)--------------------*/      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);  }  1处理一个idr的结构idr在linux内核中指的就是整数ID管理机制从本质上来说idr是一种将整数ID号和特定指针关联在一起的机制。这个机制最早是在2003年2月加入内核的当时是作为POSIX定时器的一个补丁。现在在内核的很多地方都可以找到idr的身影。详细实现请参照相关内核代码。这里从内核中获取一个idr结构并与id相关联。2分配了一个rtc_device的结构--rtc并且初始化了相关的成员id, rtc_class_ops等等。3首先调用rtc_dev_prepare在rtc-dev.c中定义。因为RTC设备本质来讲还是字符设备所以这里初始化了字符设备相关的结构设备号以及文件操作。然后调用device_register将设备注册到linux设备模型核心。这样在模块加载的时候udev daemon就会自动为我们创建设备文件rtc(n)。4先后调用rtc_dev_add_devicertc_sysfs_add_devicertc_proc_add_device三个函数。rtc_dev_add_device注册字符设备rtc_sysfs_add_device只是为设备添加了一个闹钟属性rtc_proc_add_device 创建proc文件系统接口。四. rtc-dev.c rtc-dev.c 初始化了一个file_operations结构--rtc_dev_fops并定义了这些操作函数。1. rtc_dev_fops rtc基本的文件操作[cpp] view plaincopystatic 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,  ;   2. 函数的实现以rtc_dev_read为例   [cpp] view plaincopyrtc_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);      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)              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;  }  这里的read不是应用程序用来获取时间的而是有其他的作用他帮助应用程序周期性的完成一些工作。如果要使用这个功能应用程序首先保证RTC驱动程序提供这样的功能。这个功能是这样实现的进程读取/dev/rtc(n)进程睡眠直到RTC中断将他唤醒。我们可以发现这里的睡眠是ldd3中提到的手工睡眠。这个函数的手工休眠过程如下首先调用DECLARE_WAITQUEUE(wait, current)声明一个等待队列入口然后调用add_wait_queue将这个入口加入到RTC的irq等待队列里然后进入循环。在循环里首先把进程的状态改成TASK_INTERRUPTIBLE这样进程就不能再被调度运行。但是现在进程还在运行没有进入睡眠状态。程序然后读取RTC里面的irq_data如果不是零那么程序跳出这个循环进程不会睡眠。因为这个irq_data在rtc的中断处理程序会被赋值而读过之后就会清零所以如果数据不是零的话说明发生过一次中断。如果是零那么没有发生中断调用schedule进程会被调度出可运行队列从而让出处理器真正进入睡眠。跳出循环代表被唤醒然后将进程状态改变为可运行移除等待队列入口。最后将读回的数据传给用户空间。五. interface.c interface.c里的所有函数的实现都对应于rtc-dev.c 中ioctl相应的命令。对应关系如下RTC_ALM_READ                     rtc_read_alarm           读取闹钟时间RTC_ALM_SET                      rtc_set_alarm            设置闹钟时间RTC_RD_TIME                      rtc_read_time            读取时间与日期RTC_SET_TIME                     rtc_set_time             设置时间与日期RTC_PIE_ON RTC_PIE_OFF           rtc_irq_set_state              开关RTC全局中断的函数RTC_AIE_ON RTC_AIE_OFF           rtc_alarm_irq_enable     使能禁止RTC闹钟中断RTC_UIE_OFF RTC_UIE_ON           rtc_update_irq_enable    使能禁止RTC更新中断RTC_IRQP_SET                     rtc_irq_set_freq         设置中断的频率以上就是所有ioctl的命令与实现的对应关系。其中如果不涉及中断的话有两个命令需要我们特别关心一下就是RTC_RD_TIME与RTC_SET_TIME。因为RTC最基本的功能就是提供时间与日期。这两个命令恰恰是获取时间和设置时间。下面分析一下这两个命令的实现也就是rtc_set_alarm与rtc_read_time函数的实现1. rtc_read_time 函数[cpp] view plaincopyint rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)  {      int err;        err  mutex_lock_interruptible(rtc-ops_lock);      if (err)          return err;        if (!rtc-ops)          err  -ENODEV;      else if (!rtc-ops-read_time)          err  -EINVAL;      else {          memset(tm, 0, sizeof(struct rtc_time));          err  rtc-ops-read_time(rtc-dev.parent, tm);      }        mutex_unlock(rtc-ops_lock);      return err;  }  这个函数用了一个信号来保证在同一时刻只有一个进程可以获取时间。锁定了这个信号量后调用rtc-ops里面read函数这个函数是由具体的驱动程序实现的操作底层硬件。读回的时间存放在rtc_time结构里面的。2. rtc_set_time 函数[cpp] view plaincopyint rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)  {      int err;        err  rtc_valid_tm(tm);      if (err ! 0)          return err;        err  mutex_lock_interruptible(rtc-ops_lock);      if (err)          return err;        if (!rtc-ops)          err  -ENODEV;      else if (rtc-ops-set_time)          err  rtc-ops-set_time(rtc-dev.parent, tm);      else if (rtc-ops-set_mmss) {          unsigned long secs;          err  rtc_tm_to_time(tm, secs);          if (err  0)              err  rtc-ops-set_mmss(rtc-dev.parent, secs);      } else          err  -EINVAL;        mutex_unlock(rtc-ops_lock);      return err;  }  这个函数其实和rtc_read_time函数差不多同样是锁定信号量同样是调用底层驱动函数。但是这里的设置时间提供了两个调用一个是set_time一个是set_mmss。因为有的RTC硬件只计算秒数不关心墙钟时间所以如果是这样的RTC必须实现set_mmss来设置时间。六. rtc-sysfs.c 部分这个部分主要是有关sysfs的操作。rtc-sysfs.c中定义了这样一个设备属性组如下[cpp] view plaincopystatic struct device_attribute rtc_attrs[]  {      __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),      __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),      __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),      __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),      __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,            rtc_sysfs_set_max_user_freq),      __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),       { },  };  这个属性组是在class.c的模块初始化函数中由rtc_sysfs_init函数赋值给rtc_class-dev_attrs的以后属于这个类的设备都会有这些属性。但是我们知道要想一个设备结构拥有一种属性必须调用device_create_file这样才会使这个属性出现在sysfs相关设备目录里。但是在这里的代码中只是给这个类的dev_attrs域赋值了这个属性组指针而没有调用device_create_file。我原来以为是在rtc_device_resgister函数中由rtc_sysfs_add_device完成这个工作但是这个函数只是给设备添加了闹钟属性并没有处理这个属性组。最后发现这个工作是由device_register来完成的。这里的调用关系有点复杂 device_register调用device_add device_add调用 device_add_attrsdevice_add_attrs调用device_add_attributes device_add_attributes调用device_create_file来完成设备的属性设置的。设置完属性后在/sys/class/rtc/rtc(n)的目录下就会出现namedatetime等文件用户读这些文件的时候就会调用相应的函数。如读取name文件就会调用rtc_sysfs_show_name函数这个函数也是在rtc-sysfs.c中实现的作用是读取并显示时间。 七. rtc-proc.c 这个文件提供RTC的proc文件系统接口。proc文件系统是软件创建的文件系统内核通过他向外界导出信息下面的每一个文件都绑定一个函数当用户读取这个文件的时候这个函数会向文件写入信息。rtc-proc.c中初始化了一个文件操作[cpp] view plaincopystatic const struct file_operations rtc_proc_fops  {      .open        rtc_proc_open,      .read        seq_read,      .llseek      seq_lseek,      .release     rtc_proc_release,  };  RTC驱动在向RTC核心注册自己的时候由注册函数rtc_device_resgister调用rtc_proc_add_device来实现proc接口的初始化这个函数如下定义[cpp] view plaincopyvoid rtc_proc_add_device(struct rtc_device *rtc)  {      if (rtc-id  0)          proc_create_data(driver/rtc, 0, NULL, rtc_proc_fops, rtc);  }  他主要调用了proc_create_data。proc_create_data完成创建文件节点的作用并将文件的操作函数与节点联系起来。调用这个函数后在/proc/driver目录下就会有一个文件rtc应用程序打开这个文件就会调用rtc_proc_open函数这个函数如下定义[cpp] view plaincopystatic 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);  }  我们知道一个proc的文件必须与一个操作函数组成一个proc入口项这个文件才能正常工作。这个函数最主要作用就是调用single_open创建一个proc文件入口项使其操作函数是rtc_proc_show并初始化seq_file接口。rtc_proc_show函数如下定义[cpp] view plaincopystatic 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);        return 0;  }  这个函数就是最后给用户显示信息的函数了可以看出他通过调用rtc_deivce中的操作函数读取时间日期和一些其他的信息显示给用户。 六. 总结RTC核心使底层硬件对用户来说是透明的并且减少了编写驱动程序的工作量。RTC新的驱动接口提供了更多的功能使系统可以同时存在多个RTC。/devsysfsproc这三种机制的实现使得应用程序能灵活的使用RTCRTC核心虽然表面上看上去很简单但是还是涉及到很多知识有些东西书上讲的还是不够详细还需要通过分析代码加深理解。 另外RTC核心代码的组织方式也值得学习不同功能的代码放在不同的文件中简单明了。
http://www.yutouwan.com/news/151212/

相关文章:

  • 网站建设详细的步骤有哪些网络系统管理技能大赛答案
  • 网站怎么做文件下载做网站展示软件
  • 中山网站建设文化咨询供求信息网站建设报价
  • 设计的网站怎么添加域名深圳东莞网站建设
  • 怎样在百度上建立网站wordpress建导航
  • 河间市网站建设价格佛山外贸网站建设报价
  • 网络小说网站推广策划方案怎么搭建论坛
  • 网站建设的心得与体会网站建设敬请期待图片素材
  • 凡科网h5lnmp wordpress优化
  • 企业自己做网站工作站做网站
  • h5做网站什么软件广元网站设计
  • 网站建设服务支持泉州做网站优化的公司
  • 学建设网站首页wordpress 分页个数
  • 企业网站的建设与流程做网站为何要续费
  • 语言文字建设网站长春火车站
  • 动态海报网站什么叫网站流量
  • 姑苏区住房建设局网站土建找工作去哪个网站
  • 网站违规关键词禁止搜索引擎收录的方法
  • 怎样做集装箱网站一篇网站设计小结
  • 网站 备案信息浙江网上职工之家
  • wordpress群站域名品牌加盟网
  • 中国铁路建设工程招标网站企业文化vi设计
  • 模板wordpress演示站怎么做如何做旅游网站的旅行家
  • wordpress网站演示wordpress 搜索结果
  • 网站建设收费标准策划wordpress文章 公众号
  • 公司网站开发策划深圳东门市场
  • 网站建设 风险说明江苏提升关键词排名收费
  • 郑州百度seo网站优网站的图片怎么做
  • 浙江广厦建设职业技术学院招生网站html登录注册页面代码
  • wordpress标题字体太大seo推广教程视频