云题海 - 专业文章范例文档资料分享平台

当前位置:首页 > 基于ARM9的嵌入式Linux系统研究及设备驱动程序的开发(兰州理工硕士论文)

基于ARM9的嵌入式Linux系统研究及设备驱动程序的开发(兰州理工硕士论文)

  • 62 次阅读
  • 3 次下载
  • 2026/1/8 7:45:20

基于ARM9的嵌入式Linux系统研究及设备驱动程序的开发38if(result)err(\failed.Error number%d\是USB注销函数,只有系统要注销USB驱动时才会使用这个函数。调用的时候,可以将与USB接口互联的设备全部断开,从而可以使内核能够注销掉这些无用的驱动。它的结构是这样的:static void__exit usb_skel_exit(void){/*从子系统注销驱动程序*/usb_deregister(&skel_driver);}探测和断开:如果有一个设备已经成功安装,此时USB核心恰好接受这个设备的请求时,驱动就会使用探测函数将这个设备的信息发送给USB核心,由核心来判断这个新安装的设备是否适用。而当驱动因为某种原因放弃设备的控制权之后,USB核心就会使用断开函数,用它来完成后续的清理工作。探测函数在工作中时,USB驱动为了能准备的调用USB设备时,其会将与调用相关的结构体全部进行初始化操作。探测函数会使用循环探测的方法来访问接口中的所有端点,并在每个端点访问的过程中加以局部指针,这样为后续的访问节省了很多时间,也提高了访问的速度。在第一轮探测完所有端点后,通过检查检查USB_DIR_IN来确定端点的末地址。如果所有这些探测都通过了,并且驱动程序已经发现了正确的端点类型,则使用一个结构体来保存该端点的所有信息,以便于以后和该端点通信:/*找到批量IN类型的端点

*/buffer_size=endpoint->wMaxPacketSize;dev->bulk_in_size=buffer_size;dev->bulk_in_endpointAddr=endpoint->bEndpointAddress;dev->bulk_in_buffer=kmalloc(buffer_size,GFP_KERNEL);if(!dev->bulk_in_buffer){err(\所有的USB设备响应时间都是有限的。而在这个有限时间内,驱动使用函数usb_set_intfdata来联系接口的信息。当这一切都完成后,USB驱动程序必须在探测函数中调用usb_register_dev函数来把该设备注册到USB核心里:

兰州理工硕士论文39/*注册设备到USB核心*/retval=usb_register_dev(interface,&skel_class);if(retval){/*有些情况下是不允许注册驱动程序的*/err(\当一个USB设备被断开时,和该设备相关联的所有资源都应该被尽可能的清理掉,在此时,如果已在在探测函数中调用了注册函数来为该USB设备分配了一个次设备号话,必须调用usb_deregister_dev函数来把次设备号交还给USB核心。在断开函数中,从接口获取之前调用usb_set_intfdata设置的任何数据也是很重要的。然后设置structusb_interface结构体中的数据指针为NULL,以防任何不适当的对该数据的错误访问。在探测函数中会对每一个接口进行一次探测,所以我们在写USB驱动程序的时候,只要做好第一个端点,其它的端点就会自动完成探测。在探测函数中我们要注意的是在内核中用结构体struct usb_host_endpoint来描述USB端点,这个结构体在另一个名为structusb_endpoint_descriptor的结构体中包含了真正的端点信息,structusb_endpoint_descriptor结构体包含了所有的USB特定的数据,该结构体中我们要关心的几个字段是:bEndpointAddress:这个是特定的USB地址,可以结合USB_DIR_IN和USB_DIR_OUT来使用,以确定该端点的数据是传向设备还是主机。bmAttributes:这个是端点的类型,这个值可以结合位掩码USB_ENDPOINT_XFERTYPE_MASK来使用,以确定此端点的类型是USB_ENDPOINT_XFER_ISOC(等时)、USB_ENDPOINT_XFER_BULK(批量)、USB_ENDPOINT_XFER_INT的哪一种。wMaxPacketSize:这个是端点一次可以处理的最大字节数,驱动程序可以发送数量大于此值的数据到端点,在实际传输中,数据量如果大于此值会被分割。bInterval:这个值只有在端点类型是中断类型时才起作用,它是端点中断请求的间隔时间,以毫秒为单位。提交和控制urb:当驱动要把数据传送到USB设备中,通过分

配urb的方式来实现数据的传输:urb=usb_alloc_urb(0,GFP_KERNEL);if(!urb){retval=-ENOMEM;

基于ARM9的嵌入式Linux系统研究及设备驱动程序的开发40goto error;}虽然驱动已经为urb分配了空间,但要想将数据成功的传送到缓冲区,还要通过创建并使用DMA缓冲区才能真正实现数据的收发。下面是部分传送代码:buf=usb_buffer_alloc(dev->udev,count,GFP_KERNEL,&urb->transfer_dma);if(!buf){retval=-ENOMEM;goto error;}if(copy_from_user(buf,user_buffer,count)){retval=-EFAULT;goto error;}当数据从用户空间正确复制到局部缓冲区后,urb必须在可以被提交给USB核心之前被正确初始化:/*初始化urb*/usb_fill_bulk_urb(urb,dev->udev,usb_sndbulkpipe(dev->udev,dev->bulk_out_endpointAddr),buf,count,skel_write_bulk_callback,dev);urb->transfer_flags|=URB_NO_TRANSFER_DMA_MAP;然后urb就可以被提交给USB核心以传输到设备了:/*把数据从批量OUT端口发出*/retval=usb_submit_urb(urb,GFP_KERNEL);if(retval){err(\submitting write urb,error%d\error;}当urb被成功传输到USB设备之后,urb回调函数将被USB核心调用,之后初始化urb,使其指向skel_write_bulk_callback函数,以下就是该函数:static void skel_write_bulk_callback(struct urb*urb,struct pt_regs*regs){ 兰州理工硕士论文41struct usb_skel*dev;dev=(struct usb_skel*)urb->context;if(urb->status&&!(urb->status==-ENOENT|urb->status==-ECONNRESET|urb->status==-ESHUTDOWN)){dbg(\write bulk status received:%d\释放已分配的缓冲区*/usb_buffer_free(urb->dev,urb->transfer_buffer_length,urb->transfer_buffer,urb->transfer_dma);}有时候USB驱动程序只是要发送或者接收一些简单的数据,驱动程序也可以不用urb来进行数据的传输,这是里涉及到两个简单的接口函数:usb_bulk_msg和usb_control_msg,在这个USB框架程序里读操作就是这样的一个应用:/*进行阻塞的批量读以从设备获取数据*/retval=usb_bulk_msg(dev->udev,usb_rcvbulkpipe(dev->udev,dev->bulk_in_endpointAddr),dev->bulk_in_buffer,min(dev->bulk_in_size,count),&count,HZ*10);/*如果读成功,复制到用户空间*/if(!retval){if(copy_to_user(buffer,dev->bulk_in_buffer,count))retval=-EFAULT;elseretval=count;}usb_bulk_msg接口函数的定义如下:int usb_bulk_msg(struct usb_device*usb_dev,unsigned int pipe,void*data,int len,int*actual_length,int timeout);其参数为:struct usb_device*usb_dev:指向批量消息所发送的目标USB设备指针。unsigned int pipe:批量消息所发送目标USB设备的特定端点,此值是调用

基于ARM9的嵌入式Linux系统研究及设备驱动程序的开发42usb_sndbulkpipe或者usb_rcvbulkpipe来创建的。void*data:如果是一个OUT端点,它是指向即将发送到设备的数据的指针。如果是IN端点,它是指向从设备读取的数据应该存放的位置的指针。int len:data参数所指缓冲区的大小。int*actual_length:指向保存实际传输字节数的位置的指针,至于是传输到设备还是从设备接收取决于端点的方向。int timeout:以Jiffies为单位的等待的超时时间,如果该值为0,该函数一直等待消息的结束。如果该接口函数调用成功,返回值为0,否则返回一个负的错误值。usb_control_msg接口函数定义如下:int usb_control_msg(struct usb_device*dev,unsigned intpipe,__u8request,__u8requesttype,__u16 value,__u16 index,void*data,__u16 size,int timeout)除了允许驱动程序发送和接收USB控制消息之外,usb_control_msg函数的运作和usb_bulk_msg函数类似,其参数和usb_bulk_msg的

参数有几个重要区别:struct usb_device*dev:指向控制消息所发送的目标USB设备的指针。unsigned int pipe:控制消息所发送的目标USB设备的特定端点,该值是调用usb_sndctrlpipe或usb_rcvctrlpipe来创建的。__u8 request:控制消息的USB请求值。__u8 requesttype:控制消息的USB请求类型值。__u16 value:控制消息的USB消息值。__u16 index:控制消息的USB消息索引值。void*data:如果是一个OUT端点,它是指身即将发送到设备的数据的指针。如果是一个IN端点,它是指向从设备读取的数据应该存放的位置的指针。__u16 size:data参数所指缓冲区的大小。int timeout:以Jiffies为单位的应该等待的超时时间,如果为0,该函数将一直等待消息结束。如果该接口函数调用成功,返回传输到设备或者从设备读取的字节数;如果不成功它返回一个负的错误值。这两个接口函数都不能在一个中断上下文中或者持有自旋锁的情况下调用,同样,该函数也不能被任何其它函数取消,使用时要谨慎。要给未知的USB设备写驱动程序,只需要把这个框架程序稍做修改就可以用了,把0xfff0这两个值改为未知USB的ID号。之后就是在探测函数中把需要探测的接口端点类型写好,在这个框架程序中只探测了批量(USB_ENDPOINT_XFER_BULK)IN和OUT端点,可以在此处使用掩码(USB_ENDPOINT_XFERTYPE_MASK)让其探测其它的端点类型,驱动程序会对USB设备的每一个接口进行一次探测,当探测成功后,驱动程序就被绑

兰州理工硕士论文43定到这个接口上。再有就是urb的初始化问题,如果你只写简单的USB驱动,这块不用多加考虑,框架程序里的东西已经够用了。还有一个初始化等时urb的,在被提交到USB核心前,必须在驱动程序中手工地进行初始化,可以参考内核源代码树下的/usr/src/~/drivers/usb/media下的konicawc.c文件。现在驱动程序已经大体写好了,然后在linux下把它编译成模块就可以把驱动模块插入到内核中运行了,编译的Makefile文件可以这样来写:ifneq($(KERNELRELEASE),)obj-m:=xxx.oelseKERNELDIR?=/lib/modules/$(shell uname-r)/buildPWD:=$(shell

pwd)default:$(MAKE)-C$(KERNELDIR)M=$(PWD)modulesendifclean:rm-rf*.mod.**.o*.ko.*.ko.*.tmp*.*.mod.o.*.*.o.*其中xxx是源文件的文件名,在linux下直接执行make就可以生成驱动模块(xxx.ko)了。生成驱动模块后使用insmodxxx.ko就可以插入到内核中运行了,lsmod命令可以查看已经嵌入到内核中的模块的具体名称,也可以用命令rmmod把模块卸载掉;如果把编译出来的驱动模块拷贝/lib/modules/~/kernel/drivers/usb/下,然后depmod一下,那么你在插入USB设备的时候,系统就会自动加载驱动模块的,可以看到驱动程序已经绑定到接口上。图4.4 USB挂载图

基于ARM9的嵌入式Linux系统研究及设备驱动程序的开发444.4网络驱动设计4.4.1 DM9000结构分析本平台采用了DM9000网卡芯片,这是一个集成度较高的低功耗、高性能的以太网控制芯片,其采用LQFP48管教封装,与MCU连接有8bit/16bit模式,支持3.3V和5V的I/O控制,内置AUTOMDI-X功能10/100M PHY支持多种连接模式,并且配备了标准的10/100M自适应、16K大容量的FIFO、4路多功能GPIO、掉电和全双工等功能。其结构图如下所示MemoryManagementInternalSRAMPorcessornIetfraceAUTONegotiationMII Mangementcontrol&RegisterEEPROMTX-MachineControl&Status RegisterRX-MachineMII100 Base-TXTranseciver100Base-TXPCSAUTO-MDIX100Base-TXTx/Rx图4.5 DM9000结构框图4.4.2 Dm9000驱动移植过程1.在内核编译配置选项中,driver-->net-->10/100M net-->DM9000 support选项选中。2.在arch/arm/mach-s3c2410/devs.c中添加dm9000的platform_device。3.在arch/arm/mach-s3c2410/devs.h中声明平台设备eievk_dm9000_device:4.在arm/arm/mach-s3c2410/mach-smdk2410.c中将eievk_dm9000_device添加到平台设备列表中:static struct

platform_device*smdk2440_devices[]__initdata={&s3c_device_usb,&s3c_device_lcd,&s3c_device_wdt,&s3c_device_i2c,&s3c_device_iis,&eievk_dm9000_device,//add dm9000 by beelike

兰州理工硕士论文45&s3c_device_nand,};5.此时Dm9000设备已经成功注册进入驱动核心。下面进入driver/net/dm9000.C中,还需要做两方面的工作:设置芯片MAC地址,使能DM9000的中断。根据开发板的特点,设置以下的内容:1)GPFCON(56000050)GPF7[15:14]置10,功能设置为EINT7。这可以用函数实现:s3c2410_gpio_cfgpin(S3C2410_GPF7,S3C2410_GPF3_EINT7);2)EXTINT0(56000088)[30:28]置0低电平触发中断3)外部中断屏蔽寄存器。EINTMASK(560000a4)[7]置0以enable interrupt EINT74)全局中断屏蔽寄存器INTMASK(4A000008)[4]置0使能EINT4_7。代码修改:在dm9000.C的开始添加如下定义:/********************beelike add********************/#includestatic char net_mac_addr[]={0x00,0xe0,0x3d,0xf4,0xdd,0xf7};//MACstatic

void*extint0,*intmsk,*eintmsk;#define EINTMASK(0x560000a4)//外部中断屏蔽#define EXTINT0(0x56000088)//外部中断方式#define INTMSK(0x4A000008)//中断屏蔽/*******************end add***********************/在dm9000.C中dm9000_probe(struct platform_device*pdev)中适当位置(设置MAC之后,register_netdevice()之前)添加如下代码:/***********beelike add********/for(i=0;i<6;i++){ndev->dev_addr[i]=net_mac_addr[i];}extint0=ioremap_nocache(EXTINT0,4);//intmsk=ioremap_nocache(INTMSK,4);eintmsk=ioremap_nocache(EINTMASK,4);s3c2410_gpio_cfgpin(S3C2410_GPF7,S3C2410_GPF7_EINT7);writel(readl(extint0)&0x8fffffff,extint0);//eint7 low levelwritel(readl(intmsk)&(~(1<<4)),intmsk);//writel(readl(extint0)&(~(1<<7)),extint0);iounmap(intmsk);iounmap(extint0);

基于ARM9的嵌入式Linux系统研究及设备驱动程序的开发46iounmap(eintmsk);/******************end*********/编译下载之后,启动内核后:图4.6目标板IP配置图图4.7网络连接测试图4.4.3 Dm9000驱动简要分析1.定义DM9000的platform_device,并为platform_data分配资源。2.在实验平台的列表中增加platform_device这个数据结构。3.在DM9000.C中,重新指定该芯片的驱动程序static struct platform_driver dm9000_driver={.driver={.name=\emove=dm9000_drv_remove,.suspend=dm9000_drv_suspend,

兰州理工硕士论文47.resume=dm9000_drv_resume,};4.在内核中加载module_init(dm9000_init)这个初始化程序,用来注册DM9000的驱动。5.定义了board_info这个数据结构,其主要功能是存储和芯片相关的信息,包括占用资源的大小、如何实现读写操作等等。6.模块初始化函数最终将调用probe函数。这个函数完成的基本过程:(1)分配网络设备号ndev=alloc_etherdev(sizeof(struct board_info));(2)从内核中分配设备所需要的资源空间:db->addr_res=platform_get_resource(pdev,IORESOURCE_MEM,0);db->data_res=platform_get_resource(pdev,IORESOURCE_MEM,1);db->irq_res=platform_get_resource(pdev,IORESOURCE_IRQ,0);(3)在内核的映射中申请资源,并保存映射地址:db->addr_req=request_mem_region(db->addr_res->start,i,pdev->name);db->data_req=request_mem_region(db->data_res->start,iosize,pdev->name);db->io_addr=ioremap(db->addr_res->start,i);db->io_data=ioremap(db->data_res->start,iosize);(4)根据DM9000的数据宽度来设置读写数

  • 收藏
  • 违规举报
  • 版权认领
下载文档10.00 元 加入VIP免费下载
推荐下载
本文作者:...

共分享92篇相关文档

文档简介:

基于ARM9的嵌入式Linux系统研究及设备驱动程序的开发38if(result)err(\failed.Error number%d\是USB注销函数,只有系统要注销USB驱动时才会使用这个函数。调用的时候,可以将与USB接口互联的设备全部断开,从而可以使内核能够注销掉这些无用的驱动。它的结构是这样的:static void__exit usb_skel_exit(void){/*从子系统注销驱动程序*/usb_deregister(&skel_driver);}探测和断开:如果有一个设备已经成功安装,此时USB核心恰好接受这个设备的请求时,驱动就会使用探测函数将这个设备的信息发送给USB核心,由核心来判断这个新安装的设备是否适用。而当驱动因为某种原因放弃设备的控制权之后,USB核心就会使用断开函数,用它来完成后续的清理工作。探测函数在工作中时,USB驱动为了能准备

× 游客快捷下载通道(下载后可以自由复制和排版)
单篇付费下载
限时特价:10 元/份 原价:20元
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:fanwen365 QQ:370150219
Copyright © 云题海 All Rights Reserved. 苏ICP备16052595号-3 网站地图 客服QQ:370150219 邮箱:370150219@qq.com