久久婷婷香蕉热狠狠综合,精品无码国产自产拍在线观看蜜,寡妇房东在做爰3,中文字幕日本人妻久久久免费,国产成人精品三上悠亚久久

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > Linux底(di)層(ceng)驅(qu)動開發(fa)需要學習哪(na)些內容

Linux底層驅動開發需要學(xue)習哪些內容 時間(jian):2018-01-09      來源:未知(zhi)

Linux底層驅(qu)動(dong)開(kai)發需要學(xue)習(xi)哪些內(nei)容想必(bi)這(zhe)是很(hen)多學(xue)習(xi)Linux的朋(peng)友十(shi)分頭疼的問題,今(jin)天就(jiu)讓我來告訴大家我們到(dao)底該學(xue)習(xi)哪些內(nei)容呢?

1. 要(yao)會一些硬件知識(shi),比(bi)如Arm接口編程

2. 學會寫簡(jian)單的makefile

3. 編(bian)一應用(yong)程序,可以用(yong)makefile跑起來

4. 學會寫(xie)驅動的(de)makefile

5. 寫一簡單char驅(qu)動,makefile編譯通過(guo),可以(yi)insmod, lsmod, rmmod. 在(zai)驅(qu)動的init函(han)數里(li)打印hello world, insmod后應該(gai)能夠通過(guo)dmesg看到輸出(chu)。

6. 寫一(yi)完整驅動(dong), 加上read, write, ioctl, polling等各種(zhong)函(han)數的(de)(de)驅動(dong)實(shi)現。 在(zai)ioctl里完成(cheng)從用戶空(kong)(kong)間向內核(he)空(kong)(kong)間傳遞結構體的(de)(de)實(shi)現。

7. 寫一block驅動, 加上read,write,ioctl,poll等各種函數實現。

8. 簡單(dan)學習下內存管理, 這個是難的,明白各種memory alloc的函(han)數實現細節。這是Linux開發的基本功。

9. 學習鎖機(ji)制的應用(yong),這個(ge)不是難的但是容(rong)易(yi)犯(fan)錯的,涉(she)及到很多同(tong)步和并發(fa)的問題(ti)。

10. 看內核中實(shi)(shi)際應用的(de)(de)(de)(de)(de)驅動代碼。 你會(hui)發(fa)現基(ji)本的(de)(de)(de)(de)(de)你已經知(zhi)道(dao)了(le), 大的(de)(de)(de)(de)(de)框(kuang)架都是一樣(yang)的(de)(de)(de)(de)(de), 無非是read, write, ioctl等函數的(de)(de)(de)(de)(de)實(shi)(shi)現, 但(dan)里(li)面包含了(le)很(hen)多很(hen)多細小的(de)(de)(de)(de)(de)實(shi)(shi)現細節是之前(qian)不(bu)(bu)知(zhi)道(dao)的(de)(de)(de)(de)(de)。 這時候就(jiu)要(yao)考慮到很(hen)多別的(de)(de)(de)(de)(de)問題而不(bu)(bu)僅(jin)僅(jin)是基(ji)本功(gong)能的(de)(de)(de)(de)(de)實(shi)(shi)現。 推薦您看2.6.20中integrated的(de)(de)(de)(de)(de)一個驅動 kvm, 記得(de)是在driver/lguest下(xia),很(hen)好玩的(de)(de)(de)(de)(de), 就(jiu)是Linux下(xia)的(de)(de)(de)(de)(de)虛(xu)(xu)擬(ni)機(ji)驅動, 代碼不(bu)(bu)長,但(dan)功(gong)能強(qiang)大。有(you)(you)能力的(de)(de)(de)(de)(de)可以自己(ji)(ji)寫一操作系統按照要(yao)求做成磁盤(pan)鏡像加(jia)載到虛(xu)(xu)擬(ni)機(ji)中, 然后客戶機(ji)可以有(you)(you)自己(ji)(ji)的(de)(de)(de)(de)(de)4G虛(xu)(xu)擬(ni)地址(zhi)空(kong)間。

11. 看完(wan)驅動歡迎您進入Linux kernel學習(xi)中來。 簡單的方(fang)法,跟著ldd(Linux devive driver)做(zuo)一遍。

1、 Makefile 是如何編寫(xie)

eg:

# 這是上面(mian)那(nei)個程序的(de) Makefile 文件(jian)

main:main.o mytool1.o mytool2.o

gcc -o main main.o mytool1.o mytool2.o

main.o:main.c mytool1.h mytool2.h

gcc -c main.c

mytool1.o:mytool1.c mytool1.h

gcc -c mytool1.c

mytool2.o:mytool2.c mytool2.h

gcc -c mytool2.c

分析:

在(zai) Makefile 中也(ye)#開始的(de)行都是注(zhu)釋行.Makefile 中重要的(de)是描述文件的(de)依(yi)賴關(guan)系的(de)說

明.一般的格式是: Linux 操作系(xi)統 C 語言(yan)編程入門

target: components //表示的是(shi)依賴(lai)關系

TAB rule //規則

main:main.o mytool1.o mytool2.o 表(biao)示我們(men)的(de)(de)目標(target)main 的(de)(de)依賴(lai)對(dui)象(xiang)(components)是 main.o mytool1.o mytool2.o 當倚賴(lai)的(de)(de)對(dui)象(xiang)在目標修(xiu)改(gai)后修(xiu)改(gai)的(de)(de)話(hua),就要去執(zhi)行規(gui)則一行所指(zhi)定(ding)的(de)(de)命令.就象(xiang)我們(men)的(de)(de)上

面(mian)那個 Makefile 第3行(xing)所說的(de)一樣要執行(xing) gcc -o main main.o mytool1.o mytool2.o

(注意規則一(yi)行中的 TAB表示那里是一(yi)個 TAB 鍵)

Makefile 有(you)三個非(fei)常(chang)有(you)用(yong)的變(bian)量.分別是$@,$^,$<代表(biao)的意義分別是:

$@--目(mu)標文(wen)件(jian)(jian); $^--所有(you)的(de)依(yi)賴(lai)文(wen)件(jian)(jian); $<--第一(yi)個依(yi)賴(lai)文(wen)件(jian)(jian)。

1、 字符設備驅動(dong)

Linux字符(fu)(fu)設(she)備驅動的(de)關鍵數據(ju)結(jie)構(gou)cdev及(ji)file_operations結(jie)構(gou)體的(de)操作方法,并分析了Linux字符(fu)(fu)設(she)備的(de)整體結(jie)構(gou),給出了簡(jian)單的(de)設(she)計模(mo)板.

2.1、驅動結構

1) cdev結構(gou)體(ti)(cdev結構(gou)體(ti)描述字(zi)符設(she)備)

定義:

1 struct cdev {

3 struct kobject kobj; /* 內嵌的kobject對象 */

4 struct module *owner; /*所屬模塊(kuai)*/

5 struct file_operations *ops; /*文件操作(zuo)結構體*/

6 struct list_head list;

7 dev_t dev; /*設備號*/ 定義了(le)設備號

8 unsigned int count;

9 };

dev_t 成員定(ding)義了(le)設(she)備(bei)號,為 32 位(wei)(wei),其中高 12 位(wei)(wei)為主設(she)備(bei)號,低20位(wei)(wei)為次設(she)備(bei)號。使用下列(lie)宏可(ke)以從(cong)dev_t獲(huo)得(de)主設(she)備(bei)號和次設(she)備(bei)號:

MAJOR(dev_t dev) //主設備號(hao)

MINOR(dev_t dev) //次設備號

 而使(shi)用下(xia)列宏則可以通過主(zhu)設備號和設備號生(sheng)成 dev_t:

MKDEV(int major, int minor)

file_operations 定義(yi)了(le)字符設備(bei)驅動提供給虛擬文件系統(tong)的(de)接(jie)口函數

Linux 2.6內核(he)提供了(le)一組函數用于操作 cdev結(jie)構體(ti)

Void cdev_init(struct cdev *, struct file_operations *);

struct cdev *cdev_alloc(void);

void cdev_put(struct cdev *p);

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

void cdev_del(struct cdev *);

cdev_init()函數用于初始化 cdev 的成員,并建立 cdev 和 file_operations 之間的連接。
1            void cdev_init(struct cdev *cdev, struct file_operations *fops)
2            {
3                   memset(cdev, 0, sizeof *cdev);
4                   INIT_LIST_HEAD(&cdev->list);
5                   cdev->kobj.ktype = &ktype_cdev_default;
6                   kobject_init(&cdev->kobj);
7                   cdev->ops = fops;                     /*將傳入的文件操作結構體指針賦值給cdev的ops*/
8            }
       cdev_alloc()函數用于動態申請一個cdev內存
1            struct cdev *cdev_alloc(void)
2            {
3                   struct  cdev  *p=kmalloc(sizeof(struct  cdev),GFP_KERNEL);  /*分配cdev的內存*/
4                   if (p) {
5                         memset(p, 0, sizeof(struct cdev));
6                         p->kobj.ktype = &ktype_cdev_dynamic;
7                         INIT_LIST_HEAD(&p->list);
8                         kobject_init(&p->kobj);
9                   }
10         return p;
11      ;  &nbsp; }

cdev_add()函數(shu)(shu)(shu)(shu)和(he) cdev_del()函數(shu)(shu)(shu)(shu)分別向系統添加(jia)(jia)和(he)刪除一(yi)個(ge)cdev,完成(cheng)字(zi)符設(she)備的(de)注(zhu)冊(ce)和(he)注(zhu)銷。對(dui) cdev_add()的(de)調用(yong)通常(chang)(chang)發生(sheng)在字(zi)符設(she)備驅動模塊(kuai)加(jia)(jia)載函數(shu)(shu)(shu)(shu)中,而對(dui)cdev_del()函數(shu)(shu)(shu)(shu)的(de)調用(yong)則通常(chang)(chang)發生(sheng)在字(zi)符設(she)備驅動模塊(kuai)卸載函數(shu)(shu)(shu)(shu)中。

2) 分配和(he)釋放設(she)備號

在 調用 cdev_add() 函 數 向(xiang)系(xi)(xi)統(tong)注冊 字(zi)符 設(she)(she)備(bei)(bei) 之前 , 應首先調用register_chrdev_region()或(huo) alloc_chrdev_region()函數向(xiang)系(xi)(xi)統(tong)申(shen)(shen)請(qing)設(she)(she)備(bei)(bei)號(hao)。register_chrdev_region() 函 數 用 于 已(yi) 知(zhi) 起 始 設(she)(she) 備(bei)(bei)的(de) 設(she)(she)備(bei)(bei) 號(hao) 的(de) 情 況(kuang)(kuang); 而alloc_chrdev_region()用于設(she)(she)備(bei)(bei)號(hao)未知(zhi),向(xiang)系(xi)(xi)統(tong)動態(tai)申(shen)(shen)請(qing)未被(bei)占用的(de)設(she)(she)備(bei)(bei)號(hao)的(de)情況(kuang)(kuang),相反地 ,在 調用 cdev_del() 函 數 從(cong)系(xi)(xi) 統(tong) 注銷 字(zi)符設(she)(she)備(bei)(bei) 之 后(hou),unregister_chrdev_region()應該(gai)被(bei)調用以釋放(fang)原(yuan)先申(shen)(shen)請(qing)的(de)設(she)(she)備(bei)(bei)號(hao)。

3)file_operations結構體
1            struct file_operations
2            {
3                   struct module *owner; // 擁有該結構的模塊的指針,一般為THIS_MODULES
5                  loff_t(*llseek)(struct file *, loff_t, int); // 用來修改文件當前的讀寫位置 
7                  ssize_t(*read)(struct file *, char _  _user *, size_t, loff_t*); // 從設備中同步讀取數據
9                  ssize_t(*aio_read)(struct  kiocb  *,  char  _  _user  *,  size_t,  loff_t); // 初始化一個異步的讀取操作
11                ssize_t(*write)(struct  file  *,  const  char  _  _user  *,  size_t, loff_t*); // 向設備發送數據
13                 ssize_t(*aio_write)(struct kiocb *, const char _  _user *, size_t, loff_t); // 初始化一個異步的寫入操作
15                int(*readdir)(struct file *, void *, filldir_t); // 僅用于讀取目錄,對于設備文件,該字段為 NULL
17                 unsigned int(*poll)(struct file *, struct poll_table_struct*);  // 輪詢函數,判斷目前是否可以進行非阻塞的讀取或寫入
19                 int(*ioctl)(struct  inode  *, struct  file *, unsigned  int, unsigned long); // 執行設備I/O控制命令
21                 long(*unlocked_ioctl)(struct  file  *,  unsigned  int,  unsigned  long); // 不使用BLK文件系統,將使用此種函數指針代替ioctl
23                 long(*compat_ioctl)(struct file *, unsigned int, unsigned long); // 在64位系統上,32位的ioctl調用將使用此函數指針代替
25                 int(*mmap)(struct file *, struct vm_area_struct*); // 用于請求將設備內存映射到進程地址空間
27                 int(*open)(struct inode *, struct file*); // 打開
29                 int(*flush)(struct file*);
30                 int(*release)(struct inode *, struct file*); / 關閉
32                 int(*synch)(struct file *, struct dentry *, int datasync); // 刷新待處理的數據
34                 int(*aio_fsync)(struct kiocb *, int datasync); // 異步fsync
36                 int(*fasync)(int, struct file *, int); // 通知設備FASYNC標志發生變化
38                 int(*lock)(struct file *, int, struct file_lock*);
39                 ssize_t(*readv)(struct  file  *,  const  struct  iovec  *,  unsigned  long, loff_t*);
40                 ssize_t(*writev)(struct  file  *,  const  struct  iovec  *,  unsigned  long, loff_t*);  // readv和writev:分散/聚集型的讀寫操作
42                 ssize_t(*sendfile)(struct  file  *,  loff_t  *,  size_t,  read_actor_t, void*); // 通常為NULL
44                 ssize_t(*sendpage)(struct file *, struct page *, int, size_t, loff_t *, int); // 通常為NULL
46                 unsigned long(*get_unmapped_area)(struct file *,unsigned long, unsigned long, unsigned long, unsigned long); // 在進程地址空間找到一個將底層設備中的內存段映射的位置
49                 int(*check_flags)(int); // 允許模塊檢查傳遞給fcntl(F_SETEL...)調用的標志
51                 int(*dir_notify)(struct file *filp, unsigned long arg); // 僅對文件系統有效,驅動程序不必實現
53                 int(*flock)(struct file *, int, struct file_lock*); 
54    ;      };

llseek()函數(shu)用(yong)來修改一個(ge)(ge)文件的當前讀寫位置,并將(jiang)新(xin)位置返(fan)回,在出錯時,這個(ge)(ge)函數(shu)返(fan)回一個(ge)(ge)負值

read()函數用(yong)來從設備中(zhong)讀取數據,成功時(shi)函數返(fan)回(hui)讀取的字節(jie)數,出錯時(shi)返(fan)回(hui)一個負值。

write()函數(shu)向設備發(fa)送數(shu)據(ju),成(cheng)功時該函數(shu)返回寫入的字節數(shu)。如果此函數(shu)未(wei)被實現,當用戶進行write()系統(tong)調用時,將得到-EINVAL返回值。

readdir()函數(shu)僅用于(yu)目錄,設備(bei)節點不(bu)需要實現它(ta)。

ioctl()提供(gong)設(she)備相關控(kong)制命(ming)令的(de)實現 (既不是(shi)讀操(cao)作也不是(shi)寫操(cao)作) , 當(dang)調用(yong)成(cheng)功時,返(fan)回給(gei)調用(yong)程序(xu)一(yi)個非負值。內核本身識別(bie)部分控(kong)制命(ming)令,而不必調用(yong)設(she)備驅(qu)動中的(de)

ioctl()。如果(guo)設備不(bu)提供ioctl()函(han)數,對于內核不(bu)能識別(bie)的(de)命令,用(yong)戶進行ioctl()系(xi)統調(diao)用(yong)時將獲得-EINVAL返回值。

mmap()函(han)數(shu)(shu)將設(she)備內(nei)存映射到進程(cheng)內(nei)存中(zhong),如果設(she)備驅動未實現(xian)此函(han)數(shu)(shu),用戶進行 mmap()系(xi)統調用時將獲得-ENODEV返回值(zhi)。 這個函(han)數(shu)(shu)對于(yu)幀緩沖等(deng)設(she)備特(te)別有(you)意義(yi)。

3)字符設備驅(qu)動的組成(cheng)

A、字(zi)符設備驅動模(mo)塊(kuai)加載與卸載函數

字符設備驅動模塊加載函數中應該實現設備號的申請和cdev的注冊, 而在卸載函數中應實現設備號的釋放和 cdev的注銷常見的設備結構體、模塊加載和卸載函數形式如代碼清單:
1     //設備結構體
2            struct xxx_dev_t
3            {
4                  struct cdev cdev;
5                  ...
6            } xxx_dev;
7     //設備驅動模塊加載函數
8            static int _  _init xxx_init(void)
9            {
10                 ...
11                 cdev_init(&xxx_dev.cdev, &xxx_fops); //初始化cdev
12                 xxx_dev.cdev.owner = THIS_MODULE; //獲取字符設備號
14                 if (xxx_major)
15                 {
16                       register_chrdev_region(xxx_dev_no, 1, DEV_NAME);
17                 }
18                 else
19                 {
20                       alloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME);
21                 }
22   
23                 ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1); //注冊設備
24                 ...
25          }
26 //設備驅動模塊卸載函數
27          static void _  _exit xxx_exit(void)
28          {
29                 unregister_chrdev_region(xxx_dev_no, 1); //釋放占用的設備號
30                 cdev_del(&xxx_dev.cdev); //注銷設備
31                 ...
 32          }

B、字符設(she)備驅動的file_operations 結構(gou)體中成員(yuan)函數(shu)

file_operations 結構體中成員函數是字符設備驅動與內核的接口,是用戶空間對Linux進行系統調用終的落實者。 大多數字符設備驅動會實現read()、 write()和 ioctl()函數,常見的字符設備驅動的這3個函數的形式如代碼清單
1   /* 讀設備*/
2            ssize_t  xxx_read(struct  file  *filp,  char  _  _user  *buf,  size_t  count,  loff_t*f_pos)
4            {
5                  ...
6                  copy_to_user(buf, ..., ...);
7                  ...
8         &nbsp;  } 

設備驅動的讀函數中,filp是文件結構體指針,buf是用戶空間內存的地址,該地址在內核空間不能直接讀寫,count是要讀的字節數,f_pos是讀的位置相對于文件開頭的偏移。
9   /* 寫設備*/
10         ssize_t  xxx_write(struct  file  *filp,  const  char  _  _user  *buf,  size_t  count, loff_t *f_pos)
12         {
13                 ...
14                 copy_from_user(..., buf, ...);
15                 ...
16     &nbsp;   } 

設備驅動的寫函數中,filp是文件結構體指針,buf是用戶空間內存的地址,該地址在內核空間不能直接讀寫,count是要寫的字節數,f_pos是寫的位置相對于文件開頭的偏移
17  /* ioctl函數 */
18         int  xxx_ioctl(struct  inode  *inode,  struct  file  *filp,  unsigned  int cmd,
unsigned long arg)
20         {
21                 ...
22                 switch (cmd)
23                 {
24                       case XXX_CMD1:
25               ...
26               break;
27                       case XXX_CMD2:
28               ...
29               break;
30                       default: /* 不能支持的命令 */
32               return  - ENOTTY;
33                 }
34                 return 0;
35   &nbsp;     }

I/O 控(kong)制函(han)數的cmd參數為事先定義的I/O 控(kong)制命令, 而 arg為對應(ying)于(yu)(yu)該命令的參數。例(li)如(ru)(ru)對于(yu)(yu)串(chuan)行設備,如(ru)(ru)果(guo)SET_BAUDRATE 是一個設置波特(te)率的命令,那后(hou)面的arg就應(ying)該是波特(te)率值。

 讀和寫(xie)函(han)數中的_ _user 是(shi)一個宏,表明其后的指(zhi)針指(zhi)向用(yong)戶空(kong)間

在字符設備驅動中,需要定義一個 file_operations 的實例,并將具體設備驅動的函數賦值給file_operations的成員,如代碼清單:
1            struct file_operations xxx_fops =
2            {
3                   .owner = THIS_MODULE,
4                   .read = xxx_read,
5                   .write = xxx_write,
6                   .ioctl = xxx_ioctl,
7                   ...
8       &nbsp;    };

上一篇:stm32的PWM實現過程

下一篇:GDB調試入門(一)

熱(re)點文章推薦
華清(qing)學員就業榜單
高薪學員(yuan)經驗分享
熱點(dian)新聞推薦
前臺專(zhuan)線:010-82525158 企(qi)業培訓(xun)洽談專線(xian):010-82525379 院校合作(zuo)洽談(tan)專線:010-82525379 Copyright © 2004-2022 北京華清遠見科技集團有限公司 版權所有 ,,京公海網安備11010802025203號

回到頂部