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

下載本文檔

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

文檔簡介

1、V1.0大1- 設(shè)備驅(qū)動程序入門2- 中斷處理3- 等待隊列4- 定時處理5- 實(shí)例分析字符設(shè)備驅(qū)動程序6- 實(shí)例分析網(wǎng)絡(luò)設(shè)備驅(qū)動程序7- 用戶與內(nèi)核的接口 驅(qū)動程序分類驅(qū)動程序分類 模塊方式驅(qū)動程序模塊方式驅(qū)動程序 內(nèi)核方式驅(qū)動程序內(nèi)核方式驅(qū)動程序 用戶模塊驅(qū)動程序用戶模塊驅(qū)動程序 字符設(shè)備驅(qū)動程序字符設(shè)備驅(qū)動程序 表現(xiàn)為文件,面向字節(jié),即時收發(fā)數(shù)據(jù) 塊設(shè)備驅(qū)動程序塊設(shè)備驅(qū)動程序 表現(xiàn)為文件,面向塊,通過緩存區(qū)進(jìn)行緩沖 網(wǎng)絡(luò)設(shè)備驅(qū)動程序網(wǎng)絡(luò)設(shè)備驅(qū)動程序 表現(xiàn)為net_device結(jié)構(gòu)鏈表中的一項(xiàng),面向流或數(shù)據(jù) 報,通過sk_buff結(jié)構(gòu)進(jìn)行收發(fā) 編寫步驟編寫步驟 1) 寫入口函數(shù) 2) 寫模

2、塊函數(shù) 3) 編譯為.O文件 4) 插入模塊 5) 創(chuàng)建設(shè)備文件 調(diào)試方式調(diào)試方式 實(shí)例實(shí)例一、入口函數(shù)一、入口函數(shù) Open() 打開設(shè)備 增加使用記數(shù);分配內(nèi)存空間;初始化變量、函數(shù);申請中斷、I/O空間Release() 關(guān)閉設(shè)備 減少使用記數(shù);釋放內(nèi)存空間;釋放中斷、 I/O空間Write() 寫設(shè)備 Copy_from_user()Read() 寫設(shè)備 Copy_to_user()其他函數(shù)如ioctl()和中斷處理函數(shù)等二、模塊函數(shù)二、模塊函數(shù) Init_module() 模塊初始化函數(shù)。在插入模塊時執(zhí)行 也可以用module_init(your_init_func) 主要執(zhí)行設(shè)備的

3、注冊Cleanup_module() 模塊清理函數(shù)。在移除模塊時執(zhí)行 也可以用module_exit(your_cleanup_func) 主要執(zhí)行設(shè)備的反注冊三、編譯三、編譯 用如下命令將mydriver.c編譯為mydriver.oPpc_8xx-gcc-DLINUX-DMODULE-D_KERNEL_-Wall-Wstrict-prototypes-fno-builtin-nostdinc -O2-I/opt/hardhat/devkit/lsp/embeddedplanet-cllf-ppc_8xx/linux-2.4.17_mvl21/include/-I/opt/hardhat/d

4、evkit/ppc/8xx/lib/lib/gcc-Lib/powerpc-hardhat-linux/2.95.3/include/-I/opt/hardhat/devkit/lsp/embeddedplanet-cllf-ppc_8xx/linux-2.4.17_mvl21/arch/ppc/-cMydriver.c四、插入模塊四、插入模塊 insmod mydriver.o該命令將驅(qū)動程序模塊插入到內(nèi)核中,并執(zhí)行init_module()函數(shù)。該命令也可以向驅(qū)動程序中傳遞一些參數(shù)。rmmod mydriver該命令將驅(qū)動程序模塊從內(nèi)核中先移除,并執(zhí)行cleanup_module()函數(shù)。

5、其它命令:modprobe、depmod、modinfo。五、創(chuàng)建設(shè)備文件五、創(chuàng)建設(shè)備文件 Mknod/dev/mydriver c major minor該命令創(chuàng)建一個字符設(shè)備文件mydriver,它的主設(shè)備號是major,次設(shè)備號是minor。設(shè)備號信息可以在/proc/devices文件中獲得。網(wǎng)絡(luò)設(shè)備驅(qū)動程序不需要此步驟,因?yàn)樗怀霈F(xiàn)在文件系統(tǒng)中。模塊驅(qū)動程序的調(diào)試模塊驅(qū)動程序的調(diào)試 使用printk函數(shù) 在程序的開始加入 #define MY_debug 在需要打印調(diào)試信息的位置加入 #ifdef MY_DEBUG printk(“my debug info”); #endif模塊驅(qū)

6、動程序?qū)嵗K驅(qū)動程序?qū)嵗齅odexample.c#include #include #include #include #include #include unsigned int test_major=0ssize_t read_test(struct file *file,char *buf,size_t count,loff_t *offset)int left;if(verify_area(VERIFY_WRITE,buf,count)=-EFAULT)Return EFAULT;for(left=count;left0;left-)put_user(1,buf);buf+Retur

7、n count;ssize_t write_test(struct file *file,const char *buf,size_t count,loff_t *offset)Return count;Int open_test(struct inode *inode,strut file *file)MOD_INC_USE_COUNT;Return 0;Int release_test(struct inode *inode,struct file *file)MOD_DEC_USE_COUNT;Return 0;Static struct file_operationsTest_fops

8、= Read: read_test, write: write_test, open: open_test, release: release_test,;Int my_init_module(void)Int result;Result=register_chrdev(test_major,”test”, &test_fops);If(resultload Ox200000 nete860.bin BINBDIti Ox200000五五. .在主機(jī)上執(zhí)行在主機(jī)上執(zhí)行ddd debuggerddd debugger/opt/hardhat/devkit/ppc/8xx/bin/ppc_

9、8xx-gdb gdb/opt/hardhat/devkip/lsp/embeddedplanet-cllf-8xx/linux2.4.17_mvl21/vmlinux六六. .在在dddddd中輸入中輸入: :Target remote 192.168.1.20:2001 適用范圍及特點(diǎn)適用范圍及特點(diǎn) I/O映射映射 內(nèi)存映射內(nèi)存映射 讀寫設(shè)備讀寫設(shè)備 適用范圍及特點(diǎn)適用范圍及特點(diǎn) 測試新的硬件設(shè)備 測試一個新的設(shè)備是否可用 觀察設(shè)備的工作情況快速創(chuàng)建一個硬件應(yīng)用 比如控制小馬達(dá)的轉(zhuǎn)動 點(diǎn)亮某個指示燈優(yōu)點(diǎn):1)可以連接完整的C庫,編程容易2)可以使用傳統(tǒng)調(diào)試器,而不必調(diào)試內(nèi)容缺點(diǎn):1)不支持

10、設(shè)備中斷2)不支持設(shè)備定時 I/O映射映射 ioperm()為用戶應(yīng)用程序打開一塊I/O空間iopl()為用戶應(yīng)用程序打開整個I/O地址空間MontaVista Linux不支持 內(nèi)存映射內(nèi)存映射 通過設(shè)備/dev/mem來訪問硬件設(shè)備 使用mmap()函數(shù)來選擇要訪問的內(nèi)存物理基址和塊大小,它返回已經(jīng)映射到物理基址的虛擬地址 void *mmap (void *start, size_t length, int prot, int flags,in fd,off_t offset) fd=open(“/dev/men”,O_WRONLY);ledptr=mmap(0,sizeof(LED_A

11、REA),PROT_WRITE,MAP_SHARED,fd,LED_ADDRESS);*ledptr=value; 讀寫設(shè)備讀寫設(shè)備 使用函數(shù)inb(), inw(), inl() 或readb(), readw(), readl()來讀設(shè)備 使用函數(shù)outb(), outw(), outl()或writeb(), writew(),writel()來寫設(shè)備 它們的頭文件是,基本概述基本概述探測中斷探測中斷安裝中斷安裝中斷取消中斷取消中斷 分類分類 硬件中斷由硬件設(shè)備產(chǎn)生的中斷執(zhí)行相應(yīng)的中斷處理程序可以產(chǎn)生軟中斷(tasklet)來實(shí)現(xiàn)耗時的中斷處理任務(wù),也就是下半部中斷 軟中斷(softIR

12、Q)內(nèi)核中共有32個softIRQ, 其中一個就是TASKLET_SOFTIRQ在內(nèi)核執(zhí)行do_softirq()函數(shù)時,輪詢這32個softirq,如果相應(yīng)的softirq可以執(zhí)行,就執(zhí)行它指導(dǎo)的函數(shù)TASKLET_SOFTIRQ對應(yīng)的函數(shù)是tasklet_action(),它會依次執(zhí)行掛在TASKLET_SOFTIRQ上的tasklet Read執(zhí)行流程執(zhí)行流程 中斷處理程序舉例中斷處理程序舉例 struct tasklet_struct my_tasklet; elsewhere, in some initialization section tasklet_init(&my_t

13、asklet, my_bh, NULL); void th_interrupt(int irq, void *dev_id, struct pt_regs *regs) dl_gettimeofday(tv_head); tv_head+; if(tv_head=(tv_data+NR_TIMEVAL) tv_head=tv_data; tasklet_schedule(&my_tasklet); /*queue the tasklet*/ short_bh_count+; /*record that an interrupt arrived*? 1. probe_irq_on(voi

14、d) 返回一個unsigned long 位掩碼2. 使設(shè)備發(fā)中斷使設(shè)備發(fā)中斷3. probe_irq_oof(unsigned long) 第一步返回的位掩碼傳給此函數(shù) 返回值即為探測到的中斷號(如果為0或?yàn)樨?fù)則沒有可用中斷) 探測中斷例子探測中斷例子 unsigned long mask=probe_irq_on(); outb_p(0 x10,short_base+2); /*enable reporting*/ outb_p(0 x00,short_base); /*clear the bit*/ outb_p(0 xFF,short_base); /*set the bit:inte

15、rrupt*/ outb_p(0 x00,short_base+2); /*disable reporting*/ irq=probe_irq_off(mask); 安裝安裝SIU中斷中斷 SIU中斷向量表16個(/include/asm-asm-ppc/irq.h) 外部中斷 根據(jù)硬件連線確定IRQ號碼,比如是IRQ3 調(diào)用函數(shù)request_8xxirq(SIU_IRQ3, my_handler, flag, devname, devpointer) 內(nèi)部中斷 選擇一個未用的LEVEL號碼,比如是LEVEL3 調(diào)用函數(shù)request_8xxirq(SIU_LEVEL3, my_handle

16、r, flag, devname, NULL) 安裝安裝SIU中斷例子中斷例子 #define CPM_INTERRUPTSIU_LEVEL2 (在文件irq.h中定義) cpm_interrupt_init()函數(shù)中 *(arch/ppc/8xx_io/commproc.c) /* Set our interrup handler with the core CPU. */ If (request_8xxirq(CPM_interrupt, cpm_interrupt, 0,”cpm”, NULL)!=0)Panic( “could not allocate CPM IRQ!”); 安裝安裝

17、CPM中斷中斷 CPM中斷向量表32個(/arch/ppc/8xx_io/commproc.h) 確定相應(yīng)的中斷向量,比如是SCC1 調(diào)用函數(shù) cpm_install_handler(CPMVEC_SCC1, scc1_handler, devpointer) 例子例子 cpm_interrupt_init() 函數(shù)中 *(/arch/ppc/8xx_io/commproc.c) /* Install our own error handler. */ cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); 取消中斷取消中斷

18、取消SIU中斷 (do_free_irq(int irq,void* dev_id) 例:do_free_irq(SIU_IRQ3, devpointer) 取消CPM中斷 cpm_free_handler(int vec) 例:cpm_free_handler(CPMVEC_ERROR) 中斷處理程序任務(wù)中斷處理程序任務(wù) 響應(yīng)中斷 查看中斷狀態(tài)寄存器,判斷中斷源 根據(jù)中斷源進(jìn)行相應(yīng)處理概述概述 使用時機(jī) 請求暫不可用的資源 版本相關(guān)(/linux/wait.h) 2.4版以前使用結(jié)構(gòu)體 wait_queue 2.4版使用結(jié)構(gòu)體 wait_queue_head_t主要函數(shù)主要函數(shù) (/kern

19、el/sched.c) sleep_on(wait_queue_head_t *q) interruptible_sleep_on(wait_queue_head_t *q) (/linux/sched.h) wake_up(wait_queue_head_t *q) wake_up_interruptible(wait_queue_head_t *q) (/inclued/linux/wait.h) DECLARE_wait_queue_head(name) DECLARE_waitqueue (name,tsk) add_wait_queue(wait_queue_head_t *head

20、, wait_queue_t *new) remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)使用實(shí)例使用實(shí)例 情景:內(nèi)核中有一塊內(nèi)存,在寫時發(fā)現(xiàn)滿了 首先在程序開始定義全局變量 strut wait_queue_head_t wqh; /struct wait_queue_t wq; 或者使用宏 DECLARE_WAIT_QUEUE_HEAD(wqh); /DECLARE_WAITQUEUE(wq,current); 在write函數(shù)中: while(is_full) interruptible_sleep_on(&

21、;wqh); /add_wait_queue(&wqh,Qwq); /current-state=TASK_interruptible; /schedule();使用實(shí)例使用實(shí)例(續(xù)續(xù)) write_to_buffer(); is_empty=0; 在read函數(shù)中: if(!is_empty) read_from_buffer(); if_full=0; wake_up_interruptible(&wqh); 概述概述 數(shù)據(jù)結(jié)構(gòu) include/linux/timer.h struct timer_list struct timer_list *next; struct t

22、imer_list *prev; unsigned long expires; unsigned long data; void(*function)(unsigned loing); 主要函數(shù)主要函數(shù) 初始化timer void init_timer(struct timer_list *timer); 添加timer void add_timer(struct timer_list *timer); 刪除timer void del_timer(struct timer_list *timer);使用實(shí)例使用實(shí)例 struct timer_list my_timer; init_timer

23、(&my_timer); my_timer.function = my_timerfunc; my_timer.data = my_argu; my_timer.expires = jiffies+HZ; /delay 1 sec add_timer(my_timer); 等待隊列和定時器綜合實(shí)例等待隊列和定時器綜合實(shí)例 init_timer_out; struct timer_list timer; void timeout_func(unsigned long who) timed_out = 1; debug(“Timing outn”) wake_up_interruptibl

24、e(wait_queue_head_t*)who); int sleep_or_timerout(wait_queue_head_t*wait,int timeout) timed_out=0; timer.data=(unsigned long) wait; timer.function = timeout_func; 等待隊列和定時器綜合實(shí)例等待隊列和定時器綜合實(shí)例 timer.expires= jiffies + timeout; add_timer(&timer); debug(“going to sleepn”); interruptible_sleep_on(wait);

25、del_timer(&timer); if(timed_out) timed_out = 0; return 1; else return 0; 源程序源程序:mydriver.c mydriver.h 該程序是一個典型的模塊方式字符設(shè)備驅(qū)動程序該程序是一個典型的模塊方式字符設(shè)備驅(qū)動程序 該程序包含了中斷該程序包含了中斷(上下半部上下半部),時鐘,等待隊列,時鐘,等待隊列 的處理例程的處理例程 其特點(diǎn)在于用時鐘中斷來模擬硬件中斷其特點(diǎn)在于用時鐘中斷來模擬硬件中斷 函數(shù)列表函數(shù)列表 my_init_module(); mydriver_init(); my_cleanup_module(

26、); mydriver_stop(); mydriver_open(); mydriver_release(); mydriver_timer_expiration(); mydriver_interrupt(); mydriver_task(); mydriver_read(); mydriver_write() 程序分析程序分析 my_init_module(void 調(diào)用mydriver_init() my_cleanup_module(void) 調(diào)用mydriver_stop()注冊設(shè)備注冊設(shè)備 if(rc=unregister_chrdev(mydriver_major, mydr

27、iver_name, &my_fops):初始化等待隊列初始化等待隊列Int_waitqueue_head(&mydriver_zz);取消設(shè)備注冊取消設(shè)備注冊If(rc=unregister_chrdev(mydriver_major, mydriver_name) mydriver_open(pinode,pfile) 增加打開記數(shù) mydriver_open_count+,; 為文件的緩存區(qū)分配內(nèi)存空間 mydriver_buffer= (char *) kmalloc(MYDRIVER_BUFFERSIZE,GEP_KERNEL); 初始化所分配的內(nèi)存空間 memset

28、(mydriver_buffer, 0, MYDRIVER_BUFFERSIZE); 申請中斷號 #ifndef MYDRIVER_SIMULATE_INTERRUPT rc=request_irq(mydriver_irq,mydriver_interrupt, SA_SHIRQ, mydriver_name, NULL); 初始化定時器 init_timer(&mydriver_timer); 增加使用記數(shù) MOD_INC_USE_COUNT; mydriver_release(pinode,pfile) 增加釋放記數(shù) mydriver_release_count+,; 刪除定時器

29、 if (rc=del_timer(&mydriver_timer); 釋放中斷號 #ifndef MYDRIVER_SIMULATE_INTERRUPT free_irq(mydriver_irq,mydriver_name); 釋放用戶緩存區(qū)內(nèi)存空間 kfree(mydriver_buffer); 增加使用記數(shù) MOD_DEC_USE_COUNT; mydriver_timer_expiration(mydriver_data) 說明 定義MYDRIVER_SIMULATE_INTERRUPT時才編譯,其作用是用定時器來模擬硬件中斷 增加定時器超時記數(shù) mydriver_timer

30、_count+; 執(zhí)行中斷處理函數(shù) mydriver_interupt( MYDRIVER_IRQ,(void*) mydriver_data,(NULL); mydriver_interrupt(irq,dev_id,fp) 增加中斷記數(shù) mydriver_interrup_count+; 設(shè)置I/O成功標(biāo)志 mydriver_final_status=0; 初始化tasklet(下半部) tasklet_init(&mydriver_tasklet, mydriver_task, (unsigned long) dev_id); 調(diào)度tasklet(下半部) tasklet_sch

31、edule(&mydriver_tasklet); mydriver_task(data) 喚醒等待隊列 wake_up_interruptible(&mydriver_zz); mydriver_read(pfile,user_buf,count,poffset) 增加讀記數(shù) mydriver_read_count+; 給定時器賦值,并添加定時器 mydriver_timer.function=mydriver_timer_expiration; mydriver_timer.data=0; mydriver_timer.expires=jiffies+(MYDRIVER_I

32、O_DURATION *HZ); add_timer(&mydriver_timer); 睡眠在等待隊列mydriver_zz上 interruptible_sleep_on(&mydriver_zz); mydriver_read(pfile,user_buf,count,poffset)續(xù)續(xù) 處理異常情況 if (signal_pending(current) del_timer(&mydriver_timer); printk(“ABNORMALLY terminated:”); 正常讀出數(shù)據(jù),將數(shù)據(jù)拷貝給用戶,返回讀出的字節(jié)數(shù) if (mydriver_fina

33、l_status = 0) if (copy_to_user(user_buf, mydriver_buffer, count) printk(“NORMALLY TERMINATTED:”); return mydriver_final_count; mydriver_write(pfile,user_buf,count,poffset) 增加寫記數(shù) mydriver_write_count+; 拷貝數(shù)據(jù)到文件緩存區(qū) if (copy_from_user(mydriver_buffer, user_buf, count); 給定時器賦值,并添加定時器 與read中相同 睡眠在等待隊列mydr

34、iver_zz上 interruptible_sleep_on(&mydriver_zz); mydriver_write(pfile,user_buf,count,poffset)續(xù)續(xù) 處理異常情況 if (signal_pending(current) del_timer(&mydriver_timer); printk(“ABNORMALLY terminated:”); 正常寫入數(shù)據(jù),返回寫入的字節(jié)數(shù) if (mydriver_final_status = 0) printk(“NORMALLY TERMINATTED:”); return mydriver_final

35、_count; 思考思考 如何將此模塊方式驅(qū)動程序修改為內(nèi)核方式驅(qū)動程序? 源程序源程序enet.c commproc.h Motorola MPC8xx以太網(wǎng)驅(qū)動以太網(wǎng)驅(qū)動 在在SCCx上實(shí)現(xiàn)以太網(wǎng)功能上實(shí)現(xiàn)以太網(wǎng)功能 函數(shù)列表函數(shù)列表 scc_enet_init(); scc_enet_open(); scc_enet_start_xmit(); scc_enet_rx(); scc_enet_close(); scc_enet_interrupt(); scc_enet_get_stats(); scc_enet_timeout(): scc_enet_t 調(diào)用路徑 (/init/mai

36、n.c)start_kernel()-init()-(do_basic_setup()-do_initcalls()- (/fs/partitions/check.c)_initcall(partition_setup)-partion_setup()- (/drivers/block/genhd.c)device_init()-(/net/core/dev.c) net_dev_init()-network_probe(),使用pci_probes 初始化數(shù)組,其中包含scc_enet_init() 初始化net_device結(jié)構(gòu)的各個域; dev=init_etherdev(0,0) 初始

37、化MPC860的parameter ram; ep=(scc_enet_t *)(&cp-cp_dparamPROFF_ENET); 初始化MPC860的寄存器 immap=(immap_t*)(_get_IMMR()&0 xFFFF0000); sccp=(volatile scc_t*) (&cp-cp_sccSCC_ENET_; 初始化buffer; 初始化board; 設(shè)置并安裝中斷; sccp-scc_sccm=(SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); cpm_inistall_handler(CPMVE

38、C_ENET, scc_enet_interrupt, dev); 將函數(shù)指針賦給net_device結(jié)構(gòu)中相應(yīng)的入口 dev-open = scc_enet_open; dev-hard_star_xmit = scc_enet_start_xmit; dev-tx_timeout= scc_enet_timeout; dev-watchdog_timeo = TX_TIMEOUT; dev-stop = scc_enet_close; dev-get_stats = scc_enet_get_stats; dev-set_multicast_list = set_multicast_lis

39、t; scc_enet_open 更改dev-state域的指示位 netif_start_queue(dev); 相當(dāng)于下面的語句 clear_bit(_LINK_STATE_XOFF,&dev-state); scc_enet_close(dev) 更改dev-state域的指示位 netif_stop_queue(dev); 相當(dāng)于下面的語句 set_bit(_LINK_STATE_XOFF,&dev-state); 當(dāng)用戶通過enet發(fā)送數(shù)據(jù)時,執(zhí)行該函數(shù) 將skb中相應(yīng)域的值賦給bdp(即cep-cur_tx)的相應(yīng)域 包長度:bdp-cbd_datlen = skb

40、-len; 包數(shù)據(jù)指針:bdp-cbd_vufaddr = _pa(skb-data); 保存skb指針 cep-tx_skbuff cep-skb_cur = skb 增加統(tǒng)計域中的發(fā)送字節(jié)數(shù) (cep-stats.tx_bytes+=skb-len;); 將cep-skb_cur域加一, 如果超過TX_RING_SIZE, 則置為0 cep-skb_cur = (cep-skb_cur+1) & TX_RING_MOD_MASK; 清理相應(yīng)數(shù)據(jù)緩沖區(qū)中的內(nèi)容 flush_dcache_range(unsigned long) (skb-data), (unsigned long)

41、(skb-data+skb-len) 鎖中斷 spin_lock_irq(&cep-lock); 開始發(fā)送 bdp-cbd_sc |=(BD_ENET_TX_READY |BD_ENET_TX_TC); 設(shè)定發(fā)送開始時間 dep-trans_start=jiffies; 調(diào)理BD指針:將BD的指針向下一個可用BD,并判斷發(fā)送緩沖區(qū)是否滿 設(shè)置cep-cur_tx指針 cep-cur_tx= (cbd_t*)bdp; 解鎖中斷 spin_unlock_irq(&cep-lock); 當(dāng)產(chǎn)生RXF中斷,即收到幀后,執(zhí)行 獲取cep指針 cep=(struct scc_enet_pr

42、ivate *)dev-priv; 獲取bdp指針 bdp= cep-cur_rx; 檢查收到的是否是完整幀 更新統(tǒng)計信息 為skb申請內(nèi)存 skb= dev_alloc_skb(pkt_len-4); 將skb與設(shè)備相關(guān)連 skb-dev = dev; 在skb中分配pkt_len-4長度的空間 skb_put(skb,pkt_len-4); (skbuff.h中) 將數(shù)據(jù)拷貝到skb中 eht_copy_and_sum(skb,(unsigned char *)_va(bdp-cbd_bufaddr),pkt_len-4;0); (etherdevice.h中) 判斷并獲取協(xié)議的ID sk

43、b-protocol = eth_type_trans(skb,dev); (該函數(shù)在eth.c中) 將skb傳送到上層 netif_rx(skb); 設(shè)置BD 進(jìn)入for循環(huán)繼續(xù)讀取收到的包,如果bd為空,則退出循環(huán) 設(shè)置cep-cur_rx指針 cep-cur_rx = (cbd_t *) bodp; 當(dāng)CPMVEC_ENET產(chǎn)生中斷時,執(zhí)行 獲取cep指針 cep=(struct scc_enet_private *)dev-priv; 獲取中斷事件 int_events=cep-sccp-scc_scce; 處理接收中斷: if(int_events & SCCE_ENET_RXF) scc_enet_rx(dev_id); 處理寫送中斷; 加讀寫鎖spin_lock(&cep-lock); while循環(huán) 如果發(fā)送緩沖區(qū)滿,則退出循環(huán) if(bdp=cep-cur_tx) & (cep-tx_full=0) break; 更新統(tǒng)計信息; 出錯重發(fā) if (bdp-c

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論