第二部分Linux設(shè)備驅(qū)動程序_第1頁
第二部分Linux設(shè)備驅(qū)動程序_第2頁
第二部分Linux設(shè)備驅(qū)動程序_第3頁
第二部分Linux設(shè)備驅(qū)動程序_第4頁
第二部分Linux設(shè)備驅(qū)動程序_第5頁
已閱讀5頁,還剩81頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、第二部分 Linux設(shè)備驅(qū)動程序1第一章 設(shè)備驅(qū)動簡介2設(shè)備驅(qū)動程序的角色是內(nèi)核的一部分,屬于內(nèi)核中的設(shè)備管理子系統(tǒng)是應(yīng)用程序和實際設(shè)備間的軟件層提供對硬件的基本操作,如open,read,write,ioctl,close等只提供硬件操作機制,如何使用硬件(操作策略)應(yīng)由應(yīng)用決定,驅(qū)動不應(yīng)該包含策略驅(qū)動程序既可以直接編譯到內(nèi)核中(zImage),或者編譯為可動態(tài)加載的模塊(.ko文件,用insmod程序加載)3Linux設(shè)備的分類字符( char ) 設(shè)備-是一種可以按字節(jié)流來存取的設(shè)備-實現(xiàn) open, close, read, 和 write等系統(tǒng)調(diào)用-文本控制臺( /dev/conso

2、le )和串口( /dev/ttyS0)、內(nèi)存、Flash等塊(block)設(shè)備-按整塊數(shù)據(jù)存取(如512字節(jié))-如磁盤設(shè)備(/dev/hda)-可以帶有文件系統(tǒng)網(wǎng)絡(luò)設(shè)備-負(fù)責(zé)網(wǎng)絡(luò)數(shù)據(jù)包的發(fā)送和接收,如eth04第二章 內(nèi)核模塊基礎(chǔ)5模塊代碼結(jié)構(gòu)hello world模塊實例分析hello.c6初始化和退出函數(shù)初始化函數(shù)module_init()-由insmod調(diào)用-注冊設(shè)備,請求資源等退出函數(shù)module_exit()-由rmmod調(diào)用-取消設(shè)備注冊、釋放資源等初始化中的錯誤處理(goto的使用)int _init my_init_function(void) int err; /* reg

3、istration takes a pointer and a name */ err = register_this(ptr1, skull); if (err) goto fail_this; err = register_that(ptr2, skull); if (err) goto fail_that; err = register_those(ptr3, skull); if (err) goto fail_those; return 0; /* success */fail_those: unregister_that(ptr2, skull);fail_that: unregi

4、ster_this(ptr1, skull);fail_this: return err; /* propagate the error */7模塊的編譯和加載模塊編譯Makefile分析Makefile8模塊加載參數(shù)參數(shù)的值可由 insmod 或者 modprobe 在加載時指定參數(shù)類型可以是bool,charp,int等聲明方式module_param()如static char *whom = world;static int howmany = 1;module_param(howmany, int, S_IRUGO);module_param(whom, charp, S_IRUGO

5、);hellop.c9課后練習(xí)輸入hello world模塊例子代碼,編譯并加載模塊給hello world模塊增加參數(shù),重新編譯并加載10第三章 字符設(shè)備驅(qū)動程序11設(shè)備文件和設(shè)備號Linux上的設(shè)備操作都是通過設(shè)備文件進行如crw-rw-rw- 1 root tty 4, 64 Apr 11 2002 /dev/ttyS0 c表示字符設(shè)備,b表示塊設(shè)備主設(shè)備號標(biāo)識設(shè)備相連的驅(qū)動,次設(shè)備號決定引用哪個設(shè)備12設(shè)備號的分配和釋放靜態(tài)分配int register_chrdev_region(dev_t first, unsigned int count, char *name);-first :

6、起始設(shè)備編號(通常為0)-count:請求的設(shè)備編號個數(shù)-name:設(shè)備名動態(tài)分配int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);-dev:內(nèi)核分配的主次設(shè)備號釋放設(shè)備號void unregister_chrdev_region(dev_t first, unsigned int count); 注意:一定要檢查返回值,確保分配成功!13關(guān)鍵數(shù)據(jù)結(jié)構(gòu)include/linux/fs.hstruct (定義設(shè)備操作方法)struct struct module

7、 *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char _user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, char _user *, size_t, loff_t);ssize_t (*write) (struct file *, const char _user *, size_t, loff_t *);。int (*ioctl) (struct inode *, struct file *

8、, unsigned int, unsigned long);。int (*open) (struct inode *, struct file *);int (*flush) (struct file *);int (*release) (struct inode *, struct file *);struct file(對應(yīng) 每個打開的文件,在open時創(chuàng)建)struct inode(內(nèi)核內(nèi)部表示文件的結(jié)構(gòu))14字符設(shè)備初始化和注冊(1)字符設(shè)備用cdev結(jié)構(gòu)表示cdev結(jié)構(gòu)的初始化struct cdev *my_cdev = cdev_alloc();my_cdev-ops = &my

9、_fops;或者void cdev_init(struct cdev *cdev, struct *fops);15字符設(shè)備初始化和注冊(2)設(shè)備注冊int cdev_add(struct cdev *dev, dev_t num, unsigned int count);-dev:cdev結(jié)構(gòu)-num:設(shè)備編號-count:設(shè)備數(shù)(通常是1)設(shè)備注銷void cdev_del(struct cdev *dev);16設(shè)備的方法(1)open方法(打開設(shè)備)-初始化設(shè)備、分配資源等int (*open)(struct inode *inode, struct file *filp);relea

10、se方法(釋放設(shè)備)-釋放資源、關(guān)閉設(shè)備等-并不是在應(yīng)用程序每次調(diào)用close時都會調(diào)用release17設(shè)備的方法(2)read方法(從設(shè)備讀取數(shù)據(jù))ssize_t read(struct file *filp, char _user *buff, size_t count, loff_t *offp);count:請求傳輸?shù)臄?shù)據(jù)大小buff:緩沖區(qū)offp:正在存取的文件位置返回值:等于count,完整讀取 大于0但小于count,部分傳輸 等于0,已到達文件尾 小于0,出錯write方法(往設(shè)備寫入數(shù)據(jù))ssize_t write(struct file *filp, const cha

11、r _user *buff, size_t count, loff_t *offp);返回值:等于count,完整寫入 大于0但小于count,部分寫入 等于0,沒有寫入 小于0,出錯18設(shè)備的方法(3)用戶空間和內(nèi)核空間的數(shù)據(jù)傳送unsigned long copy_to_user(void _user *to,const void *from,unsigned long count); unsigned long copy_from_user(void *to,const void _user *from,unsigned long count); 注意:需要檢查返回值19設(shè)備的方法(4)

12、llseek方法(用于設(shè)備定位)-有些設(shè)備不能定位,如串口等字節(jié)流設(shè)備-調(diào)用read、write時會更新文件當(dāng)前位置指針-如果設(shè)備不支持llseek,需要調(diào)用以下函數(shù)打開設(shè)備:int nonseekable_open(struct inode *inode; struct file *filp); 同時 結(jié)構(gòu)中設(shè)置 llseek 方法為 no_llseek20設(shè)備的方法(5)ioctl方法(用于其他的設(shè)備控制操作,如獲取參數(shù)、改變設(shè)置、硬件控制等)int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, un

13、signed long arg);-cmd:命令參數(shù)-arg:指針或者數(shù)值ioctl命令-系統(tǒng)范圍內(nèi)唯一-Documentation/ioctl-number.txt(內(nèi)核使用的ioctl幻數(shù))-由4個字段組成type-幻數(shù)number-序號direction-數(shù)據(jù)傳送方向size-數(shù)據(jù)大小21設(shè)備的方法(6)定義ioctl命令的宏_IO(type,nr)(沒有參數(shù)的命令)_IOR(type, nr, datatype)(讀數(shù)據(jù))_IOW(type,nr,datatype)(寫數(shù)據(jù)) _IOWR(type,nr,datatype)(讀寫)返回值:對于無效的命令,通常返回-EINVAL命令參數(shù)傳

14、遞:put_user(datum, ptr)-返回datum變量的值給應(yīng)用程序get_user(local, ptr)-從應(yīng)用程序獲取參數(shù)值保存在local變量中22設(shè)備的方法(7)scull的ioctl命令 分析main.c應(yīng)用程序的調(diào)用方法(數(shù)值或指針方式):int quantum;ioctl(fd,SCULL_IOCSQUANTUM, &quantum); ioctl(fd,SCULL_IOCTQUANTUM, quantum); ioctl(fd,SCULL_IOCGQUANTUM, &quantum); quantum = ioctl(fd,SCULL_IOCQQUANTUM); 2

15、3實例分析scull設(shè)備驅(qū)動代碼分析main.c24課后練習(xí)輸入scull驅(qū)動代碼,編譯并加載,使用cp、dd、cat等命令對scull設(shè)備進行讀寫操作25第四章 內(nèi)核時間和定時器26內(nèi)核時間單位jiffies-時鐘滴答計數(shù)器-兩個jiffies的間隔一般為10ms(1/HZ,HZ=100,即1秒產(chǎn)生的時鐘滴答數(shù))-volatile類型,如unsigned long j, stamp_1, stamp_half, stamp_n;j = jiffies; (當(dāng)前時間)stamp_1 = j + HZ;(1秒)stamp_half = j + HZ/2;(半秒)stamp_n = j + n *

16、 HZ / 1000; (n毫秒)27延時函數(shù)(1)忙等待while (time_before(jiffies, j1) cpu_relax();-浪費CPU資源,降低性能釋放CPUwhile (time_before(jiffies, j1) schedule();-延時不準(zhǔn)確,可能大于預(yù)期的值28延時函數(shù)(2)超時set_current_state(TASK_INTERRUPTIBLE);schedule_timeout (delay);-jiffies為單位短延時(忙等待)void ndelay(unsigned long nsecs);-納秒void udelay(unsigned l

17、ong usecs);-微秒void mdelay(unsigned long msecs);-毫秒jit模塊代碼分析29內(nèi)核定時器(1)調(diào)度一個函數(shù)在將來一個特定的時間執(zhí)行,如查詢設(shè)備、關(guān)閉硬件等定時器函數(shù)是異步執(zhí)行的,屬于軟中斷類型定時器函數(shù)的一些限制-不允許存取用戶空間-不能存取 current 指針-不能進行睡眠或者調(diào)度. 不能調(diào)用 schedule 或者某種 wait_event, 也不能調(diào)用任何其他可能睡眠的函數(shù). 例如kmalloc定時器函數(shù)執(zhí)行后可以再次注冊30內(nèi)核定時器(2)定時器API:#include struct timer_list /* . */ unsigned

18、long expires; void (*function)(unsigned long); unsigned long data;void init_timer(struct timer_list *timer);struct timer_list TIMER_INITIALIZER(_function, _expires, _data);void add_timer(struct timer_list * timer);int del_timer(struct timer_list * timer);-expires:定時器將要運行的jiffies值-function:定時器到期時執(zhí)行的函

19、數(shù)-data:傳遞給function的參數(shù),可以使指針jit模塊代碼分析31課后練習(xí)輸入jit驅(qū)動代碼,編譯并加載,讀取/proc目錄下的相應(yīng)文件,觀察不同延時方法的表現(xiàn)32第五章 并發(fā)和競態(tài)33什么是并發(fā)和競態(tài)CPU的多處理特性,導(dǎo)致多個線程同時執(zhí)行,如內(nèi)核搶占、中斷、異步執(zhí)行(定時器)、SMP(多處理器)等資源共享容易導(dǎo)致競態(tài)scull的問題分析-內(nèi)存泄露34如何避免競態(tài)用內(nèi)核提供的并發(fā)控制原語(信號量、鎖定等)減少資源共享(如全局變量等)信號量和互斥-臨界區(qū)(操作共享資源)-信號量是一個整數(shù),一個進程只有在信號量大于0時才能進入臨界區(qū),同時信號量減1,小于0時需要等待(休眠)-信號量初始

20、值為1時就成為互斥35并發(fā)控制(1)-linux信號量初始化void sema_init(struct semaphore *sem, int val);-val:信號量初始值互斥體初始化編譯時:DECLARE_MUTEX(name); DECLARE_MUTEX_LOCKED(name);-初始處于鎖定狀態(tài)運行時:void init_MUTEX(struct semaphore *sem);void init_MUTEX_LOCKED(struct semaphore *sem);36并發(fā)控制(2)-自旋鎖特性:-可以在不能休眠的代碼中使用-提高性能-主要用于可搶占內(nèi)核和多CPU系統(tǒng)使用規(guī)則

21、:-擁有鎖時不能休眠(不能調(diào)用任何可能導(dǎo)致休眠的函數(shù),如kmalloc,copy_from_user等)-持有自旋鎖的時間應(yīng)盡可能短,否則內(nèi)核延遲將增加,高優(yōu)先級進程將被迫長時間等待,影響性能37自旋鎖API初始化:spinlock_t my_lock = SPIN_LOCK_UNLOCKED; (編譯時)void spin_lock_init(spinlock_t *lock); (運行時)獲取自旋鎖:void spin_lock(spinlock_t *lock);void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);-

22、禁止中斷,同時保存當(dāng)前中斷允許狀態(tài)void spin_lock_irq(spinlock_t *lock);-禁止中斷void spin_lock_bh(spinlock_t *lock)-禁止軟中斷釋放自旋鎖:void spin_unlock(spinlock_t *lock);void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);void spin_unlock_irq(spinlock_t *lock);void spin_unlock_bh(spinlock_t *lock);判斷能否獲得自旋鎖,同時不會阻

23、塞:int spin_trylock(spinlock_t *lock);int spin_trylock_bh(spinlock_t *lock);38第六章 內(nèi)存分配39kmalloc函數(shù)(1)和malloc相似有可能阻塞不對所分配的內(nèi)存區(qū)段清零所分配的內(nèi)存區(qū)段在物理上是連續(xù)的40kmalloc函數(shù)(2)#include void *kmalloc(size_t size, int flags); -s ize:需要分配的內(nèi)存大小-flags:標(biāo)志-GFP_KERNEL(代表進程分配,可能導(dǎo)致休眠,最常用)-GFP_ATOMIC(在中斷服務(wù)程序、定時器函數(shù)環(huán)境中使用,不會導(dǎo)致休眠)41km

24、alloc函數(shù)(3)只能分配預(yù)定義的,固定大小的字節(jié)數(shù)實際分配的大小可能大于請求的字節(jié)數(shù)kmalloc能分配的最小字節(jié)數(shù)是32或64不要分配太大的內(nèi)存(大于128K)42kfree函數(shù)釋放由kmalloc分配的內(nèi)存void kfree(void *obj); obj:kmalloc返回的指針43IO內(nèi)存(1)通常指外設(shè)的寄存器或設(shè)備內(nèi)存,如顯存或網(wǎng)卡緩沖區(qū)等映射到內(nèi)存地址空間。也是通過CPU地址總線和數(shù)據(jù)總線讀寫需要將IO內(nèi)存的物理地址映射到內(nèi)核的虛擬地址(ioremap)不要直接使用指針訪問IO內(nèi)存,應(yīng)使用內(nèi)核提供的讀寫函數(shù)(可讀性、可移植性好,經(jīng)過優(yōu)化)44IO內(nèi)存(2)IO內(nèi)存的分配和映

25、射-請求分配IO內(nèi)存區(qū)域#include struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);start:起始地址len:長度成功返回非NULL指針-釋放IO內(nèi)存區(qū)域void release_mem_region(unsigned long start, unsigned long len); 45IO內(nèi)存(3)將設(shè)備的IO地址(如寄存器地址等)映射到內(nèi)核的虛擬地址空間#include void * ioremap(unsigned long offset, unsign

26、ed long size); -offset:設(shè)備的IO地址(物理地址)-size:映射范圍由于體系結(jié)構(gòu)差異,不能直接操作返回的指針,應(yīng)使用內(nèi)核提供的IO操作函數(shù)取消ioremap所做的映射void iounmap(void *addr); -addr:ioremap返回的內(nèi)核虛擬地址46IO內(nèi)存(4)讀IO內(nèi)存unsigned int ioread8(void *addr);-8位unsigned int ioread16(void *addr);-16位unsigned int ioread32(void *addr);-32位addr:ioremap返回的指針寫IO內(nèi)存void iowr

27、ite8(u8 value, void *addr);void iowrite16(u16 value, void *addr);void iowrite32(u32 value, void *addr);連續(xù)讀寫void ioread8_rep(void *addr, void *buf, unsigned long count);void ioread16_rep(void *addr, void *buf, unsigned long count);void ioread32_rep(void *addr, void *buf, unsigned long count);void iow

28、rite8_rep(void *addr, const void *buf, unsigned long count);void iowrite16_rep(void *addr, const void *buf, unsigned long count);void iowrite32_rep(void *addr, const void *buf, unsigned long count);buf:數(shù)據(jù)緩沖區(qū)count:數(shù)據(jù)大小讀寫整塊IO內(nèi)存void memset_io(void *addr, u8 value, unsigned int count);void memcpy_fromio

29、(void *dest, void *source, unsigned int count);void memcpy_toio(void *dest, void *source, unsigned int count);47第七章 中斷處理48設(shè)備通訊的三種方式輪詢中斷DMA(直接內(nèi)存存?。?9什么是中斷中斷是外設(shè)給CPU的信號,可以臨時打斷CPU執(zhí)行的代碼,轉(zhuǎn)而執(zhí)行中斷處理程序一個中斷通常和一個處理程序關(guān)聯(lián)中斷具有優(yōu)先級,高優(yōu)先級的中斷可以嵌套低優(yōu)先級的中斷在CPU相應(yīng)中斷時,同級的中斷會被自動屏蔽中斷處理程序時異步執(zhí)行的,需要注意防止競態(tài)中斷處理程序必須是原子執(zhí)行的,不能進入休眠狀態(tài)50中

30、斷處理程序(1)注冊和釋放#include int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *dev_name, void *dev_id);irq:請求的中斷號(可以參考CPU數(shù)據(jù)手冊)handler:和irq相關(guān)聯(lián)的中斷處理程序flags:中斷標(biāo)志,通常取SA_INTERRUPTdev_name:中斷的所有者dev_id:私有數(shù)據(jù),如不使用,可以設(shè)為NULLvoid free_irq(unsigne

31、d int irq, void *dev_id);通常應(yīng)該在打開設(shè)備的時候請求中斷,而不是在模塊初始化時,防止沒有使用設(shè)備而占用中斷資源。/proc/interrupts可以顯示系統(tǒng)中斷的狀態(tài)51中斷處理程序(2)運行限制:-不能和用戶空間傳遞數(shù)據(jù)-不能等待任何事件-分配內(nèi)存時應(yīng)使用GFP_ATOMIC參數(shù)-不能給信號量加鎖-不能執(zhí)行調(diào)度程序中斷處理程序的主要工作是響應(yīng)中斷(設(shè)置中斷響應(yīng)標(biāo)志),將設(shè)備的數(shù)據(jù)讀入驅(qū)動的緩沖區(qū),同時喚醒等待數(shù)據(jù)的用戶進程中斷處理程序的返回值-IRQ_HANDLED:已處理-IRQ_NONE:未處理,或者不是本設(shè)備產(chǎn)生的中斷short模塊代碼分析52前半部和后半部(

32、1)當(dāng)中斷處理程序要做較長時間的處理時,應(yīng)分為兩部分前半部執(zhí)行時關(guān)閉中斷,因此執(zhí)行過程要盡可能短(request_irq注冊的處理程序)后半部由前半部調(diào)度,在推后的更安全的時間執(zhí)行(此時可以允許中斷)典型的處理過程如前半部只是獲取設(shè)備數(shù)據(jù)到緩沖,然后直接退出,數(shù)據(jù)的處理、進程喚醒等耗時的操作由后半部執(zhí)行53前半部和后半部(2)內(nèi)核提供的后半部處理機制tasklet-較快,但必須是原子執(zhí)行的tasklet的聲明:DECLARE_TASKLET(name, function, data);name:tasklet名稱function:tasklet被調(diào)度時執(zhí)行的函數(shù)data:指針參數(shù)如:void

33、short_do_tasklet(unsigned long);DECLARE_TASKLET(short_tasklet, short_do_tasklet, 0);tasklet的調(diào)度(一般有前半部調(diào)用)tasklet_schedule(&short_tasklet);54前半部和后半部(3)工作隊列-運行周期較長,但允許休眠工作隊列的聲明:static struct work_struct short_wq;INIT_WORK(&short_wq, (void (*)(void *) short_do_tasklet, NULL);工作隊列的調(diào)度:schedule_work(&short

34、_wq);short模塊代碼分析55第八章 塊設(shè)備驅(qū)動程序56塊設(shè)備的特性可以隨機讀寫固定大小的數(shù)據(jù)塊可以提高性能塊大小通常是4096字節(jié)內(nèi)核使用的扇區(qū)大小是512字節(jié)57塊設(shè)備的注冊和注冊塊設(shè)備的注冊int register_blkdev(unsigned int major, const char *name); major:主設(shè)備號,如為0,由內(nèi)核動態(tài)分配name:設(shè)備名塊設(shè)備的注銷int unregister_blkdev(unsigned int major, const char *name); 58塊設(shè)備的操作#include struct block_device_operat

35、ionsint (*open)(struct inode *inode, struct file *filp); int (*release)(struct inode *inode, struct file *filp); int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); 大部分的塊設(shè)備ioctl命令都有內(nèi)核處理,驅(qū)動實現(xiàn)的較少int (*media_changed) (struct gendisk *gd); int (*revalidate_disk) (s

36、truct gendisk *gd); 對包含可移動介質(zhì)的塊設(shè)備(如光驅(qū)等),用來判斷設(shè)備介質(zhì)是否改變并作出響應(yīng)和字符驅(qū)動的主要區(qū)別是沒有讀寫函數(shù)59gendisk結(jié)構(gòu)內(nèi)核用來顯示磁盤驅(qū)動器或分區(qū)主要成員struct block_device_operations *fops; 設(shè)備操作集合.struct request_queue *queue; 設(shè)備I/O 請求隊列結(jié)構(gòu)分配和初始化struct gendisk *alloc_disk(int minors); void add_disk(struct gendisk *gd); 釋放void del_gendisk(struct gendi

37、sk *gd);sbull驅(qū)動模塊初始化函數(shù)分析60塊設(shè)備操作函數(shù)open和close-設(shè)置驅(qū)動和硬件的狀態(tài). 包括起停磁盤, 加鎖一個可移出設(shè)備的門, 分配 DMA 緩沖等等-不一定由應(yīng)用程序調(diào)用,可能由內(nèi)核直接調(diào)用,如mount等ioctl-大部分ioctl由內(nèi)核處理,驅(qū)動處理的很少sbull模塊設(shè)備操作代碼分析61I/O請求I/O請求的處理-在內(nèi)核認(rèn)為需要啟動對設(shè)備讀寫的時候調(diào)用-請求隊列包含當(dāng)前需要處理的請求,由內(nèi)核對所有I/O請求進行調(diào)度(合并或重排等,性能考慮)后將請求加入隊列請求隊列的初始化和清除#include request_queue_t blk_init_queue(re

38、quest_fn_proc *request, spinlock_t *lock); request:請求處理函數(shù)void blk_cleanup_queue(request_queue_t *); 從隊列中獲取請求struct request *elv_next_request(request_queue_t *queue); (不刪除請求)從隊列中刪除請求void blkdev_dequeue_request(struct request *req); 通知內(nèi)核請求已處理void end_request(struct request *req, int success); sucess:指

39、示請求是否成功完成62請求的結(jié)構(gòu)(1)一個request可能包含多個bio,一個bio可能包含多個bio_vec(段)bio結(jié)構(gòu)圖63請求隊列圖請求的結(jié)構(gòu)(2)64請求的結(jié)構(gòu)(3)遍歷request中的biorq_for_each_bio(bio, request)遍歷bio中的段bio_for_each_segment(bvec, bio, segno); 65請求完成函數(shù)int end_that_request_first(struct request *req, int success, int count); success:驅(qū)動是否完成請求的扇區(qū)的傳送count:完成傳送的扇區(qū)數(shù)-告

40、知內(nèi)核驅(qū)動已完成count個扇區(qū)傳送void end_that_request_last(struct request *req); -通知等待請求完成的進程,同時釋放request結(jié)構(gòu)sbull模塊代碼分析66第九章 網(wǎng)絡(luò)設(shè)備驅(qū)動程序67網(wǎng)絡(luò)設(shè)備的特點將接口注冊到內(nèi)核中,供內(nèi)核在需要時調(diào)用沒有設(shè)備文件(沒有read,write等調(diào)用)異步接收數(shù)據(jù),需要將數(shù)據(jù)推送給內(nèi)核驅(qū)動和協(xié)議相互獨立需要支持設(shè)置網(wǎng)絡(luò)地址, 修改發(fā)送參數(shù), 以及維護流量和錯誤統(tǒng)計等操作68net_device結(jié)構(gòu)分配#include struct net_device *alloc_netdev(int sizeof_pri

41、v, const char *name, void (*setup)(struct net_device *);sizeof_priv :私有數(shù)據(jù)區(qū)的大小name:接口名(如eth0等)setup:初始化函數(shù)的指針, 用來設(shè)置 net_device 結(jié)構(gòu)的剩余部分(snull的net_device初始化函數(shù)分析)如:snull_devs0 = alloc_netdev(sizeof(struct snull_priv), sn%d, snull_init);對于以太網(wǎng),可以簡化為:#include struct net_device *alloc_etherdev(int sizeof_pri

42、v); 默認(rèn)使用eth%d 作為name參數(shù). ether_setup()為初始化函數(shù)。釋放void free_netdev(struct net_device *dev); 69網(wǎng)絡(luò)設(shè)備的注冊和注銷int register_netdev(struct net_device *dev); void unregister_netdev(struct net_device *dev); 70網(wǎng)絡(luò)接口的打開和關(guān)閉(1)open和close接口由ifconfig調(diào)用open時所做的處理:-申請必要的資源(中斷、I/O地址空間等)-設(shè)置硬件地址(MAC地址)啟動發(fā)送隊列void netif_start_queue(struct net_device *dev); 71網(wǎng)絡(luò)接口的打開和關(guān)閉(2)close所做的處理:-釋放所申請到的資源-停止發(fā)送隊列-void netif_stop_queue(struct net_device *dev); 72數(shù)據(jù)包的發(fā)送sk_buff結(jié)構(gòu)#in

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論