<delect id="sj01t"></delect>
  1. <em id="sj01t"><label id="sj01t"></label></em>
  2. <div id="sj01t"></div>
    1. <em id="sj01t"></em>

            <div id="sj01t"></div>
            操作系統

            Linux系統字符設備驅動框架筆記

            時間:2025-05-09 13:31:40 操作系統 我要投稿
            • 相關推薦

            Linux系統字符設備驅動框架筆記

              不積跬步,何以至千里。掌握知識都是從很小的點開始的。下面是小編整理的Linux系統字符設備驅動框架筆記,歡迎閱讀!

            Linux系統字符設備驅動框架筆記

              字符設備是Linux三大設備之一(另外兩種是塊設備,網絡設備),字符設備就是字節流形式通訊的I/O設備,絕大部分設備都是字符設備,常見的字符設備包括鼠標、鍵盤、顯示器、串口等等,當我們執行 ls -l /dev 的時候,就能看到大量的設備文件, c 就是字符設備, b 就是塊設備,網絡設備沒有對應的設備文件。編寫一個外部模塊的字符設備驅動,除了要實現編寫一個模塊所需要的代碼之外,還需要編寫作為一個字符設備的代碼。

              驅動模型

              Linux一切皆文件,那么作為一個設備文件,它的操作方法接口封裝在 struct file_operations ,當我們寫一個驅動的時候,一定要實現相應的接口,這樣才能使這個驅動可用,Linux的內核中大量使用"注冊+回調"機制進行驅動程序的編寫,所謂注冊回調,簡單的理解,就是當我們open一個設備文件的時候,其實是通過VFS找到相應的inode,并執行此前創建這個設備文件時注冊在inode中的open函數,其他函數也是如此,所以,為了讓我們寫的驅動能夠正常的被應用程序操作,首先要做的就是實現相應的方法,然后再創建相應的設備文件。

              #include //for struct cdev

              #include //for struct file

              #include //for copy_to_user

              #include //for error number

              /* 準備操作方法集 */

              /*

              struct file_operations {

              struct module *owner; //THIS_MODULE

              //讀設備

              ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

              //寫設備

              ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

              //映射內核空間到用戶空間

              int (*mmap) (struct file *, struct vm_area_struct *);

              //讀寫設備參數、讀設備狀態、控制設備

              long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

              //打開設備

              int (*open) (struct inode *, struct file *);

              //關閉設備

              int (*release) (struct inode *, struct file *);

              //刷新設備

              int (*flush) (struct file *, fl_owner_t id);

              //文件定位

              loff_t (*llseek) (struct file *, loff_t, int);

              //異步通知

              int (*fasync) (int, struct file *, int);

              //POLL機制

              unsigned int (*poll) (struct file *, struct poll_table_struct *);

              。。。

              };

              */

              ssize_t myread(struct file *filep, char __user * user_buf, size_t size, loff_t* offset)

              {

              return 0;

              }

              struct file fops = {

              .owner = THIS_MODULE,

              .read = myread,

              ...

              };

              /* 字符設備對象類型 */

              struct cdev {

              //public

              struct module *owner; //模塊所有者(THIS_MODULE),用于模塊計數

              const struct file_operations *ops; //操作方法集(分工:打開、關閉、讀/寫、...)

              dev_t dev; //設備號(第一個)

              unsigned int count; //設備數量

              //private

              ...

              };

              static int __init chrdev_init(void)

              {

              ...

              /* 構造cdev設備對象 */

              struct cdev *cdev_alloc(void);

              /* 初始化cdev設備對象 */

              void cdev_init(struct cdev*, const struct file_opeartions*);

              /* 為字符設備靜態申請設備號 */

              int register_chedev_region(dev_t from, unsigned count, const char* name);

              /* 為字符設備動態申請主設備號 */

              int alloc_chedev_region(dev_t* dev, unsigned baseminor, unsigned count, const char* name);

              MKDEV(ma,mi) //將主設備號和次設備號組合成設備號

              MAJOR(dev) //從dev_t數據中得到主設備號

              MINOR(dev) //從dev_t數據中得到次設備號

              /* 注冊字符設備對象cdev到內核 */

              int cdev_add(struct cdev* , dev_t, unsigned);

              ...

              }

              static void __exit chrdev_exit(void)

              {

              ...

              /* 從內核注銷cdev設備對象 */

              void cdev_del(struct cdev* );

              /* 從內核注銷cdev設備對象 */

              void cdev_put(stuct cdev *);

              /* 回收設備號 */

              void unregister_chrdev_region(dev_t from, unsigned count);

              ...

              }

              實現read,write

              Linux下各個進程都有自己獨立的進程空間,即使是將內核的數據映射到用戶進程,該數據的PID也會自動轉變為該用戶進程的PID,由于這種機制的存在,我們不能直接將數據從內核空間和用戶空間進行拷貝,而需要專門的拷貝數據函數/宏:

              long copy_from_user(void *to, const void __user * from, unsigned long n)

              long copy_to_user(void __user *to, const void *from, unsigned long n)

              這兩個函數可以將內核空間的數據拷貝到回調該函數的用戶進程的用戶進程空間,有了這兩個函數,內核中的read,write就可以實現內核空間和用戶空間的數據拷貝。

              ssize_t myread(struct file *filep, char __user * user_buf, size_t size, loff_t* offset)

              {

              long ret = 0;

              size = size > MAX_KBUF?MAX_KBUF:size;

              if(copy_to_user(user_buf, kbuf,size)

              return -EAGAIN;

              }

              return 0;

              }

            【Linux系統字符設備驅動框架筆記】相關文章:

            有無操作系統的嵌入式Linux驅動設備有何區別07-20

            Linux系統下USB驅動程序的設計與開發10-21

            Linux系統調用設備的ioctl函數10-20

            Linux系統中怎么掛載外界設備06-14

            linux系統命令(經典)01-25

            linux系統命令11-23

            C語言簡單的字符驅動程序介紹09-22

            Linux操作系統學習筆記權限管理09-26

            linux系統命令大全08-16

            <delect id="sj01t"></delect>
            1. <em id="sj01t"><label id="sj01t"></label></em>
            2. <div id="sj01t"></div>
              1. <em id="sj01t"></em>

                      <div id="sj01t"></div>
                      黄色视频在线观看