新聞中心

        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)核定時器是軟件意義上的定時器,最終依賴定時器來實現(xiàn)。時鐘中斷處理程序會喚起Timer_softirq軟中斷,運行當(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.104case.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機制
        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);

        實例一)五、完整代碼

        //“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機制
        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;/*返回實際的寫入字節(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)閉
        主站蜘蛛池模板: 阳朔县| 新郑市| 白山市| 海安县| 玛沁县| 新化县| 新竹县| 西平县| 延安市| 温宿县| 吕梁市| 泰兴市| 濮阳县| 上高县| 仪征市| 广州市| 十堰市| 马鞍山市| 通许县| 洮南市| 青岛市| 平塘县| 大埔区| 贵阳市| 醴陵市| 浮山县| 九龙县| 萨嘎县| 利川市| 财经| 巩义市| 香港 | 汉沽区| 潜江市| 子长县| 塔河县| 齐河县| 察雅县| 任丘市| 南城县| 五河县|