色yeye在线视频观看_亚洲人亚洲精品成人网站_一级毛片免费播放_91精品一区二区中文字幕_一区二区三区日本视频_成人性生交大免费看

當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > Linux底層驅(qū)動開發(fā)需要學(xué)習(xí)哪些內(nèi)容

Linux底層驅(qū)動開發(fā)需要學(xué)習(xí)哪些內(nèi)容 時(shí)間:2018-01-09      來源:未知

Linux底層驅(qū)動開發(fā)需要學(xué)習(xí)哪些內(nèi)容想必這是很多學(xué)習(xí)Linux的朋友十分頭疼的問題,今天就讓我來告訴大家我們到底該學(xué)習(xí)哪些內(nèi)容呢?

1. 要會一些硬件知識,比如Arm接口編程

2. 學(xué)會寫簡單的makefile

3. 編一應(yīng)用程序,可以用makefile跑起來

4. 學(xué)會寫驅(qū)動的makefile

5. 寫一簡單char驅(qū)動,makefile編譯通過,可以insmod, lsmod, rmmod. 在驅(qū)動的init函數(shù)里打印hello world, insmod后應(yīng)該能夠通過dmesg看到輸出。

6. 寫一完整驅(qū)動, 加上read, write, ioctl, polling等各種函數(shù)的驅(qū)動實(shí)現(xiàn)。 在ioctl里完成從用戶空間向內(nèi)核空間傳遞結(jié)構(gòu)體的實(shí)現(xiàn)。

7. 寫一block驅(qū)動, 加上read,write,ioctl,poll等各種函數(shù)實(shí)現(xiàn)。

8. 簡單學(xué)習(xí)下內(nèi)存管理, 這個(gè)是難的,明白各種memory alloc的函數(shù)實(shí)現(xiàn)細(xì)節(jié)。這是Linux開發(fā)的基本功。

9. 學(xué)習(xí)鎖機(jī)制的應(yīng)用,這個(gè)不是難的但是容易犯錯(cuò)的,涉及到很多同步和并發(fā)的問題。

10. 看內(nèi)核中實(shí)際應(yīng)用的驅(qū)動代碼。 你會發(fā)現(xiàn)基本的你已經(jīng)知道了, 大的框架都是一樣的, 無非是read, write, ioctl等函數(shù)的實(shí)現(xiàn), 但里面包含了很多很多細(xì)小的實(shí)現(xiàn)細(xì)節(jié)是之前不知道的。 這時(shí)候就要考慮到很多別的問題而不僅僅是基本功能的實(shí)現(xiàn)。 推薦您看2.6.20中integrated的一個(gè)驅(qū)動 kvm, 記得是在driver/lguest下,很好玩的, 就是Linux下的虛擬機(jī)驅(qū)動, 代碼不長,但功能強(qiáng)大。有能力的可以自己寫一操作系統(tǒng)按照要求做成磁盤鏡像加載到虛擬機(jī)中, 然后客戶機(jī)可以有自己的4G虛擬地址空間。

11. 看完驅(qū)動歡迎您進(jìn)入Linux kernel學(xué)習(xí)中來。 簡單的方法,跟著ldd(Linux devive driver)做一遍。

1、 Makefile 是如何編寫

eg:

# 這是上面那個(gè)程序的 Makefile 文件

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

分析:

在 Makefile 中也#開始的行都是注釋行.Makefile 中重要的是描述文件的依賴關(guān)系的說

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

target: components //表示的是依賴關(guān)系

TAB rule //規(guī)則

main:main.o mytool1.o mytool2.o 表示我們的目標(biāo)(target)main 的依賴對象(components)是 main.o mytool1.o mytool2.o 當(dāng)倚賴的對象在目標(biāo)修改后修改的話,就要去執(zhí)行規(guī)則一行所指定的命令.就象我們的上

面那個(gè) Makefile 第3行所說的一樣要執(zhí)行 gcc -o main main.o mytool1.o mytool2.o

(注意規(guī)則一行中的 TAB表示那里是一個(gè) TAB 鍵)

Makefile 有三個(gè)非常有用的變量.分別是$@,$^,$<代表的意義分別是:

$@--目標(biāo)文件; $^--所有的依賴文件; $<--第一個(gè)依賴文件。

1、 字符設(shè)備驅(qū)動

Linux字符設(shè)備驅(qū)動的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)cdev及file_operations結(jié)構(gòu)體的操作方法,并分析了Linux字符設(shè)備的整體結(jié)構(gòu),給出了簡單的設(shè)計(jì)模板.

2.1、驅(qū)動結(jié)構(gòu)

1) cdev結(jié)構(gòu)體(cdev結(jié)構(gòu)體描述字符設(shè)備)

定義:

1 struct cdev {

3 struct kobject kobj; /* 內(nèi)嵌的kobject對象 */

4 struct module *owner; /*所屬模塊*/

5 struct file_operations *ops; /*文件操作結(jié)構(gòu)體*/

6 struct list_head list;

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

8 unsigned int count;

9 };

dev_t 成員定義了設(shè)備號,為 32 位,其中高 12 位為主設(shè)備號,低20位為次設(shè)備號。使用下列宏可以從dev_t獲得主設(shè)備號和次設(shè)備號:

MAJOR(dev_t dev) //主設(shè)備號

MINOR(dev_t dev) //次設(shè)備號

而使用下列宏則可以通過主設(shè)備號和設(shè)備號生成 dev_t:

MKDEV(int major, int minor)

file_operations 定義了字符設(shè)備驅(qū)動提供給虛擬文件系統(tǒng)的接口函數(shù)

Linux 2.6內(nèi)核提供了一組函數(shù)用于操作 cdev結(jié)構(gòu)體

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()函數(shù)用于初始化 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;                     /*將傳入的文件操作結(jié)構(gòu)體指針賦值給cdev的ops*/
8            }
       cdev_alloc()函數(shù)用于動態(tài)申請一個(gè)cdev內(nèi)存
1            struct cdev *cdev_alloc(void)
2            {
3                   struct  cdev  *p=kmalloc(sizeof(struct  cdev),GFP_KERNEL);  /*分配cdev的內(nèi)存*/
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          }

cdev_add()函數(shù)和 cdev_del()函數(shù)分別向系統(tǒng)添加和刪除一個(gè)cdev,完成字符設(shè)備的注冊和注銷。對 cdev_add()的調(diào)用通常發(fā)生在字符設(shè)備驅(qū)動模塊加載函數(shù)中,而對cdev_del()函數(shù)的調(diào)用則通常發(fā)生在字符設(shè)備驅(qū)動模塊卸載函數(shù)中。

2) 分配和釋放設(shè)備號

在 調(diào)用 cdev_add() 函 數(shù) 向系統(tǒng)注冊 字符 設(shè)備 之前 , 應(yīng)首先調(diào)用register_chrdev_region()或 alloc_chrdev_region()函數(shù)向系統(tǒng)申請?jiān)O(shè)備號。register_chrdev_region() 函 數(shù) 用 于 已 知 起 始 設(shè) 備的 設(shè)備 號 的 情 況; 而alloc_chrdev_region()用于設(shè)備號未知,向系統(tǒng)動態(tài)申請未被占用的設(shè)備號的情況,相反地 ,在 調(diào)用 cdev_del() 函 數(shù) 從系 統(tǒng) 注銷 字符設(shè)備 之 后,unregister_chrdev_region()應(yīng)該被調(diào)用以釋放原先申請的設(shè)備號。

3)file_operations結(jié)構(gòu)體
1            struct file_operations
2            {
3                   struct module *owner; // 擁有該結(jié)構(gòu)的模塊的指針,一般為THIS_MODULES
5                  loff_t(*llseek)(struct file *, loff_t, int); // 用來修改文件當(dāng)前的讀寫位置 
7                  ssize_t(*read)(struct file *, char _  _user *, size_t, loff_t*); // 從設(shè)備中同步讀取數(shù)據(jù)
9                  ssize_t(*aio_read)(struct  kiocb  *,  char  _  _user  *,  size_t,  loff_t); // 初始化一個(gè)異步的讀取操作
11                ssize_t(*write)(struct  file  *,  const  char  _  _user  *,  size_t, loff_t*); // 向設(shè)備發(fā)送數(shù)據(jù)
13                 ssize_t(*aio_write)(struct kiocb *, const char _  _user *, size_t, loff_t); // 初始化一個(gè)異步的寫入操作
15                int(*readdir)(struct file *, void *, filldir_t); // 僅用于讀取目錄,對于設(shè)備文件,該字段為 NULL
17                 unsigned int(*poll)(struct file *, struct poll_table_struct*);  // 輪詢函數(shù),判斷目前是否可以進(jìn)行非阻塞的讀取或?qū)懭?br style="padding: 0px; margin: 0px; list-style-type: none;" /> 19                 int(*ioctl)(struct  inode  *, struct  file *, unsigned  int, unsigned long); // 執(zhí)行設(shè)備I/O控制命令
21                 long(*unlocked_ioctl)(struct  file  *,  unsigned  int,  unsigned  long); // 不使用BLK文件系統(tǒng),將使用此種函數(shù)指針代替ioctl
23                 long(*compat_ioctl)(struct file *, unsigned int, unsigned long); // 在64位系統(tǒng)上,32位的ioctl調(diào)用將使用此函數(shù)指針代替
25                 int(*mmap)(struct file *, struct vm_area_struct*); // 用于請求將設(shè)備內(nèi)存映射到進(jìn)程地址空間
27                 int(*open)(struct inode *, struct file*); // 打開
29                 int(*flush)(struct file*);
30                 int(*release)(struct inode *, struct file*); / 關(guān)閉
32                 int(*synch)(struct file *, struct dentry *, int datasync); // 刷新待處理的數(shù)據(jù)
34                 int(*aio_fsync)(struct kiocb *, int datasync); // 異步fsync
36                 int(*fasync)(int, struct file *, int); // 通知設(shè)備FASYNC標(biāo)志發(fā)生變化
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); // 在進(jìn)程地址空間找到一個(gè)將底層設(shè)備中的內(nèi)存段映射的位置
49                 int(*check_flags)(int); // 允許模塊檢查傳遞給fcntl(F_SETEL...)調(diào)用的標(biāo)志
51                 int(*dir_notify)(struct file *filp, unsigned long arg); // 僅對文件系統(tǒng)有效,驅(qū)動程序不必實(shí)現(xiàn)
53                 int(*flock)(struct file *, int, struct file_lock*); 
54          };

llseek()函數(shù)用來修改一個(gè)文件的當(dāng)前讀寫位置,并將新位置返回,在出錯(cuò)時(shí),這個(gè)函數(shù)返回一個(gè)負(fù)值

read()函數(shù)用來從設(shè)備中讀取數(shù)據(jù),成功時(shí)函數(shù)返回讀取的字節(jié)數(shù),出錯(cuò)時(shí)返回一個(gè)負(fù)值。

write()函數(shù)向設(shè)備發(fā)送數(shù)據(jù),成功時(shí)該函數(shù)返回寫入的字節(jié)數(shù)。如果此函數(shù)未被實(shí)現(xiàn),當(dāng)用戶進(jìn)行write()系統(tǒng)調(diào)用時(shí),將得到-EINVAL返回值。

readdir()函數(shù)僅用于目錄,設(shè)備節(jié)點(diǎn)不需要實(shí)現(xiàn)它。

ioctl()提供設(shè)備相關(guān)控制命令的實(shí)現(xiàn) (既不是讀操作也不是寫操作) , 當(dāng)調(diào)用成功時(shí),返回給調(diào)用程序一個(gè)非負(fù)值。內(nèi)核本身識別部分控制命令,而不必調(diào)用設(shè)備驅(qū)動中的

ioctl()。如果設(shè)備不提供ioctl()函數(shù),對于內(nèi)核不能識別的命令,用戶進(jìn)行ioctl()系統(tǒng)調(diào)用時(shí)將獲得-EINVAL返回值。

mmap()函數(shù)將設(shè)備內(nèi)存映射到進(jìn)程內(nèi)存中,如果設(shè)備驅(qū)動未實(shí)現(xiàn)此函數(shù),用戶進(jìn)行 mmap()系統(tǒng)調(diào)用時(shí)將獲得-ENODEV返回值。 這個(gè)函數(shù)對于幀緩沖等設(shè)備特別有意義。

3)字符設(shè)備驅(qū)動的組成

A、字符設(shè)備驅(qū)動模塊加載與卸載函數(shù)

字符設(shè)備驅(qū)動模塊加載函數(shù)中應(yīng)該實(shí)現(xiàn)設(shè)備號的申請和cdev的注冊, 而在卸載函數(shù)中應(yīng)實(shí)現(xiàn)設(shè)備號的釋放和 cdev的注銷常見的設(shè)備結(jié)構(gòu)體、模塊加載和卸載函數(shù)形式如代碼清單:
1     //設(shè)備結(jié)構(gòu)體
2            struct xxx_dev_t
3            {
4                  struct cdev cdev;
5                  ...
6            } xxx_dev;
7     //設(shè)備驅(qū)動模塊加載函數(shù)
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; //獲取字符設(shè)備號
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); //注冊設(shè)備
24                 ...
25          }
26 //設(shè)備驅(qū)動模塊卸載函數(shù)
27          static void _  _exit xxx_exit(void)
28          {
29                 unregister_chrdev_region(xxx_dev_no, 1); //釋放占用的設(shè)備號
30                 cdev_del(&xxx_dev.cdev); //注銷設(shè)備
31                 ...
32          }

B、字符設(shè)備驅(qū)動的file_operations 結(jié)構(gòu)體中成員函數(shù)

file_operations 結(jié)構(gòu)體中成員函數(shù)是字符設(shè)備驅(qū)動與內(nèi)核的接口,是用戶空間對Linux進(jìn)行系統(tǒng)調(diào)用終的落實(shí)者。 大多數(shù)字符設(shè)備驅(qū)動會實(shí)現(xiàn)read()、 write()和 ioctl()函數(shù),常見的字符設(shè)備驅(qū)動的這3個(gè)函數(shù)的形式如代碼清單
1   /* 讀設(shè)備*/
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            } 

設(shè)備驅(qū)動的讀函數(shù)中,filp是文件結(jié)構(gòu)體指針,buf是用戶空間內(nèi)存的地址,該地址在內(nèi)核空間不能直接讀寫,count是要讀的字節(jié)數(shù),f_pos是讀的位置相對于文件開頭的偏移。
9   /* 寫設(shè)備*/
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         } 

設(shè)備驅(qū)動的寫函數(shù)中,filp是文件結(jié)構(gòu)體指針,buf是用戶空間內(nèi)存的地址,該地址在內(nèi)核空間不能直接讀寫,count是要寫的字節(jié)數(shù),f_pos是寫的位置相對于文件開頭的偏移
17  /* ioctl函數(shù) */
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         }

I/O 控制函數(shù)的cmd參數(shù)為事先定義的I/O 控制命令, 而 arg為對應(yīng)于該命令的參數(shù)。例如對于串行設(shè)備,如果SET_BAUDRATE 是一個(gè)設(shè)置波特率的命令,那后面的arg就應(yīng)該是波特率值。

讀和寫函數(shù)中的_ _user 是一個(gè)宏,表明其后的指針指向用戶空間

在字符設(shè)備驅(qū)動中,需要定義一個(gè) file_operations 的實(shí)例,并將具體設(shè)備驅(qū)動的函數(shù)賦值給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            };

上一篇:stm32的PWM實(shí)現(xiàn)過程

下一篇:GDB調(diào)試入門(一)

华清图书馆

0元电子书,限时免费申领

10本华清图书PDF版

扫码关注华清远见公众号
自动回复“2”,即可申领!
熱點(diǎn)文章推薦
華清學(xué)員就業(yè)榜單
高薪學(xué)員經(jīng)驗(yàn)分享
熱點(diǎn)新聞推薦
前臺專線:010-82525158 企業(yè)培訓(xùn)洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠(yuǎn)見科技集團(tuán)有限公司 版權(quán)所有 ,京ICP備16055225號-5京公海網(wǎng)安備11010802025203號

回到頂部

主站蜘蛛池模板: 久久深夜视频 | 日本a级片视频 | wwww.xxxx免费 | 中国裸体BBBBXXXX | 公妇仑乱在线观看 | 日韩欧无码一区二区三区免费不卡 | 手机看黄AV免费网址 | 国产亚洲日本精品 | 欧美 日韩 综合 | 影院一区 | 大尺度吃奶摸下激烈视频 | 女人被狂躁高潮啊的视频在线看 | 少妇与大狼拘作爱性a | 48久久国产精品性色aⅴ人妻 | 脱美女内衣视频网站 | 三级三级久久三级久久 | 国产杨幂丝袜AV在线播放 | 精品熟女少妇av久久免费 | 欧美精品影院 | 热热色国产 | 在线观看免费日本 | 酒店大战丝袜高跟鞋人妻 | 蜜桃久久久久久 | 国产午夜AAA片无码无片久久 | AAA女人18毛片水真多 | 女人高潮叫床污话 | 中文字幕一二三综合a | 五月丁香激激情亚洲综合 | 日韩AV一区二区三区免费看 | 清纯小雨被调教成YIN娃 | 熟妇人妻系列AV无码一区二区 | 18禁男女污污污午夜网站免费 | 欧美国产成人精品一区二区三区 | 99国产揄拍国产精品人妻 | 168黄色网 | 亚洲综合另类小说专区 | 大陆精大陆国产国语精品 | 一区二区成人在线观看 | 影音先锋男人在线资源资源网 | 人妻少妇精品视中文字幕国语 | 69麻豆天美精东蜜桃传媒潘甜甜 |