Linux设备驱动程序

上传人:c****d 文档编号:243150482 上传时间:2024-09-16 格式:PPT 页数:80 大小:436.50KB
返回 下载 相关 举报
Linux设备驱动程序_第1页
第1页 / 共80页
Linux设备驱动程序_第2页
第2页 / 共80页
Linux设备驱动程序_第3页
第3页 / 共80页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,主题:,Linux设备驱动程序,主讲人:,徐文正,V1.0,1,大纲,1-,设备驱动程序入门,2-,中断处理,3-,等待队列,4-,定时处理,5-,实例分析字符设备驱动程序,6-,实例分析网络设备驱动程序,7-,用户与内核的接口,2,1,设备驱动程序入门,驱动程序分类,模块方式驱动程序,内核方式驱动程序,用户模块驱动程序,3,1.1,驱动程序分类,字符设备驱动程序,表现为文件,面向字节,即时收发数据,块设备驱动程序,表现为文件,面向块,通过缓存区进行缓冲,网络设备驱动程序,表现为,net_device,结构链表中的一项,面向流或数据 报,通过,sk_buff,结构进行收发,4,1.2,模块方式驱动程序,编写步骤,1),写入口函数,2),写模块函数,3),编译为,.O,文件,4),插入模块,5),创建设备文件,调试方式,实例,5,1.2,模块方式驱动程序,一、入口函数,Open(),打开设备,增加使用记数;分配内存空间;初始化变量、函数;申请中断、,I/O,空间,Release(),关闭设备,减少使用记数;释放内存空间;释放中断、,I/O,空间,Write(),写设备,Copy_from_user,(),Read(),写设备,Copy_to_user,(),其他,函数如,ioctl,(),和中断处理函数等,6,1.2,模块方式驱动程序,二、模块函数,Init_module(),模块初始化函数。在插入模块时执行,也可以用,module_init(your_init_func,),主要执行设备的注册,Cleanup_module,(),模块清理函数。在移除模块时执行,也可以用,module_exit(your_cleanup_func,),主要执行设备的反注册,7,1.2,模块方式驱动程序,三、编译,用如下命令将,mydriver.c,编译为,mydriver.o,Ppc_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/devkit/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/-c,Mydriver.c,8,1.2,模块方式驱动程序,四、插入模块,insmod mydriver.o,该命令将驱动程序模块插入到内核中,并执行,init_module,(),函数。该命令也可以向驱动程序中传递一些参数。,rmmod mydriver,该命令将驱动程序模块从内核中先移除,并执行,cleanup_module(),函数。,其它命令:,modprobe,、,depmod,、,modinfo,。,9,1.2,模块方式驱动程序,五、创建设备文件,Mknod/dev/mydriver,c major minor,该命令创建一个字符设备文件,mydriver,,它的主设备号是,major,,次设备号是,minor,。设备号信息可以在,/proc/devices,文件中获得。,网络设备驱动程序不需要此步骤,因为它不出现在文件系统中。,10,1.2,模块方式驱动程序,模块驱动程序的调试,使用,printk,函数,在程序的开始加入,#define MY_debug,在需要打印调试信息的位置加入,#ifdef,MY_DEBUG,printk,(“my debug info”);,#endif,11,1.2,模块方式驱动程序,模块驱动程序实例,Modexample.c,#include ,#include ,#include ,#include ,#include ,#include ,unsigned int test_major=0,ssize_t read_test(struct file * *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+,Return count;,12,1.2,模块方式驱动程序,ssize_t write_test(struct file *,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;,13,1.2,模块方式驱动程序,Static struct,Test_fops=,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”, ,If(resultload Ox200000 nete860.bin BIN,BDIti Ox200000,五,.,在主机上执行,ddd debugger,/opt/hardhat/devkit/ppc/8xx/bin/ppc_8xx-gdb gdb/opt/hardhat/devkip/lsp/embeddedplanet-cllf-8xx/linux2.4.17_mvl21/vmlinux,六,.,在,ddd,中输入,:,Target remote 192.168.1.20:2001,22,1.4,用户模式驱动程序,适用范围及特点,I/O,映射,内存映射,读写设备,23,1.4,用户模式驱动程序,适用范围及特点,测试新的硬件设备,测试一个新的设备是否可用,观察设备的工作情况,快速创建一个硬件应用,比如控制小马达的转动,点亮某个指示灯,范 围,特 点,优点:,1,)可以连接完整的,C,库,编程容易,2,)可以使用传统调试器,而不必调试内容,缺点:,1,)不支持设备中断,2,)不支持设备定时,24,1.4,用户模式驱动程序,I/O,映射,ioperm(),为用户应用程序打开一块,I/O,空间,iopl(),为用户应用程序打开整个,I/O,地址空间,MontaVista Linux,不支持,25,1.4,用户模式驱动程序,内存映射,通过设备,/dev/mem,来访问硬件设备,使用,mmap,(),函数来选择要访问的内存物理基址和块大小,它返回已经映射到物理基址的虚拟地址,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_AREA),PROT_WRITE,MAP_SHARED,fd,LED_ADDRESS);,*ledptr,=value;,26,1.4,用户模式驱动程序,读写设备,使用函数,inb(), inw(), inl,(),或,readb(), readw(), readl,(),来读设备,使用函数,outb(), outw(), outl,(),或,writeb(), writew(),writel,(),来写设备,它们的头文件是,27,2,中断处理,基本概述,探测中断,安装中断,取消中断,28,2.1,基本概念,分类,硬件中断,由硬件设备产生的中断,执行相应的中断处理程序,可以产生软中断,(tasklet,),来实现耗时的中断处理任务,也就是下半部中断,软中断(,softIRQ,),内核中共有,32,个,softIRQ,其中一个就是,TASKLET_SOFTIRQ,在内核执行,do_softirq,(),函数时,轮询这,32,个,softirq,,如果相应的,softirq,可以执行,就执行它指导的函数,TASKLET_SOFTIRQ,对应的函数是,tasklet_action,(),它会依次执行挂在,TASKLET_SOFTIRQ,上的,tasklet,29,2.1,基本概念,Read,执行流程,Process,read(),Device Driver,Top Half,(markbin),Dev_read(),Initiate transfer,Wait (time passes),Bottom,Half/Task,(resume),30,2.1,基本概念,中断处理程序举例,struct tasklet_struct my_tasklet,;,elsewhere, in some initialization section,tasklet_init(&my_tasklet, 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( /*queue the tasklet,*/,short_bh_count,+; /*record that an interrupt arrived*?,31,2.2,探测中断,1. probe_irq_on(void),返回一个,unsigned long,位掩码,2.,使设备发中断,3. probe_irq_oof(unsigned long),第一步返回的位掩码传给此函数,返回值即为探测到的中断号(如果为,0,或为负则没有可用中断),32,探测中断例子,unsigned long,mask=probe_irq_on,();,outb_p(0x10,short_base+2); /*enable reporting*/,outb_p(0x00,short_base); /*clear the bit*/,outb_p(0xFF,short_base); /*set the bit:interrupt,*/,outb_p(0x00,short_base+2); /*disable reporting*/,irq=probe_irq_off(mask,);,2.2,探测中断,33,安装,SIU,中断,SIU,中断向量表,16,个(,/include/asm-asm-ppc/irq.h,),外部中断,根据硬件连线确定,IRQ,号码,比如是,IRQ3,调用函数,request_8xxirq(SIU_IRQ3, my_handler, flag, devname, devpointer,),内部中断,选择一个未用的,LEVEL,号码,比如是,LEVEL3,调用函数,request_8xxirq(SIU_LEVEL3, my_handler, flag, devname, NULL),2.2,探测中断,34,安装,SIU,中断例子,#define CPM_INTERRUPTSIU_LEVEL2,(,在文件,irq.h,中定义),cpm_interrupt_init,(),函数中,*,(,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!”);,2.2,探测中断,35,安装,CPM,中断,CPM,中断向量表,32,个(,/arch/ppc/8xx_io/commproc.h),确定相应的中断向量,比如是,SCC1,调用函数,cpm_install_handler(CPMVEC_SCC1, scc1_handler, devpointer,),2.2,探测中断,例子,cpm_interrupt_init,(),函数中,*,(,/arch/ppc/8xx_io/commproc.c),/* Install our own error handler. */,cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);,36,取消中断,取消,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,),2.2,探测中断,中断处理程序任务,响应中断,查看中断状态寄存器,判断中断源,根据中断源进行相应处理,37,3,等待队列,概述,使用时机,请求暂不可用的资源,版本相关,(/linux/wait.h,),2.4,版以前使用结构体,wait_queue,2.4,版使用结构体,wait_queue_head_t,38,3,等待队列,主要函数,(/kernel/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, wait_queue_t,*new),remove_wait_queue(wait_queue_head_t *head, wait_queue_t,*old),39,3,等待队列,使用实例,情景:内核中有一块内存,在写时发现满了,首先在程序开始定义全局变量,strut wait_queue_head_t wqh,;,/struct wait_queue_t wq,;,或者使用宏,DECLARE_WAIT_QUEUE_HEAD(wqh,);,/DECLARE_WAITQUEUE(wq,current,);,在,write,函数中:,while(is_full,) ,interruptible_sleep_on(&wqh,);,/add_wait_queue(&wqh,Qwq,);,/current-state=TASK_interruptible,;,/schedule();,40,3,等待队列,使用实例,(,续,),write_to_buffer();,is_empty=0;,在,read,函数中:,if(!is_empty,) ,read_from_buffer,();,if_full,=0;,wake_up_interruptible(&wqh,);,41,4,定时处理,概述,数据结构,include/linux/timer.h,struct timer_list,struct timer_list,*next;,struct timer_list *prev,;,unsigned long expires;,unsigned long data;,void(*function)(unsigned loing,); ,42,4,定时处理,主要函数,初始化,timer,void init_timer(struct timer_list,*timer);,添加,timer,void add_timer(struct timer_list,*timer);,删除,timer,void del_timer(struct timer_list,*timer);,43,4,定时处理,使用实例,struct timer_list my_timer,;,init_timer(&my_timer,);,my_timer.function = my_timerfunc,;,my_timer.data = my_argu,;,my_timer.expires = jiffies+HZ,; /delay 1 sec,add_timer(my_timer,);,44,4,定时处理,等待队列和定时器综合实例,init_timer_out,;,struct timer_list,timer;,void timeout_func(unsigned,long who),timed_out,= 1;,debug(“Timing,outn”),wake_up_interruptible(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,;,45,4,定时处理,等待队列和定时器综合实例,timer.expires,= jiffies + timeout;,add_timer(&timer,);,debug(“going,to sleepn,”);,interruptible_sleep_on(wait,);,del_timer(&timer,);,if(timed_out,) ,timed_out,= 0;,return 1;,else return 0;,46,5,实例分析字符设备驱动程序,源程序,:mydriver.c mydriver.h,该程序是一个典型的模块方式字符设备驱动程序,该程序包含了中断,(,上下半部,),,时钟,等待队列 的处理例程,其特点在于用时钟中断来模拟硬件中断,47,5,实例分析字符设备驱动程序,函数列表,my_init_module(); mydriver_init,();,my_cleanup_module,();,mydriver_stop,();,mydriver_open(); mydriver_release,();,mydriver_timer_expiration,();,mydriver_interrupt(); mydriver_task,();,mydriver_read(); mydriver_write,(),48,5,实例分析字符设备驱动程序,程序分析,my_init_module(void,调用,mydriver_init,(),my_cleanup_module(void,),调用,mydriver_stop,(),注册设备,if(rc=unregister_chrdev(mydriver_major, mydriver_name, &my_fops):,初始化等待队列,Int_waitqueue_head(,取消设备注册,If(rc=unregister_chrdev(mydriver_major,mydriver_name),49,5,实例分析字符设备驱动程序,mydriver_open(pinode,pfile,),增加打开记数,mydriver_open_count,+,;,为文件的缓存区分配内存空间,mydriver_buffer,= (char *),kmalloc(MYDRIVER_BUFFERSIZE,GEP_KERNEL,);,初始化所分配的内存空间,memset(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,);,增加使用记数,MOD_INC_USE_COUNT;,50,5,实例分析字符设备驱动程序,mydriver_release(pinode,pfile,),增加释放记数,mydriver_release_count,+,;,删除定时器,if (rc=del_timer(&mydriver_timer,);,释放中断号,#ifndef,MYDRIVER_SIMULATE_INTERRUPT,free_irq(mydriver_irq,mydriver_name,);,释放用户缓存区内存空间,kfree(mydriver_buffer,);,增加使用记数,MOD_DEC_USE_COUNT;,51,5,实例分析字符设备驱动程序,mydriver_timer_expiration(mydriver_data,),说明,定义,MYDRIVER_SIMULATE_INTERRUPT,时才编译,其作用是用定时器来模拟硬件中断,增加定时器超时记数,mydriver_timer_count,+;,执行中断处理函数,mydriver_interupt( MYDRIVER_IRQ,(void*) mydriver_data,(NULL,);,52,5,实例分析字符设备驱动程序,mydriver_interrupt(irq,dev_id,fp,),增加中断记数,mydriver_interrup_count,+;,设置,I/O,成功标志,mydriver_final_status,=0;,初始化,tasklet,(,下半部),tasklet_init(&mydriver_tasklet, mydriver_task, (unsigned long) dev_id,);,调度,tasklet,(,下半部),tasklet_schedule(&mydriver_tasklet,);,mydriver_task(data,),唤醒等待队列,wake_up_interruptible(&mydriver_zz,);,53,5,实例分析字符设备驱动程序,mydriver_read(p,),增加读记数,mydriver_read_count,+;,给定时器赋值,并添加定时器,mydriver_timer.function=mydriver_timer_expiration,;,mydriver_timer.data,=0;,mydriver_timer.expires=jiffies+(MYDRIVER_IO_DURATION,*HZ);,add_timer(&mydriver_timer,);,睡眠在等待队列,mydriver_zz,上,interruptible_sleep_on(&mydriver_zz,);,54,5,实例分析字符设备驱动程序,mydriver_read(p,),续,处理异常情况,if (signal_pending(current,) ,del_timer(&mydriver_timer,);,printk(“ABNORMALLY,terminated:”);,正常读出数据,将数据拷贝给用户,返回读出的字节数,if (mydriver_final_status,= 0) ,if (copy_to_user(user_buf, mydriver_buffer, count) ,printk(“NORMALLY,TERMINATTED:”);,return mydriver_final_count,;,55,5,实例分析字符设备驱动程序,mydriver_write(p,),增加写记数,mydriver_write_count,+;,拷贝数据到文件缓存区,if (copy_from_user(mydriver_buffer, user_buf, count);,给定时器赋值,并添加定时器,与,read,中相同,睡眠在等待队列,mydriver_zz,上,interruptible_sleep_on(&mydriver_zz,);,56,5,实例分析字符设备驱动程序,mydriver_write(p,),续,处理异常情况,if (signal_pending(current,) ,del_timer(&mydriver_timer,);,printk(“ABNORMALLY,terminated:”);,正常写入数据,返回写入的字节数,if (mydriver_final_status,= 0) ,printk(“NORMALLY,TERMINATTED:”);,return mydriver_final_count,;,57,5,实例分析字符设备驱动程序,思考,如何将此模块方式驱动程序修改为内核方式驱动程序,?,58,6,实例分析网络设备驱动程序,源程序,enet.c commproc.h,Motorola MPC8xx,以太网驱动,在,SCCx,上实现以太网功能,59,6,实例分析网络设备驱动程序,函数列表,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,60,6.1,scc_enet_init(),调用路径,(/init/main.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, ,初始化数组,其中包含,scc_enet_init,(),初始化,net_device,结构的各个域,;,dev=init_etherdev(0,0),初始化,MPC860,的,parameter ram;,ep=(scc_enet_t *)(&cp-cp_dparamPROFF_ENET,);,61,6.1,scc_enet_init(),初始化,MPC860,的寄存器,immap=(immap_t,*)(_get_IMMR(),sccp=(volatile scc_t*) (&cp-cp_sccSCC_ENET,_;,初始化,buffer;,初始化,board;,设置并安装中断,;,sccp-scc_sccm,=(SCCE_ENET_TXE |,SCCE_ENET_RXF | SCCE_ENET_TXB);,cpm_inistall_handler(CPMVEC_ENET,scc_enet_interrupt, dev);,62,6.1,scc_enet_init(),将函数指针赋给,net_device,结构中相应的入口,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_list,;,63,6.2,实例分析网络设备驱动程序,scc_enet_open,更改,dev-state,域的指示位,netif_start_queue(dev,);,相当于下面的语句,clear_bit(_LINK_STATE_XOFF,&dev,-state);,scc_enet_close(dev,),更改,dev-state,域的指示位,netif_stop_queue(dev,);,相当于下面的语句,set_bit(_LINK_STATE_XOFF,&dev,-state);,64,6.3,scc_enet_start_xmit(skb,dev),当用户通过,enet,发送数据时,执行该函数,将,skb,中相应域的值赋给,bdp,(,即,cep-cur_tx,),的相应域,包长度,:bdp-cbd_datlen = skb-len,;,包数据指针,:bdp-cbd_vufaddr = _pa(skb,-data);,保存,skb,指针,cep-tx_skbuff cep-skb_cur = skb,增加统计域中的发送字节数,(cep-stats.tx_bytes+=skb-len,;);,将,cep-skb_cur,域加一,如果超过,TX_RING_SIZE,则置为,0,cep-skb_cur = (cep,-skb_cur+1) ,65,6.3,scc_enet_start_xmit(skb,dev),清理相应数据缓冲区中的内容,flush_dcache_range(unsigned long) (skb-data), (unsigned long) (skb-data+skb-len,),锁中断,spin_lock_irq(&cep,-lock);,开始发送,bdp-cbd_sc,|=(BD_ENET_TX_READY |BD_ENET_TX_TC);,66,6.3,scc_enet_start_xmit(skb,dev),设定发送开始时间,dep-trans_start,=jiffies;,调理,BD,指针,:,将,BD,的指针向下一个可用,BD,并判断发送缓冲区是否满,设置,cep-cur_tx,指针,cep-cur_tx= (cbd_t*)bdp,;,解锁中断,spin_unlock_irq(&cep,-lock);,67,6.4,scc_enet_rx(dev),当产生,RXF,中断,即收到帧后,执行,获取,cep,指针,cep=(struct scc_enet_private *)dev-priv,;,获取,bdp,指针,bdp= cep-cur_rx,;,检查收到的是否是完整帧,更新统计信息,为,skb,申请内存,skb,= dev_alloc_skb(pkt_len-4);,将,skb,与设备相关连,skb-dev = dev,;,68,6.4,scc_enet_rx(dev),在,skb,中分配,pkt_len-4,长度的空间,skb_put(skb,pkt_len-4); (skbuff.h,中,),将数据拷贝到,skb,中,eht_copy_and_sum(skb,(unsigned char *)_va(bdp-cbd_bufaddr),pkt_len-4;0); (etherdevice.h,中,),判断并获取协议的,ID,skb-protocol = eth_type_trans(skb,dev,); (,该函数在,eth.c,中,),将,skb,传送到上层,netif_rx(skb,);,设置,BD,进入,for,循环继续读取收到的包,如果,bd,为空,则退出循环,设置,cep-cur_rx,指针,cep-cur_rx = (cbd_t *) bodp,;,69,6.5,scc_enet_interrupt(dev_id,regs),当,CPMVEC_ENET,产生中断时,执行,获取,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,循环,70,6.5,scc_enet_interrupt(dev_id,regs),如果发送缓冲区满,则退出循环,if(bdp=cep-cur_tx) & (cep-tx_full,=0),break;,更新统计信息,;,出错重发,if (bdp-cbd_sc,& (BD_ENET_TX_LC |BD_ENET_TX_RL | BD_ENET_TXUN) ,must_restart,=1;,cep-stats.tx_errors,+;,释放,skb,内存空间,dev_kfree_skb_irq(cep-tx_skbuff cep-skb_dirty,);,71,6.5,scc_enet_interrupt(dev_id,regs),更新,cep-skb_dirty,指针,cep-skb_dirty = (cep-skb_dirty,+ 1) &,TX_RING_MOD_MASK:,break;,更新,bd,指针,;,如果,cep-tx_full,为,1,则将其设为,0,并唤醒相关进程,if (cep-tx_full) cep-tx_full,=0;,if(netif_queue_stopped(dev,),netif_wake_queue(dev,); ,更新,cep-dirty_tx,指针,cep-dirty_tx=(cbd_t *)bdp,;,结束,while,循环;,72,6.5,scc_enet_interrupt(dev_id,regs),如果,must_restart,为,1,,则重启动发送器,mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX)| CPM_CR_FLG;,解读写锁,spin_unlock(&cep,-lock);,处理忙中断:,if (int_events,& SCCE_ENET_BSY) ,cep-stats.rx_dropped,+;,73,7,用户与内核的接口,用户访问内核的途径:系统调用,基本概念,Linux,内核中设置的一组用于实现各种系统功能的子程序。,系统调用是,Linux,操作系统向用户程序提供支持的接口,通过接些接口应用程序向操作系统请求服务,控制转向操作系统,而操作系统在完成服务后,将控制和结果返回给用户程序。,定义在,源码目录,/include/asm-ppc/unistd.h,中,74,7.1,系统调用与函数调用,系统调用由操作系统核心提供,运行于核心态,普通的函数调用由函数库或用户自己提供,运行于用户态,都可以在用户的应用程序中使用,75,7.2,系统调用分类,与文件子系统交互的系统调用,Read(), write(), open(), close(), ioctl,(),与进程子系统交互的系统调用,进程控制系统调用,进程间通讯,存储管理,进程调度,系统调用的包含文件,#include,#include,对于特定的系统调用有时还需要相应的文件,比如对,setitimer(),就需要:,#include,76,7.3,实例,#include,#include,#include,#include,#include,#include,#include,#include,int,main(),new_timer.it_value.tv_sec,=10;,new_timer.it_value.tv_usec,=10;,new_timer.it_interval.tv_sec,=10;,new_timer.it_interval.tv_uses,=10;,setitimer(ITIMER_REAL,_,&new_timer, &old_timer,);,77,7.3,实验一,模块方式驱动程序,编译驱动程序,编译应用程序,加载模块,登记设备,运行应用程序,观察结果,78,7.3,实验二,内核方式驱动程序,修改模块方式驱动程序,修改相应配置文件,配置内核,编译内核,登记设备,运行应用程序,观察结果,79,E,N,D,THANK YOU!,T,H,E,80,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!