<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > arm驅(qū)動linux內(nèi)核時鐘

          arm驅(qū)動linux內(nèi)核時鐘

          作者: 時間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
          《[arm驅(qū)動]linux內(nèi)核時鐘》涉及內(nèi)核驅(qū)動函數(shù)四個,內(nèi)核結(jié)構(gòu)體一個,分析了內(nèi)核驅(qū)動函數(shù)一個;可參考的相關(guān)應(yīng)用程序模板或內(nèi)核驅(qū)動模板一個,可參考的相關(guān)應(yīng)用程序模板或內(nèi)核驅(qū)動一個

          一、內(nèi)核定時器
          意義:內(nèi)核定時器是軟件意義上的定時器,最終依賴定時器來實(shí)現(xiàn)。時鐘中斷處理程序會喚起Timer_softirq軟中斷,運(yùn)行當(dāng)前處理器上到期的所有定時器。
          二、linux設(shè)備驅(qū)動編程
          linux內(nèi)核提供一組函數(shù),時鐘數(shù)據(jù)結(jié)構(gòu);這組函數(shù)和數(shù)據(jù)結(jié)構(gòu)使驅(qū)動工程師不用關(guān)心具體的軟件定時器究竟對應(yīng)著怎樣的內(nèi)核和硬件行為。
          三、數(shù)據(jù)結(jié)構(gòu)和函數(shù):
          1)數(shù)據(jù)結(jié)構(gòu)
          結(jié)構(gòu)體一)Linux在include/linux/timer.h頭文件中定義了數(shù)據(jù)結(jié)構(gòu)timer_list來描述一個內(nèi)核定時器:

          本文引用地址:http://www.ex-cimer.com/article/201611/318226.htm

          struct timer_list {
          struct list_head list; //定時器列表
          unsigned long expires; //定時器到期時間,單位HZ等效與秒
          void (*function)(unsigned long); //處理函數(shù)
          unsigned long data;//作為參數(shù)被輸入定時器處理函數(shù)
          .................
          };

          2)定時器定義及處理函數(shù)
          a)定義一個內(nèi)核定時器

          struct timer_list my_timer;

          內(nèi)核驅(qū)動函數(shù)一)b)初始化定時器的timer_list的entry中的next指針為null

          void init_timer(struct *timer_list timer);

          內(nèi)核源碼一)init_timer內(nèi)核源碼

          void fastcall init_timer(struct timer_list *timer)
          {
          timer->entry.next = NULL;
          timer->base = __raw_get_cpu_var(tvec_bases);
          #ifdef CONFIG_TIMER_STATS
          timer->start_site = NULL;
          timer->start_pid = -1;
          memset(timer->start_comm, 0, TASK_COMM_LEN);
          #endif
          }

          內(nèi)核驅(qū)動函數(shù)二)c)添加定時器

          void add_timer(struct timer_list *timer)

          內(nèi)核驅(qū)動函數(shù)三)d)刪除定時器

          int del_timer(struct timer_list * timer)

          內(nèi)核驅(qū)動函數(shù)四)e)修改定時器的expire

          int mod_timer(struct timer_list *timer, unsigned long expires)

          模板一)四、內(nèi)核定時器使用模板(結(jié)合虛擬內(nèi)存)

          a)結(jié)構(gòu)體定義

          #define TIMERDELAY 2
          struct VirtualDisk{
          struct cdev cdev;//詳細(xì)看cdev機(jī)制
          timer_list my_timer;//設(shè)備要用的定時器
          };

          b)結(jié)構(gòu)體賦值,添加時鐘,時鐘要處理的函數(shù)

          /***********時鐘函數(shù),只需調(diào)用initMytimer************/
          //完成工作后,往往會延后expires并將定時器再次添加到內(nèi)核定時器鏈表,以便定時器能再次被觸發(fā)
          static void domytimer(unsigned long arg){//just used by initMytimer function
          struct VirtualDisk* myVirtualDiskp = (struct VirtualDisk *)(arg);//很重要
          //..........加上你還要做的代碼............
          printk("arg is %ldn", myVirtualDiskp->mytimer.expires);//打印現(xiàn)在的expires
          myVirtualDiskp->mytimer.expires = jiffies + (TIMERDELAY*HZ);//"HZ"等效與"秒"
          add_timer(&myVirtualDiskp->mytimer);
          //.......................
          }
          static void initMytimer(struct VirtualDisk *myVirtualDiskp, int delay){
          init_timer(&myVirtualDiskp->mytimer);
          myVirtualDiskp->mytimer.data = (unsigned long) myVirtualDiskp;
          myVirtualDiskp->mytimer.function = &domytimer;
          myVirtualDiskp->mytimer.expires = jiffies + (delay*HZ);
          add_timer(&myVirtualDiskp->mytimer);
          }
          /***********************/

          c)exit()或其他釋放函數(shù)中刪除時鐘

          if(VirtualDiskp)del_timer(&VirtualDiskp->mytimer);

          實(shí)例一)五、完整代碼

          //“timerlist_drv”,"timerlist_"
          #include //模塊所需的大量符號和函數(shù)定義
          #include
          #include //文件系統(tǒng)相關(guān)的函數(shù)和頭文件
          #include //指定初始化和清除函數(shù)
          #include
          #include //cdev結(jié)構(gòu)的頭文件包含
          #include
          #include
          //#include //包含驅(qū)動程序使用的大部分內(nèi)核API的定義,包括睡眠函數(shù)以及各種變量聲明
          #include //在內(nèi)核和用戶空間中移動數(shù)據(jù)的函數(shù)
          #include
          #include
          #include
          #include
          #include /*timer*/
          #include /*jiffies*/
          #define VIRTUALDISK_SIZE 0x1000//4k
          #define MEM_CLEAR 0x1
          #define VIRTUALDISK_MAJOR 250
          /******timer *******/
          #define TIMERDELAY 2
          int VirtualDisk_major = VIRTUALDISK_MAJOR;
          struct VirtualDisk{
          struct cdev cdev;//詳細(xì)看cdev機(jī)制
          unsigned char mem[VIRTUALDISK_SIZE ];
          long count; /*記錄設(shè)備目前被多少設(shè)備打開*/
          struct timer_list mytimer;
          };
          static struct class *timerlist_class;
          static struct class_device *timerlist_class_dev;
          struct VirtualDisk *VirtualDiskp;
          /*********timer opration*************/
          static void domytimer(unsigned long arg){//just used by follow function
          struct VirtualDisk* myVirtualDiskp = (struct VirtualDisk *)(arg);
          printk("arg is %ldn", myVirtualDiskp->mytimer.expires);
          myVirtualDiskp->mytimer.expires = jiffies + (TIMERDELAY*HZ);
          add_timer(&myVirtualDiskp->mytimer);
          }
          static void initMytimer(struct VirtualDisk *myVirtualDiskp, int delay){
          init_timer(&myVirtualDiskp->mytimer);
          myVirtualDiskp->mytimer.data = (unsigned long) myVirtualDiskp;
          myVirtualDiskp->mytimer.function = &domytimer;
          myVirtualDiskp->mytimer.expires = jiffies + (delay*HZ);
          add_timer(&myVirtualDiskp->mytimer);
          }
          /*********timer opration over*************/
          static int timerlist_drv_open(struct inode *inode, struct file *file)
          {
          printk("timerlist_dev readn");
          file->private_data = VirtualDiskp;
          VirtualDiskp->count++; /*增加設(shè)備打開次數(shù)*/
          return 0;
          }
          static int timerlist_drv_release(struct inode *inode, struct file *file)
          {
          printk("timerlist_dev releasen");
          VirtualDiskp->count--; /*減少設(shè)備打開次數(shù)*/
          return 0;
          }
          /*seek文件定位函數(shù):seek()函數(shù)對文件定位的起始地址可以是文件開頭(SEEK_SET,0)、當(dāng)前位置(SEEK_CUR,1)、文件尾(SEEK_END,2)*/
          static loff_t timerlist_drv_llseek(struct file *file, loff_t offset, int origin){
          loff_t ret = 0;/*返回的位置偏移*/
          switch (origin)
          {
          case SEEK_SET: /*相對文件開始位置偏移*/
          if (offset < 0)/*offset不合法*/
          {
          ret = - EINVAL; /*無效的指針*/
          break;
          }
          if ((unsigned int)offset > VIRTUALDISK_SIZE)/*偏移大于設(shè)備內(nèi)存*/
          {
          ret = - EINVAL; /*無效的指針*/
          break;
          }
          file->f_pos = (unsigned int)offset; /*更新文件指針位置*/
          ret = file->f_pos;/*返回的位置偏移*/
          break;
          case SEEK_CUR: /*相對文件當(dāng)前位置偏移*/
          if ((file->f_pos + offset) > VIRTUALDISK_SIZE)/*偏移大于設(shè)備內(nèi)存*/
          {
          ret = - EINVAL;/*無效的指針*/
          break;
          }
          if ((file->f_pos + offset) < 0)/*指針不合法*/
          {
          ret = - EINVAL;/*無效的指針*/
          break;
          }
          file->f_pos += offset;/*更新文件指針位置*/
          ret = file->f_pos;/*返回的位置偏移*/
          break;
          default:
          ret = - EINVAL;/*無效的指針*/
          break;
          }
          return ret;
          }
          /*設(shè)備控制函數(shù):ioctl()函數(shù)接受的MEM_CLEAR命令,這個命令將全局內(nèi)存的有效數(shù)據(jù)長度清零,對于設(shè)備不支持的命令,ioctl()函數(shù)應(yīng)該返回-EINVAL*/
          static int timerlist_drv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){
          struct VirtualDisk *devp = file->private_data;/*獲得設(shè)備結(jié)構(gòu)體指針*/
          switch (cmd)
          {
          case MEM_CLEAR:/*設(shè)備內(nèi)存清零*/
          memset(devp->mem, 0, VIRTUALDISK_SIZE);
          printk(KERN_INFO "VirtualDisk is set to zeron");
          break;
          default:
          return - EINVAL;
          }
          return 0;
          }
          /*讀函數(shù):讀寫函數(shù)主要是讓設(shè)備結(jié)構(gòu)體的mem[]數(shù)組與用戶空間交互數(shù)據(jù),并隨著訪問字節(jié)數(shù)變更返回用戶的文件讀寫偏移位置*/
          static ssize_t timerlist_drv_read(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
          {
          printk("timerlist_dev readn");
          unsigned long p = *ppos; /*記錄文件指針偏移位置*/
          unsigned int countt = count;/*記錄需要讀取的字節(jié)數(shù)*/
          int ret = 0; /*返回值*/
          struct VirtualDisk *devp = file->private_data; /*獲得設(shè)備結(jié)構(gòu)體指針*/
          /*分析和獲取有效的讀長度*/
          if (p >= VIRTUALDISK_SIZE ) /*要讀取的偏移大于設(shè)備的內(nèi)存空間*/
          return countt ? - ENXIO: 0;/*讀取地址錯誤*/
          if (countt > VIRTUALDISK_SIZE - p)/*要讀取的字節(jié)大于設(shè)備的內(nèi)存空間*/
          countt = VIRTUALDISK_SIZE - p;/*將要讀取的字節(jié)數(shù)設(shè)為剩余的字節(jié)數(shù)*/
          /*內(nèi)核空間->用戶空間交換數(shù)據(jù)*/
          if (copy_to_user(buf, (void*)(devp->mem + p), countt))
          {
          ret = - EFAULT;
          }
          else
          {
          *ppos += countt;
          ret = countt;
          printk("read %d bytes(s) is %ldn", countt, p);
          }
          printk("bytes(s) is %sn", buf);
          initMytimer(devp, 2);
          return ret;
          }
          /*
          file 是文件指針,count 是請求的傳輸數(shù)據(jù)長度,buff 參數(shù)是指向用戶空間的緩沖區(qū),這個緩沖區(qū)或者保存要寫入的數(shù)據(jù),或者是一個存放新讀入數(shù)據(jù)的空緩沖區(qū),該地址在內(nèi)核空間不能直接讀寫,ppos 是一個指針指向一個"long offset type"對象, 它指出用戶正在存取的文件位置. 返回值是一個"signed size type。寫的位置相對于文件開頭的偏移。
          */
          static ssize_t timerlist_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
          {
          printk("timerlist_dev writen");
          unsigned long p = *ppos; /*記錄文件指針偏移位置*/
          int ret = 0; /*返回值*/
          unsigned int countt = count;/*記錄需要寫入的字節(jié)數(shù)*/
          struct VirtualDisk *devp = file->private_data; /*獲得設(shè)備結(jié)構(gòu)體指針*/
          /*分析和獲取有效的寫長度*/
          if (p >= VIRTUALDISK_SIZE )/*要寫入的偏移大于設(shè)備的內(nèi)存空間*/
          return countt ? - ENXIO: 0;/*寫入地址錯誤*/
          if (countt > VIRTUALDISK_SIZE - p)/*要寫入的字節(jié)大于設(shè)備的內(nèi)存空間*/
          countt = VIRTUALDISK_SIZE - p;/*將要寫入的字節(jié)數(shù)設(shè)為剩余的字節(jié)數(shù)*/
          /*用戶空間->內(nèi)核空間*/
          if (copy_from_user(devp->mem + p, buf, countt))
          ret = - EFAULT;
          else
          {
          *ppos += countt;/*增加偏移位置*/
          ret = countt;/*返回實(shí)際的寫入字節(jié)數(shù)*/
          printk("written %d bytes(s) from%ldn", countt, p);
          }
          return ret;
          return 0;
          }
          static struct file_operations timerlist_drv_fops = {
          .owner = THIS_MODULE, /* 這是一個宏,推向編譯模塊時自動創(chuàng)建的__this_module變量 */
          .read = timerlist_drv_read,
          .write = timerlist_drv_write,
          .open = timerlist_drv_open,
          .release = timerlist_drv_release,
          .llseek = timerlist_drv_llseek,
          .ioctl = timerlist_drv_ioctl,
          };
          /*將 cdev 結(jié)構(gòu)嵌入一個你自己的設(shè)備特定的結(jié)構(gòu),你應(yīng)當(dāng)初始化你已經(jīng)分配的結(jié)構(gòu)使用以上函數(shù),有一個其他的 struct cdev 成員你需要初始化. 象 file_operations 結(jié)構(gòu),struct cdev 有一個擁有者成員,應(yīng)當(dāng)設(shè)置為 THIS_MODULE,一旦 cdev 結(jié)構(gòu)建立, 最后的步驟是把它告訴內(nèi)核, 調(diào)用:
          cdev_add(&dev->cdev, devno, 1);*/
          static void VirtualDisk_setup_cdev(struct VirtualDisk *dev, int minorIndex){
          int err;
          int devno = MKDEV(VirtualDisk_major, minorIndex);
          cdev_init(&dev->cdev, &timerlist_drv_fops);
          dev->cdev.owner = THIS_MODULE;
          err = cdev_add(&dev->cdev, devno, 1);
          if(err){
          printk("error %d cdev file addedn", err);
          }
          }
          static int timerlist_drv_init(void)
          {
          int result;
          dev_t devno = MKDEV(VirtualDisk_major, 0);
          if(VirtualDisk_major){
          result = register_chrdev_region(devno, 1, "timerlist_dev");
          }else{
          result = alloc_chrdev_region(&devno, 0, 1, "timerlist_dev");
          VirtualDisk_major = MAJOR(devno);
          }
          if(result < 0 ){
          return result;
          }
          VirtualDiskp = kmalloc(sizeof(struct VirtualDisk), GFP_KERNEL);
          if(!VirtualDiskp){
          result = -ENOMEM;
          goto fail_malloc;
          }
          memset(VirtualDiskp, 0, sizeof(struct VirtualDisk));
          VirtualDisk_setup_cdev(VirtualDiskp, 0);
          timerlist_class = class_create(THIS_MODULE, "timerlist_drv");
          if (IS_ERR(timerlist_class))
          return PTR_ERR(timerlist_class);
          timerlist_class_dev = class_device_create(timerlist_class, NULL, MKDEV(VirtualDisk_major, 0), NULL, "timerlist_dev"); /* /dev/xyz */
          if (IS_ERR(timerlist_class_dev))
          return PTR_ERR(timerlist_class_dev);
          return 0;
          fail_malloc:
          unregister_chrdev_region(devno, 1);
          return result;
          }
          static void timerlist_drv_exit(void)
          {
          if(VirtualDiskp)del_timer(&VirtualDiskp->mytimer);
          cdev_del(&VirtualDiskp->cdev);
          kfree(VirtualDiskp);
          unregister_chrdev_region(MKDEV(VirtualDisk_major, 0), 1);
          class_device_unregister(timerlist_class_dev);
          class_destroy(timerlist_class);
          }
          module_init(timerlist_drv_init);
          module_exit(timerlist_drv_exit);
          MODULE_LICENSE("GPL");



          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();