Linux驱动开发:USB驱动之usb-skel分析_第1页
Linux驱动开发:USB驱动之usb-skel分析_第2页
Linux驱动开发:USB驱动之usb-skel分析_第3页
Linux驱动开发:USB驱动之usb-skel分析_第4页
Linux驱动开发:USB驱动之usb-skel分析_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux驱动开发:USB驱动之usb_skel分析在学习了这么些天的驱动之后,个人觉得驱动就是个架构的问题,只要把架构弄清楚了然后往里面添砖加瓦就可以了,所以似乎看起来不是太困难,但也许是是我经验不足吧,这只能算是个人浅见了这两天在学习USB驱动开发,奇怪的是老师居然不讲USB的代码,让人不理解,后来在网上找资料才发现原来内核已经给我们准备了一个usb_skel的代码向我们介绍几本的USB驱动的架构,于是自己分析了一下代码,画了一个我认为的代码架构(比较难看),写了一些注释相关阅读:Linux驱动开发:网络设备之虚拟网卡

/Linux/2012-03/56415.htmLinux驱动开发:NandFlash时序图分析

/Linux/2012-03/56414.htmLinux驱动开发:网络设备之DM9000驱动架构分析

/Linux/2012-03/56416.htm废话不多说啦,直接上图上代码,请高手们批评指正!/*

*USBSkeletondriver-2.2

*

*Copyright(C)2001-2004GregKroah-Hartman(greg@)

*

*Thisprogramisfreesoftware;youcanredistributeitand/or

*modifyitunderthetermsoftheGNUGeneralPublicLicenseas

*publishedbytheFreeSoftwareFoundation,version2.

*

*Thisdriverisbasedonthe2.6.3versionofdrivers/usb/usb-skeleton.c

*buthasbeenrewrittentobeeasiertoreadanduse.

*

*/#include<linux/kernel.h>#include<linux/errno.h>#include<linux/init.h>#include<linux/slab.h>#include<linux/module.h>#include<linux/kref.h>#include<asm/uaccess.h>#include<linux/usb.h>#include<linux/mutex.h>/*Definethesevaluestomatchyourdevices*/#defineUSB_SKEL_VENDOR_ID0xfff0

//厂商ID#defineUSB_SKEL_PRODUCT_ID0xfff0

//产品ID/*tableofdevicesthatworkwiththisdriver*///驱动支持的USB设备列表staticstructusb_device_idskel_table[]={

{USB_DEVICE(USB_SKEL_VENDOR_ID,USB_SKEL_PRODUCT_ID)},

{},/*Terminatingentry*/};MODULE_DEVICE_TABLE(usb,skel_table);

/*topreventaracebetweenopenanddisconnect*/staticDEFINE_MUTEX(skel_open_lock);/*Getaminorrangeforyourdevicesfromtheusbmaintainer*/#defineUSB_SKEL_MINOR_BASE192

//USB主设备号/*ourprivatedefines.ifthisgrowsanylarger,useyourown.hfile*/#defineMAX_TRANSFER(PAGE_SIZE-512)/*MAX_TRANSFERischosensothattheVMisnotstressedbyallocations>PAGE_SIZEandthenumberofpacketsinapageisaninteger512isthelargestpossiblepacketonEHCI*/#defineWRITES_IN_FLIGHT8/*arbitrarilychosen*///8、usb_skel结构体可以被看作一个私有数据结构体,应该根据具体的设备量身定制structusb_skel{

structusb_device*udev;

//该设备的usb_device指针

structusb_interface*interface;

//该设备的usb_interface指针

structsemaphorelimit_sem;

//限制进程写的数据量

unsignedchar

*bulk_in_buffer;

//接收数据的缓冲区

size_tbulk_in_size;

//接收缓冲区大小

__u8bulk_in_endpointAddr;

//批量IN端点的地址

__u8bulk_out_endpointAddr;

//批量OUT端点的地址

structkrefkref;

//sturctkref作为内核中最基本的引用计数而存在

structmutexio_mutex;

//同步的IO互斥锁,保证};//5、声明一个USB骨架驱动结构体对象staticstructusb_driverskel_driver;

staticvoidskel_delete(structkref*kref){

structusb_skel*dev=to_skel_dev(kref);

usb_put_dev(dev->udev);

kfree(dev->bulk_in_buffer);

kfree(dev);}

staticintskel_open(structinode*inode,structfile*file){

structusb_skel*dev;

structusb_interface*interface;

intsubminor;

intretval=0;

subminor=iminor(inode);

//获取次设备号

mutex_lock(&skel_open_lock);

//上锁

interface=usb_find_interface(&skel_driver,subminor);

//获得接口数据

if(!interface){

mutex_unlock(&skel_open_lock);

//解锁

err("%s-error,can'tfinddeviceforminor%d",

__FUNCTION__,subminor);

retval=-ENODEV;

gotoexit;

}

dev=usb_get_intfdata(interface);

if(!dev){

mutex_unlock(&skel_open_lock);

retval=-ENODEV;

gotoexit;

}

/*incrementourusagecountforthedevice*/

kref_get(&dev->kref);

/*nowwecandropthelock*/

mutex_unlock(&skel_open_lock);

/*preventthedevicefrombeingautosuspended*/

retval=usb_autopm_get_interface(interface);

if(retval){

kref_put(&dev->kref,skel_delete);

gotoexit;

}

/*saveourobjectinthefile'sprivatestructure*/

file->private_data=dev;

exit:

returnretval;}

staticintskel_release(structinode*inode,structfile*file){

structusb_skel*dev;

dev=(structusb_skel*)file->private_data;

if(dev==NULL)

return-ENODEV;

/*allowthedevicetobeautosuspended*/

mutex_lock(&dev->io_mutex);

if(dev->interface)

usb_autopm_put_interface(dev->interface);

mutex_unlock(&dev->io_mutex);

/*decrementthecountonourdevice*/

kref_put(&dev->kref,skel_delete);

return0;}

staticssize_tskel_read(structfile*file,char*buffer,size_tcount,loff_t*ppos){

structusb_skel*dev;

intretval;

intbytes_read;

dev=(structusb_skel*)file->private_data;

mutex_lock(&dev->io_mutex);

if(!dev->interface){/*disconnect()wascalled*/

retval=-ENODEV;

gotoexit;}/*进行阻塞的批量读以从设备获取数据*/retval=usb_bulk_msg(dev->udev,usb_rcvbulkpipe(dev->udev,dev->bulk_in_endpointAddr),

dev->bulk_in_buffer,min(dev->bulk_in_size,count),&bytes_read,10000);/*如果读成功,复制到用户空间*/if(!retval){

if(copy_to_user(buffer,dev->bulk_in_buffer,bytes_read))

retval=-EFAULT;

else

retval=bytes_read;}exit:mutex_unlock(&dev->io_mutex);returnretval;}

/*当urb被成功传输到USB设备之后,urb回调函数将被USB核心调用,在我们的例子中,我们初始化urb,使它指向skel_write_bulk_callback函数*/staticvoidskel_write_bulk_callback(structurb*urb){

structusb_skel*dev;

dev=(structusb_skel*)urb->context;

/*sync/asyncunlinkfaultsaren'terrors*/

if(urb->status&&!(urb->status==-ENOENT||urb->status==-ECONNRESET||urb->status==-ESHUTDOWN)){

err("%s-nonzerowritebulkstatusreceived:%d",

__FUNCTION__,urb->status);

}

/*freeupourallocatedbuffer*/

usb_buffer_free(urb->dev,urb->transfer_buffer_length,

urb->transfer_buffer,urb->transfer_dma);

up(&dev->limit_sem);}

staticssize_tskel_write(structfile*file,constchar*user_buffer,size_tcount,loff_t*ppos){

structusb_skel*dev;

intretval=0;

structurb*urb=NULL;

char*buf=NULL;

size_twritesize=min(count,(size_t)MAX_TRANSFER);

dev=(structusb_skel*)file->private_data;

/*verifythatweactuallyhavesomedatatowrite*/

if(count==0)

gotoexit;

/*limitthenumberofURBsinflighttostopauserfromusingupallRAM*/

if(down_interruptible(&dev->limit_sem)){

retval=-ERESTARTSYS;

gotoexit;

}

/*创建一个urb,并且给它分配一个缓存*/

urb=usb_alloc_urb(0,GFP_KERNEL);

if(!urb){

retval=-ENOMEM;

gotoerror;

}

/*当urb被成功分配后,还要创建一个DMA缓冲区来以高效的方式发送数据到设备,传递给驱动程序的数据要复制到这块缓冲中去*/

buf=usb_buffer_alloc(dev->udev,writesize,GFP_KERNEL,&urb->transfer_dma);

if(!buf){

retval=-ENOMEM;

gotoerror;

}

if(copy_from_user(buf,user_buffer,writesize)){

retval=-EFAULT;

gotoerror;

}

/*thislockmakessurewedon'tsubmitURBstogonedevices*/

mutex_lock(&dev->io_mutex);

if(!dev->interface){

/*disconnect()wascalled*/

mutex_unlock(&dev->io_mutex);

retval=-ENODEV;

gotoerror;

}

/*当数据从用户空间正确复制到局部缓冲区后,urb必须在可以被提交给USB核心之前被正确初始化*/

usb_fill_bulk_urb(urb,dev->udev,

usb_sndbulkpipe(dev->udev,dev->bulk_out_endpointAddr),

buf,writesize,skel_write_bulk_callback,dev);

urb->transfer_flags|=URB_NO_TRANSFER_DMA_MAP;

/*把数据从批量OUT端口发出*/

retval=usb_submit_urb(urb,GFP_KERNEL);

mutex_unlock(&dev->io_mutex);

if(retval){

err("%s-failedsubmittingwriteurb,error%d",__FUNCTION__,retval);

gotoerror;

}

/*releaseourreferencetothisurb,theUSBcorewilleventuallyfreeitentirely*/

usb_free_urb(urb);

returnwritesize;

error:

if(urb){

usb_buffer_free(dev->udev,writesize,buf,urb->transfer_dma);

usb_free_urb(urb);

}

up(&dev->limit_sem);

exit:

returnretval;}

//字符设备的file_operations结构体,这个结构体中的成员实现staticconststructfile_operationsskel_fops={

.owner=THIS_MODULE,

.read=skel_read,

.write=skel_write,

.open=skel_open,

.release=skel_release,};/*

*usbclassdriverinfoinordertogetaminornumberfromtheusbcore,

*andtohavethedeviceregisteredwiththedrivercore

*/staticstructusb_class_driverskel_class={

.name="skel%d",

.fops

=&skel_fops,

.minor_base

=USB_SKEL_MINOR_BASE,};//7、探测函数skel_probe探测和断开:当一个设备被安装而USB核心认为该驱动程序应该处理时,探测函数被调用,探测函数检查传递给它的设备信息,确定驱动程序是否真的适合该设备。当驱动程序因为某种原因不应该控制设备时,断开函数被调用,它可以做一些清理工作。探测回调函数中,USB驱动程序初始化任何可能用于控制USB设备的局部结构体,它还把所需的任何设备相关信息保存到一个局部结构体中staticintskel_probe(structusb_interface*interface,conststructusb_device_id*id){

structusb_skel*dev;

//usb_skel设备

structusb_host_interface*iface_desc;

structusb_endpoint_descriptor*endpoint;

//端点描述符

size_tbuffer_size;

inti;

intretval=-ENOMEM;

/*allocatememoryforourdevicestateandinitializeit*/

dev=kzalloc(sizeof(*dev),GFP_KERNEL);

//分配设备状态的内存并初始化

if(!dev){

err("Outofmemory");

gotoerror;

}

kref_init(&dev->kref);

//初始化引用计数,设置为1

sema_init(&dev->limit_sem,WRITES_IN_FLIGHT);

//

mutex_init(&dev->io_mutex);

dev->udev=usb_get_dev(interface_to_usbdev(interface));

dev->interface=interface;

/*设置端点信息*/

/*只使用第一个批量IN和批量OUT端点*/

iface_desc=interface->cur_altsetting;

/*在探测函数里,这个循环首先访问该接口中存在的每一个端点,给该端点一个局部指针以便以后访问*/

for(i=0;i<iface_desc->desc.bNumEndpoints;++i){

endpoint=&iface_desc->endpoint[i].desc;

/*如果所有这些探测都通过了,驱动程序就知道它已经发现了正确的端点类型,可以把该端点的相关信息保存到一个局部结构体中以便稍后用它来和端点进行通信*/

if(!dev->bulk_in_endpointAddr&&usb_endpoint_is_bulk_in(endpoint)){

/*找到一个批量IN类型的端点*/

buffer_size=le16_to_cpu(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("Couldnotallocatebulk_in_buffer");

gotoerror;

}

}

if(!dev->bulk_out_endpointAddr&&usb_endpoint_is_bulk_out(endpoint)){

/*wefoundabulkoutendpoint*/

dev->bulk_out_endpointAddr=endpoint->bEndpointAddress;

}

}

if(!(dev->bulk_in_endpointAddr&&dev->bulk_out_endpointAddr)){

err("Couldnotfindbothbulk-inandbulk-outendpoints");

gotoerror;

}

/*因为USB驱动程序要在设备的生命周期的稍后时间获取和接口相关联的局部数据结构体,所以调用了usb_set_intfdata函数,把它保存到structusb_interface结构体中以便后面的访问*/

/*把数据指针保存到这个接口设备中*/

usb_set_intfdata(interface,dev);

/*我们以后调用usb_set_intfdata函数来获取数据。当这一切都完成后,USB驱动程序必须在探测函数中调用usb_register_dev函数来把该设备注册到USB核心里*/

/*注册设备到USB核心*/

retval=usb_register_dev(interface,&skel_class);

if(retval){

/*有些情况下是不允许注册驱动程序的*/

err("Notabletogetaminorforthisdevice.");

usb_set_intfdata(interface,NULL);

gotoerror;

}

/*lettheuserknowwhatnodethisdeviceisnowattachedto*/

info("USBSkeletondevicenowattachedtoUSBSkel-%d",interface->minor);

return0;

error:

if(dev)

/*thisfreesallocatedmemory*/

kref_put(&dev->kref,skel_delete);

returnretval;}

//9、骨架驱动断开函数staticvoidskel_disconnect(structusb_interface*interface){

structusb_skel*dev;

intminor=interface->minor;

/*preventskel_open()fromracingskel_disconnect()*/

mutex_lock(&skel_open_lock);

dev=usb_get_intfdata(interface);

usb_set_intfdata(interface,NULL);

/*givebackourminor*/

usb_deregister_dev(interface,&skel_class);

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论