USB驱动程序源代码

合集下载

USB转串口驱动代码分析

USB转串口驱动代码分析

USB转串口驱动代码分析分类:window xp 驱动(USB)/FireFox插件/汇编2012-08-09 15:55 3467人阅读评论(1) 收藏举报代码分析extensioninterfacebufferresourcesio/chenyujing1234/article/details/7843836目录(?)[+]1、USB插入时,创建设备[plain]view plaincopy1.DriverObject->DriverExtension->AddDevice = USB2COM_PnPAddDevice;步一、调用USB2COM_CreateDeviceObject创建功能设备对象(FDO)(1)IoCreateDevice系统API的原理为:[plain]view plaincopy1.NTKERNELAPI2.NTSTATUS3.IoCreateDevice(4. IN PDRIVER_OBJECT DriverObject,5. IN ULONG DeviceExtensionSize,6. IN PUNICODE_STRING DeviceName OPTIONAL,7. IN DEVICE_TYPE DeviceType,8. IN ULONG DeviceCharacteristics,9. IN BOOLEAN Reserved,10. OUT PDEVICE_OBJECT *DeviceObject11. );在之前真实的USB驱动中我们是这样创建的:[cpp]view plaincopy1.ntStatus = IoCreateDevice(2. DriverObject, // our driver object3.sizeof(DEVICE_EXTENSION), // extension size for us4. NULL, // name for this device5. FILE_DEVICE_UNKNOWN,6. FILE_AUTOGENERATED_DEVICE_NAME, // device characteristics7. FALSE, // Not exclusive8. &deviceObject); // Our device object就是第三个参数为NULL,第四个参数为FILE_DEVICE_UNKNOWN,意味着我们驱动想附加的设备是空的,且未知。

USB驱动程序编写

USB驱动程序编写

USB驱动程序编写linux‎下usb驱动编写(内核2.4)—‎—2.6与此接口有区别2006-‎09-15 14:57我们知道了‎在Linux下如何去使用一些最常‎见的USB设备。

但对于做系统设计‎的程序员来说,这是远远不够的,我‎们还需要具有驱动程序的阅读、修改‎和开发能力。

在此下篇中,就是要通‎过简单的USB驱动的例子,随您一‎起进入USB驱动开发的世界。

‎USB骨架程序(usb-ske‎l eton),是USB驱动程序的‎基础,通过对它源码的学习和理解,‎可以使我们迅速地了解USB驱动架‎构,迅速地开发我们自己的USB硬‎件的驱动。

USB驱动开发‎在掌握了USB设备的配置后,‎对于程序员,我们就可以尝试进行一‎些简单的USB驱动的修改和开发了‎。

这一段落,我们会讲解一个最基础‎U SB框架的基础上,做两个小的U‎S B驱动的例子。

USB骨架‎在Linux kernel‎源码目录中driver/usb/‎u sb-skeleton.c为我‎们提供了一个最基础的USB驱动程‎序。

我们称为USB骨架。

通过它我‎们仅需要修改极少的部分,就可以完‎成一个USB设备的驱动。

我们的U‎S B驱动开发也是从她开始的。

‎那些linux下不支持的USB‎设备几乎都是生产厂商特定的产品。

‎如果生产厂商在他们的产品中使用自‎己定义的协议,他们就需要为此设备‎创建特定的驱动程序。

当然我们知道‎,有些生产厂商公开他们的USB协‎议,并帮助Linux驱动程序的开‎发,然而有些生产厂商却根本不公开‎他们的USB协议。

因为每一个不同‎的协议都会产生一个新的驱动程序,‎所以就有了这个通用的USB驱动骨‎架程序,它是以pci 骨架为模‎板的。

如果你准备写一个li‎n ux驱动程序,首先要熟悉USB‎协议规范。

USB主页上有它的帮助‎。

一些比较典型的驱动可以在上面发‎现,同时还介绍了USB urbs‎的概念,而这个是usb驱动程序中‎最基本的。

单片机USB模拟U盘源码

单片机USB模拟U盘源码

单片机USB模拟U盘源码虽然现在成品U盘的成本已经非常低,但是单片机系统中模拟U盘还是有些场景会应用到,比如:①代替传统光盘,为用户提供说明书、驱动软件等(直接存储在产品中)②U盘数据监控、截取和加密等(定制U盘)③采集数据暂存,方便传输给主机下文是根据masstorage和Bulk-Only传输协议,使用CH559实现模拟U盘的功能(容量大小由选择的外部存储芯片决定),用以实现数据转存或定制U盘功能。

关键点在于USB 设备模式初始化、扇区读写和外部存储芯片的操作。

一、总体概述模拟U盘关键功能部件包括以下几点:(1)、具有USB设备功能的MCU或接口芯片,此例中CH559有2个USB主机接口和1个USB设备接口。

(2)、根据实际需要或者接口选择合适的外部存储来作为U盘的存储空间,比如SPI的串行Flash、E2PROM,甚至是Nand Flash等。

以上准备完毕整体的操作流程如下所示:二、硬件电路CH559模拟U盘使用的SPI接口的串行Flash,硬件如下图:CH559是增强型51内核的单片机,内置晶振,所以芯片外围也足够简洁。

芯片资源如下图:三、软件编写软件主要包括以下方面:(1)、USB设备模式初始化(2)、存储芯片接口初始化(3)Bulk_Only传输CBW包:CSW包:四、可拓展功能(1)、其他存储介质:除了以上提到的SPI接口的串行Flash,也可以替换成E2PROM或者Nand falsh等。

(2)、数据来源可以随意指定,比如串口数据流,并口数据流,甚至其他温湿度传感器设备等。

(3)、CH559+SPI串行Flash模拟U盘测试参数CH563模拟U盘源码.rar559模拟U盘源码.rar五、源码分享CH559模拟U 盘的源代码(C 语言):CH563模拟U 盘的源代码(C 语言):。

WindowsCE下USB摄像头驱动开发以OV511为例附带全部源代码以及讲解

WindowsCE下USB摄像头驱动开发以OV511为例附带全部源代码以及讲解

Windows 下 USB设备接口的枚举和保存
USB主设备身很复杂,但方便在提供了统一的接口方式,使得驱动程序在使 用设备的时候,工作简化到了类似操作串行接口。 USB设备可以看作提供了多个串口的设备,依据USB的规范,我们将每个串 口称作端点(Endpoint),要和这个端点通信,我们就要打开到这个端点的连接, 这个连接就是管道(Pipe)。
驱动加载完成后,用户程序再用CreateFile打开设备的 时候,将返回驱动程序上下文给用户程序,这样用户程序和 驱动就可以交互了,并且这个驱动程序上下文是含有该USB 设备相关信息的,所以,可以使用USBD函数来操作USB设 备,并且将USB设备的数据返回给应用程序。
Windows 下 流接口USB驱动程序卸载的流程
Windows 下 USB设备接口的枚举和保存
OV511+这8个Interface设置见Datasheet USBDeviceAttach函数中,通过ParseStreamInterfaces函数来保 存这些Interface。详细内容的参见代码。 主要结构如下:
for (i = 0; i < lpUsbDev->lpConfigs->dwNumInterfaces; i++) { lpIF = &lpUsbDev->lpConfigs->lpInterfaces[i]; if ((lpIF->Descriptor.bInterfaceClass == bIFStrm) && (lpIF->Descriptor.bInterfaceSubClass == bIFSubStrm)) { //保存接口 } }
OV511通过端点0来控制其寄存器。 Linux中,写寄存器函数如下:

USB驱动开发实例

USB驱动开发实例

USB驱动开发实例本节具体介绍如何进行USB驱动的开发,本节采用的源码来源自DDK的源程序,其位置在DDK子目录的src\wdm\usb\bulkusb目录下。

该示例很全面地支持了即插即用IRP的处理,也很全面地支持了电源管理,同时很好地支持了USB设备的bulk读写。

如果从头开发USB驱动,往往很难达到USB驱动的稳定性,所以强烈建议读者在此驱动修改的基础上进行USB驱动开发。

1 功能驱动与物理总线驱动DDK已经为USB驱动开发人员提供了功能强大的USB物理总线驱动(PDO),程序员需要做的事情是完成功能驱动(FDO)的开发。

驱动开发人员不需要了解USB如何将请求转化成数据包等细节,程序员只需要指定何种管道,发送何种数据即可。

当功能驱动想向某个管道发出读写请求时,首先构造请求发给USB总线驱动。

这种请求是标准的USB请求,被称为URB(USB Request Block),即USB请求块。

这种URB被发送到USB物理总线驱动以后,被USB总线驱动所解释,进而转化成请求发往USB HOST 驱动或者USB HUB驱动,如图17-21所示。

图17-21 总线驱动与功能驱动的关系可以看出,USB总线驱动完成了大部分工作,并留给USB功能驱动标准的接口,即URB请求。

USB驱动开发人员只需要根据不同的USB设备的设计要求,在相应的管道中发起URB 请求即可。

2. 构造USB请求包USB驱动在与USB设备通信的时候,如在控制管道中获取设备描述符、配置描述符、端点描述符,或者在Bulk管道中获取大量数据,都是通过创建USB 请求包(URB)来完成的。

URB中填充需要对USB的请求,然后将URB作为IRP的一个参数传递给底层的USB总线驱动。

在USB总线驱动中,能够解释不同URB,并将其转化为USB总线上的相应数据包。

DDK提供了构造URB的内核函数UsbBuildGetDescriptorRequest,其声明如下:VOID UsbBuildGetDescriptorRequest(IN OUT PURB Urb,IN USHORT Length,IN UCHAR DescriptorType,IN UCHAR Index,IN USHORT LanguageId,IN PVOID TransferBuffer OPTIONAL,IN PMDL TransferBufferMDL OPTIONAL,IN ULONG TransferBufferLength,IN PURB Link OPTIONAL);z Urb:用来输出的URB结构的指针。

USB驱动开发

USB驱动开发

第17章USB设备驱动USB设备驱动和PCI设备驱动是PC中最主要的两种设备驱动程序。

与PCI协议相比,USB协议更复杂,涉及面较多。

本章将介绍USB设备驱动开发。

首先介绍USB协议,使读者对USB协议有个整体认识。

然后介绍USB设备在WDM中的开发框架。

由于操作系统的USB总线驱动程序提供了丰富的功能调用,因此开发USB驱动开发变得相对简单,只需要调用USB总线驱动接口。

17.1 USB总线协议USB总线协议比PCI协议复杂的多,涉及USB物理层协议,又涉及USB传输层协议等。

对于USB驱动程序开发者来说,不需要对USB协议的每个细节都很清楚。

本节概要地介绍USB总线协议,并对驱动开发者需要了解的地方进行详细介绍。

17.1.1 USB设备简介USB即通用串行总线(Universal Serial Bus),是一种支持即插即用的新型串行接口。

也有人称之为“菊链(daisy-chaining)”,是因为在一条“线缆”上有链接127 个设备的能力。

USB要比标准串行口快得多,其数据传输率可达每秒4Mb~12Mb(而老式的串行口最多是每秒115Kb)。

除了具有较高的传输率外,它还能给外围设备提供支持。

需要注意的是,这不是一种新的总线标准,而是计算机系统连接外围设备(如键盘、鼠标、打印机等)的输入/输出接口标准。

到现在为止,计算机系统连接外围设备的接口还没有统一的标准,例如,键盘的插口是圆的、连接打印机要用9针或25针的并行接口、鼠标则要用9针或25针的串行接口。

USB能把这些不同的接口统一起来,仅用一个4针插头作为标准插头,如图17-1所示。

通过这个标准插头,采用菊花链形式可以把所有的外设连接起来,并且不会损失带宽。

USB正在取代当前PC上的串口和并口。

第17章 USB 设备驱动431图17-1 USB 的四条传输线以USB 方式连接设备时,所有的外设都在机箱外连接,连接外设不必再打开机箱;允许外设热插拔,而不必关闭主机电源。

WINCE下USB驱动程序

WINCE下USB驱动程序

如何编写WINDOWS 的USB驱动程序发表:不详阅读:226次关键字:字体:[大中小]随着USB设备的普及,摆在开发人员面前的驱动开发任务也是越来越繁重了,特别是对于一些嵌入式开发厂商来讲,由于设备所采用的操作系统不同,相应的硬件接口也是不一样的,开发相关的USB驱动程序更是难上加难。

Windows 是微软推出的功能强大的嵌入式操作系统,国内采用此操作系统的厂商已经很多了,本文就以windows 为例,简单介绍一下如何开发windows 下的USB驱动程序。

首先要熟悉一些USB的基本概念,当然最好把USB 1.1的协议看一遍,(当然现在2。

0的协议都已经有了) 上可以下载,我记得好像有个中文版的,翻译的还可以,上有的,具体位置记不太清楚了,中文版的协议可以快速翻一边,了解一些基本的概念,但是设计到一些关键性的东西最好还是看英文版的心里比较清楚些。

这里我就不介绍USB的基本协议了,假设用户已经熟悉了USB设备的一些基本的概念,并且对Winows 的开发有一定的了解。

下面简略介绍一下Windows 中USB设备驱动开发的一些基础知识。

Windows 的USB系统软件分为两层: USB Client设备驱动程序和底层的Windows CE 实现的函数层。

USB设备驱动程序主要负责利用系统提供的底层接口配置设备,和设备进行通讯。

底层的函数提本身又由两部分组成,通用串行总线驱动程序(USBD)模块和较低的主控制器驱动程序(HCD)模块。

HCD负责最最底层的处理,USBD模块实现较高的USBD函数接口。

USB设备驱动主要利用USBD接口函数和他们的外围设备打交道。

USB设备驱动程序主要和USBD打交道,所以我们必须详细的了解USBD提供的函数。

主要的传输函数有:AbourtTransfer IssueControlTransferCloseTransfer IssueInterrupTransferGetIsochResult IssueIsochTransferGetTransferStatus IstransferCompleteIssueBulkTransfer IssueVendorTransfer主要的用于打开和关闭USBD和USB设备之间的通信通道的函数有:AbortPipeTransfers ClosePipeIsDefaultPipeHalted IsPipeHaltedOpenPipe ResetDefaultPipeResetPipe相应的打包函数接口有:GetFrameLength GetFrameNumber ReleaseFrameLengthControl SetFrameLength TakeFrameLengthControl取得设置设备配置函数:ClearFeature SetDescriptorGetDescriptor SetFeatureGetInterface SetInterfaceGetStatus SyncFrame与USB进行交互的实现方法相关的多任务函数:FindInterface RegisterClientDeviceIdGetDeviceInfo RegisterClientSettingsGetUSBDVersion RegisterNotificationRoutine LoadGenericInterfaceDriver TranslateStringDescrOpenClientRegisterKey UnRegisterNotificationRoutine常见的Windows 下USB的设备驱动程序的编写有以下几种方法:● 流式接口函数这种驱动程序主要呈现流式函数接口,主要输出XXX_Init,XXX_Deinit,XXX_Open,XXX_Close,XXX_Open,XXX_Close,XXX_Read,XXX_Write, XXX_Seek,XXX_IOControl,XXX_PowerUp,XXX_PowerDown等流式接口,注意上述的几个接口一定都要输出,另外XXX必须为三个字符,否则会出错。

USB源代码

USB源代码
//该用途是未定义的,如果使用该用途来开集合,那么系统将不会把它
//当作标准系统设备,从而就成了一个用户自定义的HID设备。
0x09, 0x00, // USAGE (0)
//这是一个主条目(bType为0)条目,开集合,后面跟的数据0x01表示
//该集合是一个应用集合。它的性质在前面由用途页和用途定义为
//这是一个全局条目,说明逻辑值最大为255。
0x25, 0xff, // LOGICAL_MAXIMUM (255)
//这是一个局部条目,说明用途的最小值为1。
0x19, 0x01, // USAGE_MINIMUM (1)
//这是一个局部条目,说明用途的最大值8。
//注意小端模式,低字节应该在前。
0xE1,
0x05,
//bcdDevice字段。设备版本号,取1.0版,即0x0100。
//小端模式,低字节在先。
0x00,
0x01,
//iManufacturer字段。厂商字符串的索引值,为了方便记忆和管理,
//字符串索引就从1开始吧。
0x10,
//idVender字段。厂商ID号,我们这里取0x8888,仅供实验用。
//实际产品不能随便使用厂商ID号,必须跟USB协会申请厂商ID号。
//注意小端模式,低字节在先。
0xC0,
0x16,
//idProduct字段。产品ID号,由于是第六个实验,我们这里取0x0006。
0x29, 0x08, // USAGE_MAXIMUM (8)
//这是一个全局条目,说明数据域的数量为八个。
0x95, 0x08, // REPORT_COUNT (8)

STM32 USB的JMouse源代码分析 1-3

STM32 USB的JMouse源代码分析 1-3

USB的“JoyStickMouse”源代码分析01一、c源文件和头文件1、c文件的组织我们一般用C语言编程的时候都比较讲究模块化、层次化,以及数据和操作分开的原则。

模块化最明显的表现是我们把常用的、某一个具体功能实现封装在一个函数中,我们所要操作的数据以参数的方式提供给函数,函数通过代码处理过后,再把结果回馈个调用者。

层次化表现在比较复杂的功能实现都要分几层来实现,有时候也是为了提高可移植性。

比如文件系统的代码实现大致要分这么几层:磁盘操作层实现磁盘扇区的读取、写入、控制;文件分配管理函数和目录项操作函数;文件的打开、读取、写入函数,目录的建立、删除函数等;用户应用操作函数,如文件的查找、具体数据的写入等等。

一个具体USB功能的实现也能分成几层,比如我们的Stm32 JoyStickMouse,我们也可以这样分层:硬件操作层:寄存器操作和内存操作。

协议通用层:设备枚举的控制传输实现,对所有类协议都一样。

具体协议层:比如HID协议的描述符,类特定请求实现。

这样一划分,一个具体的功能实现就需要比较多的C源文件。

2、c文件和h文件一个c文件一般是几个函数组成,这几个函数可能一部分存在依存关系,而有一些函数要对外引出,而同时它还可能要引用外部函数。

解决这个相互关联的是“包含头文件”。

一个c文件很多时候都存在一个与它同名的“h文件”,对c文件的意义主要有以下几个:(1)提供常量定义,#define。

(2)提供一些类型定义,为了实现c文件数据类型的编译器无关性,一般都要将该编译器提供的数据类型重新定义,用tpyedef来实现。

(3)结构体、联合体、枚举类型的定义。

(4)带参数的宏定义。

(5)外部函数声明。

(6)外部变量声明。

(7)本身实现函数的声明:起始这个声明对c文件本身意义不大,主要是其它c 文件要使用本c文件实现的函数时,包含同名“h文件”,意义更清楚一些。

3、h文件的相互包含头文件对c源文件的意义比较清晰。

(简易USB驱动)开发指导

(简易USB驱动)开发指导

实验七(2)设备驱动开发指导块设备种类多,使用广泛,其驱动程序的开发也比字符设备复杂。

通过本实验,大家要开发一个实际块设备(U盘)的驱动程序,将能够更深入地掌握块设备驱动程序的开发方法。

Linux下已经有一个通用的U盘驱动程序usb-storage.o,其源程序放在目录drivers\usb\storage下(相对于内核源码根目录)。

但这个驱动的实现相当复杂,本实验希望开发一个相对简单些的U盘驱动程序,不求高性能,只求结构明朗、清晰易懂,主要是让大家掌握一个实际块设备的驱动方式,从而加深理解。

事实上,本实验开发的驱动程序应该能够适用于所有基于Bulkonly传输协议的USB大容量存储设备(USB Mass Storage),比如USB移动硬盘和USB外置光驱,USB闪存盘(U 盘)只是其中的一种。

由于USB大容量存储设备具有容量大、速度快、连接灵活、即插即用、总线供电等优点,它们得到了广泛使用,掌握这类设备驱动程序的开发技术无疑具有很强的实用性。

实验内容编写一个U盘驱动程序myudisk,只要求能够驱动某个型号的U盘,能够支持U盘的常规操作,如命令hexdump、mke2fs和mount等。

同时,要求在系统内核日志中显示出U盘的容量。

若有余力,可增加多分区支持功能。

实验基础和思路在教材中P130,讲解了如何编写一个Ramdisk块设备驱动程序(sbull.c),称为radimo;在文献《Linux Device Drivers》讲解了如何编写一个USB设备驱动程序,并以Linux源代码中的usb-skeleton.c为例。

虽然前者驱动的并不是一个实际的块设备,且后者又只是针对usb字符设备,但是它们提供了一个不错的基础,通过合并我们就能基本得到一个支持usb块设备的驱动程序。

之所以说基本得到,是因为合并后只是有了块设备、USB设备的驱动支持框架,但还缺一样:对U盘(USB块设备)的实际访问操作。

官方USB程序和例程

官方USB程序和例程

官方USB程序和例程一、USB的“JoyStickMouse”例程结构分析1、例程的结构(1)底层结构包括5个文件:usb_core.c(USB总线数据处理的核心文件),usb_init.c,usb_int.c(用于端点数据输入输入中断处理),usb_mem.c(用于缓冲区操作),usb_regs.c(用于寄存器操作)。

它们都包含了头文件“usb_lib.h”。

在这个头文件中,又有以下定义:#include "usb_type.h"#include "usb_regs.h"#include "usb_def.h"#include "usb_core.h"#include "usb_init.h"#include "usb_mem.h"#include "usb_int.h"usb_lib.h中又包含了七个头文件,其中usb_type.h中主要是用typedef为stm32支持的数据类型取一些新的名称。

usb_def.h中主要是定义一些相关的数据类型。

还有一个未包含在usb_lib.h中的头文件,usb_conf.h用于USB 设备的配置。

(2)上层结构上层结构总共5个文件:hw_config.c(用于USB硬件配置)、usb_pwr.c(用于USB连接、断开操作)、usb_istr.c(直接处理USB 中断)、usb_prop.c(用于上层协议处理,比如HID协议,大容量存储设备协议)、usb_desc.c(具体设备的相关描述符定义和处理)。

可见,ST的USB操作库结构十分清晰明了,我先不准备直接阅读源代码。

而是先利用MDK的软件模拟器仿真执行,先了解一下设备初始化的流程。

2、设备初始化所做的工作(1)Set_System(void)这个是main函数中首先调用的函数,它位于hw_config.c文件中。

USB驱动程序的编写采用WDM 驱动程序(计算机类)

USB驱动程序的编写采用WDM 驱动程序(计算机类)

USB驱动程序的编写采用WDM 驱动程序。

WDM 驱动程序是一些例程的集合,它们被动地存在,等待主机系统软件(PnP 管理器、I/O 管理器、电源管理器等)来调用或激活它们。

具体驱动程序不同,其所包含的例程也不同。

一个WDM 驱动程序的基本组成包括以下5个例程:(1)驱动程序入口例程:处理驱动程序的初始化。

(2)即插即用例程:处理PnP 设备的添加、删除和停止。

(3)分发例程:处理用户应用程序发出的各种 I/O 请求。

(4)电源管理例程:处理电源管理请求。

(5)卸载例程:处理驱动程序的卸载。

包含文件:ezusbsys.c, ezusbsys.h,ezusbsys.rc, resource.h, version.h, makefile,sources)在ezusbsys.c文件中,包含了上述五个例程:ezusbsys.h中定义了各种数据结构还有各种IOCTL控制码,用于不同数据的读写。

Ezusbsys.c 中实现了各种驱动例程。

包含了上述五个所说例程外还包含了其他例程,课程从下面的驱动程序入口例程得出一些信息。

驱动程序入口例程:NTSTATUSDriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath){NTSTATUS ntStatus = STATUS_SUCCESS;PDEVICE_OBJECT deviceObject = NULL;DriverObject->MajorFunction[IRP_MJ_CREATE] = Ezusb_Create; DriverObject->MajorFunction[IRP_MJ_CLOSE] = Ezusb_Close;//分发例程DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Ezusb_ProcessIOCTL;//即插即用例程DriverObject->MajorFunction[IRP_MJ_PNP] = Ezusb_DispatchPnp;//电源管理例程DriverObject->MajorFunction[IRP_MJ_POWER] = Ezusb_DispatchPower;//设备添加例程DriverObject->DriverExtension->AddDevice = Ezusb_PnPAddDevice;//卸载例程DriverObject->DriverUnload = Ezusb_Unload;return ntStatus;}在原有框架下,主要实现了的代码段在于ezusbsys.c文件中的如下例程:NTSTATUSEzusb_Read_Write( IN PDEVICE_OBJECT fdo, IN PIRP Irp )在该例程中实现对大数据块的读写控制和实现。

通用USB设备驱动源码分析

通用USB设备驱动源码分析

通用USB设备驱动源码分析Author:aaron前段时间写了篇<qualcomm usb modem驱动小结>的文章, 描述了自己如何为高通的一个usb modem设备写驱动的过程, 最近发现实际上可以使用linux自带的一个叫usbserial的模块作为这个modem的驱动并能良好的工作, 所以写了这片文章来详细的分析下usbserial 模块的源码(2.6.16.3).应该来说, 对于那些仅仅是用USB来通信, 在上层可看作tty设备, 不属于任何USB设备类型, 没有什么流控等的普通USB设备来说都可以使用这个驱动来作为设备驱动程序.下面就来对这样一种通用的驱动程序来进行详细的分析. 不对之处敬请指正!为了能让usbserail模块支持我的设备, 我必须在命令行上输入如下命令:sudo modprobe usbserial vendor=0x12d1 product=0x1003该命令用特权用户来加载usbserial模块,并把该模块依赖的模块一并加载进系统, 同时它还设置了usbserial的两个参数: vendor, product, 很显然这两个参数是厂商ID和设备ID, 而作用就是用于匹配设备.首先, 当然是要知道usbserial模块由哪些文件编译而成, 这样才能有目的性的去分析其代码. 而要知道其组成当然是去其目录下看Makefile了, 它位于内核源码目录下的./drivers/usb/serial/下./drivers/usb/serial/Makefile:## Makefile for the USB serial device drivers.## Object file lists.obj-$(CONFIG_USB_SERIAL) +=usbserial.o #编译内核时如何编译该模块usbserial-obj-$(CONFIG_USB_SERIAL_CONSOLE) += console.ousbserial-obj-$(CONFIG_USB_EZUSB) += ezusb.ousbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y) #OK, 就是usbserial模块的组成了.obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.oobj-$(CONFIG_USB_SERIAL_ANYDATA) += anydata.o .......我们重点看的是usb-serial.c, generic.c, bus.c在看源码之前我们先说说该模块的原理及整体结构:很简单跟应用层交互的是一个tty设备, 也就是说该模块把USB 设备映射成一个tty设备(即在/dev/目录下为该USB设备创建一个tty设备文件), 然后用于可以用minicom之类的串口工具来打开这个设备, 并同设备端的设备通信.对于发送过程: tty设备文件在获取了用户要求发送的数据之后传递到下层usbserial模块的核心层,而该核心层就是将数据打包成USB格式的数据并由USB通信发送到设备端去,对于接收过程: usbserial模块会在该设备打开时就启动一个urb 在那等待设备端发数据过来, 收到数据后就push到上层tty设备的缓冲中去, 而tty设备在收到数据后就会给用户,或直接显示在minicom之类的工具上.usb-serial.c 就是usbserial模块的核心, 它主要用来接收设备端发来的数据并传送到上层, 同时也接收来自上层应用的数据,并组装成urb包发送给设备.generic.c 对特定设备单独的操作,相当于是设备自己的驱动程序, 由于很多设备具有通用性, 所以对于没有特殊要求的设备都可以使用这个驱动来作为自己设备的驱动程序. 它有两个参数vendor 和product,上面提过了.bus.c 每个usb驱动和设备都必须要归入某一条总线上, 即都是归属于某条总线的,只有这样系统才能从特定一条总线开始找到每个驱动和设备并为他们匹配. 这个文件就是用来模拟一条总线, 而usbserial的每个驱动和设备都会注册到这条总线上来.好了,是时候分析usbserial模块了.我们知道当把一个模块加载进系统时会调用这个模块里的一个由module_init()声明的一个初始化函数. usbserial当然也不另外, usb-serial.c:module_init(usb_serial_init);module_exit(usb_serial_exit);没错加载时调用的就是: usb_serial_init().usb-serial.c:struct tty_driver *usb_serial_tty_driver;static int __init usb_serial_init(void){int i;int result;//创建一个tty_driver对象, 对应的就是tty设备的驱动.usb_serial_tty_driver =alloc_tty_driver(SERIAL_TTY_MINORS);if (!usb_serial_tty_driver)return -ENOMEM;/* Initialize our global data */for (i = 0; i < SERIAL_TTY_MINORS; ++i) {serial_table[i] = NULL; //该模块共支持SERIAL_TTY_MINORS个该类型设备.}result = bus_register(&usb_serial_bus_type); //注册这条serial bus.if (result) {err("%s - registering bus driver failed", __FUNCTION__);goto exit_bus;}//初始化tty_driver对象usb_serial_tty_driver->owner = THIS_MODULE;usb_serial_tty_driver->driver_name = "usbserial";usb_serial_tty_driver->devfs_name = "usb/tts/";usb_serial_tty_driver->name= "ttyUSB"; //tty设备文件名以这个开头,后加0,1,2,3,....usb_serial_tty_driver->major =SERIAL_TTY_MAJOR; //主设备号usb_serial_tty_driver->minor_start = 0;usb_serial_tty_driver->type =TTY_DRIVER_TYPE_SERIAL; //设备类型usb_serial_tty_driver->subtype =SERIAL_TYPE_NORMAL;usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;usb_serial_tty_driver->init_termios =tty_std_termios;usb_serial_tty_driver->init_termios.c_cflag =B9600 | CS8 | CREAD | HUPCL | CLOCAL;//赋值tty设备的操作集合,即应用层调用open时最终会调到serial_ops->open里面tty_set_operations(usb_serial_tty_driver,&serial_ops);result =tty_register_driver(usb_serial_tty_driver); //注册这个tty 驱动if (result) {err("%s - tty_register_driver failed",__FUNCTION__);goto exit_reg_driver;}/* register the USB driver */result = usb_register(&usb_serial_driver); //注册一个usb驱动if (result < 0) {err("%s - usb_register failed",__FUNCTION__);goto exit_tty;}/* register the generic driver, if we should */result = usb_serial_generic_register(debug); //注册generic驱动程序if (result < 0) {err("%s - registering generic driver failed", __FUNCTION__);goto exit_generic;}info(DRIVER_DESC);return result;//失败时候的一些反向操作exit_generic:usb_deregister(&usb_serial_driver);exit_tty:tty_unregister_driver(usb_serial_tty_driver);exit_reg_driver:bus_unregister(&usb_serial_bus_type);exit_bus:err ("%s - returning with error %d", __FUNCTION__, result);put_tty_driver(usb_serial_tty_driver);return result;}该函数先创建并初始化好了一个tty_driver的对象, 并把该对象注册进系统, 该对象就是tty设备的驱动程序, 后面我们会看到他是如何于具体tty设备绑定在一起的.usb_serial.c:static struct tty_operations serial_ops = {.open = serial_open,.close = serial_close,.write = serial_write,.write_room = serial_write_room,.ioctl = serial_ioctl,.set_termios = serial_set_termios,.throttle = serial_throttle,.unthrottle = serial_unthrottle,.break_ctl = serial_break,.chars_in_buffer = serial_chars_in_buffer,.read_proc = serial_read_proc,.tiocmget = serial_tiocmget,.tiocmset = serial_tiocmset,};这个就是tty设备文件对应的操作方法集合, 例如, 应用层调用open函数来打开该设备文件时将最终会走到serial_open里面.usb_serial_init() 还注册了一条总线:usb_serial_bus_type, 这样当有设备连上系统时, 该总线上的驱动就有机会去匹配这个设备. 后面我们会看到generic的驱动就是注册在该总线上的.bus.c:struct bus_type usb_serial_bus_type = {.name = "usb-serial",.match = usb_serial_device_match, //在设备匹配时会调用.probe = usb_serial_device_probe,.remove = usb_serial_device_remove,};关于设备匹配过程(probe)可以参考我的另一篇文章.usb_serial_init() 在最后usb_serial_generic_register(debug)来注册generic驱动.generic.c:int usb_serial_generic_register (int _debug){int retval = 0;debug = _debug;#ifdef CONFIG_USB_SERIAL_GENERICgeneric_device_ids[0].idVendor = vendor; //保存厂商IDgeneric_device_ids[0].idProduct = product; //保存产品IDgeneric_device_ids[0].match_flags =USB_DEVICE_ID_MATCH_VENDOR |USB_DEVICE_ID_MATCH_PRODUCT; //匹配类型/* register our generic driver with ourselves */ retval = usb_serial_register(&usb_serial_generic_device); //注册驱动if (retval)goto exit;retval = usb_register(&generic_driver); //注册驱动if (retval)usb_serial_deregister(&usb_serial_generic_ device);exit:#endifreturn retval;}该函数首先保存了命令通过命令行设备的vendor,product 用于以后设备匹配, 由此我们知道该驱动可以动态支持设备匹配. 接着该函数注册了usb_serial_generic_device驱动.generic.c:struct usb_serial_driver usb_serial_generic_device = { .driver = {.owner = THIS_MODULE,.name = "generic",},.id_table = generic_device_ids, //匹配用的设备列表, 支持动态匹配.num_interrupt_in = NUM_DONT_CARE,.num_bulk_in = NUM_DONT_CARE,.num_bulk_out = NUM_DONT_CARE,.num_ports = 1,.shutdown = usb_serial_generic_shutdown, };Usb-serial.c:int usb_serial_register(struct usb_serial_driver *driver) {int retval;fixup_generic(driver); //为driver赋上默认的操作函数if (!driver->description)driver->description = driver->;/* Add this device to our list of devices */list_add(&driver->driver_list,&usb_serial_driver_list); //加入驱动列表retval = usb_serial_bus_register(driver); //把该驱动注册进usb serial bus下if (retval) {err("problem %d when registering driver %s", retval, driver->description);list_del(&driver->driver_list);}elseinfo("USB Serial support registered for %s", driver->description);return retval;}其中的fixup_generic()函数仅仅是为driver赋上默认的操作函数.Usb-serial.c:#define set_to_generic_if_null(type,function) \do{ \ if (!type->function){ \type->function =usb_serial_generic_##function; \dbg("Had to override the "#function \" usb serial operation with the generic one.");\} \} while (0)static void fixup_generic(struct usb_serial_driver*device){set_to_generic_if_null(device, open);set_to_generic_if_null(device, write);set_to_generic_if_null(device, close);set_to_generic_if_null(device, write_room);set_to_generic_if_null(device, chars_in_buffer);set_to_generic_if_null(device,read_bulk_callback);set_to_generic_if_null(device,write_bulk_callback);set_to_generic_if_null(device, shutdown);}即通过上面的usb_serial_register()函数后usb_serial_generic_device的函数集为:usb_serial_generic_device.open = usb_serial_generic_open;usb_serial_generic_device.close =usb_serial_generic_close......驱动usb_serial_generic_device将是以后操作tty设备的主要函数.我们会在后面分析.bus.c:int usb_serial_bus_register(struct usb_serial_driver *driver){int retval;driver->driver.bus = &usb_serial_bus_type; //注册到该bus下retval = driver_register(&driver->driver);return retval;}最后usb_serial_generic_register()函数注册了一个generic_driver驱动.generic.c:static struct usb_driver generic_driver = {.name = "usbserial_generic",.probe = generic_probe, //匹配函数.disconnect = usb_serial_disconnect,.id_table = generic_serial_ids, //匹配用的设备列表.no_dynamic_id = 1, //不支持动态匹配};整个初始化过程, 乍一看一下子注册了几个驱动程序, 几个驱动列表, 有的支持动态匹配有的不支持, 感觉很复杂, 其实注册generic_driver驱动主要是为了注册一个generic_probe函数, 而该函数将会在设备连上系统后被调用以来匹配设备. 除此之外该驱动没什么用, 而在这个初始化函数中把vendor,product都保存在了generic_device_ids里, 因此可以肯定以后的匹配将用这个设备列表,而不是generic_serial_ids, 说的更直白些generic_serial_ids其实根本也没什么用. 真正有用的是usb_serial_generic_device驱动,generic.c:static int generic_probe(struct usb_interface *interface, const struct usb_device_id *id){const struct usb_device_id *id_pattern;id_pattern =usb_match_id(interface, generic_device_ids); //设备匹配 if (id_pattern != NULL)return usb_serial_probe(interface, id); //进一步匹配return -ENODEV;}如果接入系统的设备的vendor和product与我们驱动支持的设备列表匹配则调用usb_serial_probe来进一步匹配.usb_serial_probe函数比较长, 我们一段段的来看usb-serial.c:int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id){struct usb_device *dev = interface_to_usbdev (interface);struct usb_serial *serial = NULL;struct usb_serial_port *port;struct usb_host_interface *iface_desc;struct usb_endpoint_descriptor *endpoint;struct usb_endpoint_descriptor*interrupt_in_endpoint[MAX_NUM_PORTS];struct usb_endpoint_descriptor*interrupt_out_endpoint[MAX_NUM_PORTS];struct usb_endpoint_descriptor*bulk_in_endpoint[MAX_NUM_PORTS];struct usb_endpoint_descriptor*bulk_out_endpoint[MAX_NUM_PORTS];struct usb_serial_driver *type = NULL;int retval;int minor;int buffer_size;int i;int num_interrupt_in = 0;int num_interrupt_out = 0;int num_bulk_in = 0;int num_bulk_out = 0;int num_ports = 0;int max_endpoints;type = search_serial_device(interface); //获取该设备匹配的驱动if (!type) {dbg("none matched");return -ENODEV;}......}首先是找到合适的驱动程序.usb-serial.c:static struct usb_serial_driver*search_serial_device(struct usb_interface *iface) {struct list_head *p;const struct usb_device_id *id;struct usb_serial_driver *t;/* Check if the usb id matches a known device */ list_for_each(p, &usb_serial_driver_list) {t = list_entry(p, struct usb_serial_driver, driver_list);id = usb_match_id(iface, t->id_table); //看设备列表是否匹配if (id != NULL) {dbg("descriptor matches");return t; //返回匹配的驱动}}return NULL;}实际上这边的匹配和generic_probe里的匹配重复了, 因为他们的匹配的设备列表是同一个, 这边主要是为了得到匹配的驱动程序, 根据上面的代码分析我们可以知道这里匹配的驱动是usb_serial_generic_device.接着看usb_serial_probe()usb-serial.c:....serial = create_serial (dev, interface, type); //为该设备创建一个usb_serial对象if (!serial) {dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);return -ENOMEM;}/* if this device type has a probe function, call it */if (type->probe) { //从上面分析的代码可知这里的probe函数没有赋值const struct usb_device_id *id;if (!try_module_get(type->driver.owner)) { dev_err(&interface->dev, "module get failed, exiting\n");kfree (serial);return -EIO;}id = usb_match_id(interface,type->id_table);retval = type->probe(serial, id);module_put(type->driver.owner);if (retval) {dbg ("sub driver rejected device");kfree (serial);return retval;}}....这段代码可知, 主要是创建一个usb_serial的对象, 用于保存该设备的详细信息, 一般的驱动程序都会为自己匹配的设备创建一个描用于描述该设备的对象. 在以后的所有操作中如读写等都会直接从这个对象里获取相应的信息.usb-serial.c:static struct usb_serial * create_serial (struct usb_device *dev,structusb_interface *interface,structusb_serial_driver *driver){struct usb_serial *serial;serial = kmalloc (sizeof (*serial),GFP_KERNEL); //闯将该对象if (!serial) {dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);return NULL;}//初始化该对象memset (serial, 0, sizeof(*serial));serial->dev = usb_get_dev(dev); //增加dev的引用计数serial->type = driver;serial->interface = interface;kref_init(&serial->kref);return serial;}这个函数就是用来创建usb_serial对象的,并把相关信息保存在里面.继续看usb_serial_probe()usb-serial.c:..../* descriptor matches, let's find the endpoints needed *//* check out the endpoints *///查找该设备使用的endpoint的描述符, 并检查是否正确 iface_desc = interface->cur_altsetting; //接口描述符for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {endpoint =&iface_desc->endpoint[i].desc; //端点描述符if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x02)) {/* we found a bulk in endpoint*/ //bulk in 的端点dbg("found bulk in on endpoint %d", i);bulk_in_endpoint[num_bulk_in] = endpoint;++num_bulk_in;}if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&((endpoint->bmAttributes & 3) == 0x02)) {/* we found a bulk out endpoint*/ //bulk out的端点dbg("found bulk out on endpoint %d", i);bulk_out_endpoint[num_bulk_out] = endpoint;++num_bulk_out;}if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x03)) {/* we found a interrupt in endpoint */ //中断 in 端点dbg("found interrupt in onendpoint %d", i);interrupt_in_endpoint[num_interrupt _in] = endpoint;++num_interrupt_in;}if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&((endpoint->bmAttributes & 3) == 0x03)) {/* we found an interrupt out endpoint */ //中断 out 端点dbg("found interrupt out on endpoint %d", i);interrupt_out_endpoint[num_interrup t_out] = endpoint;++num_interrupt_out;}}.....该段代码主要是获取该设备使用的各个类型及方向的端点描述府, 并保存起来, 关于端点的类型与方向可以参考USB的规范.继续看usb_serial_probe()usb-serial.c:....#if defined(CONFIG_USB_SERIAL_PL2303) ||defined(CONFIG_USB_SERIAL_PL2303_MODULE)/* BEGIN HORRIBLE HACK FOR PL2303 *//* this is needed due to the looney way its endpoints are set up */if (((le16_to_cpu(dev->descriptor.idVendor) ==PL2303_VENDOR_ID) &&(le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&(le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID))) {if (interface !=dev->actconfig->interface[0]) {/* check out the endpoints of the other interface*/iface_desc =dev->actconfig->interface[0]->cur_altsetting;for (i = 0; i <iface_desc->desc.bNumEndpoints; ++i) {endpoint =&iface_desc->endpoint[i].desc;if((endpoint->bEndpointAddress & 0x80) &&((endpoint->bmAttributes & 3) == 0x03)) {/* we found a interrupt in endpoint */dbg("found interrupt in for Prolific device on separate interface");interrupt_in_endpoint [num_interrupt_in] = endpoint;++num_interrupt_in;}}}/* Now make sure the PL-2303 is configured correctly.* If not, give up now and hope this hack will work* properly during a later invocation of usb_serial_probe*/if (num_bulk_in == 0 || num_bulk_out == 0) { dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");kfree (serial);return -ENODEV;}}/* END HORRIBLE HACK FOR PL2303 */#endif上面这段代码主要是用于特定类型设备的(PL2303), 这里我们不用管他.接着看usb_serial_probe()usb-serial.c:..../* found all that we need */dev_info(&interface->dev, "%s converterdetected\n", type->description);#ifdef CONFIG_USB_SERIAL_GENERIC //这个宏定义了, 因为我们使用的是通用USB驱动.if (type == &usb_serial_generic_device) { //这个if为TRUE(上面分析过了)num_ports = num_bulk_out;if (num_ports == 0) { //bulk out端点必须要有dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");kfree (serial);return -EIO;}}#endifif (!num_ports) { //由于走到了上面那个if段,因此这里的num_ports肯定不为0/* if this device type has a calc_num_ports function, call it */if (type->calc_num_ports) {if(!try_module_get(type->driver.owner)) {dev_err(&interface->dev, "module get failed, exiting\n");kfree (serial);return -EIO;}num_ports = type->calc_num_ports (serial);module_put(type->driver.owner);}if (!num_ports)num_ports = type->num_ports;}//获取一个空闲的serial_table项if (get_free_serial (serial, num_ports, &minor) == NULL) {dev_err(&interface->dev, "No more free serial devices\n");kfree (serial);return -ENOMEM;}usbserial模块总共支持SERIAL_TTY_MINORS个设备, 它为每个设备都分配了一个serial_table项, 用于保存usb_serial对象, 方便以后直接通过minor号获取usb_serial对象.usb-serial.c:static struct usb_serial *get_free_serial (structusb_serial *serial, int num_ports, unsigned int *minor) {unsigned int i, j;int good_spot;dbg("%s %d", __FUNCTION__, num_ports);*minor = 0;for (i = 0; i < SERIAL_TTY_MINORS; ++i) {if (serial_table[i]) //查找一个空闲的serial_table项, serial_table是个usb_serial的指针数组.continue;good_spot = 1;//从上面代码可知, 对于generic的驱动, num_ports 就等于num_bulk_out, 而一般的设备仅有//一个bulkout 的端点, 因此这个for循环不会执行.for (j = 1; j <= num_ports-1; ++j)if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {good_spot = 0;i += j;break;}if (good_spot == 0)continue;*minor = i; //获取minor号dbg("%s - minor base = %d", __FUNCTION__, *minor);for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)serial_table[i] = serial; //获取空闲的serial_table项, 并把我们的usb_serial对象地址保//存在其中.return serial;}return NULL;}通过这个函数我们找到了一个空闲的serial_table项, 并把描述我们设备的usb_serial对象保存在其中, 在以后对设备的使用中, 我们可以轻易的通过minor号来找到这个usb_serial.接着看usb_serial_probe()usb-serial.c:....//保存设备信息到usb_serial对象中,serial->minor = minor;serial->num_ports = num_ports; //这里的port数量不是endpoint的数量,serial->num_bulk_in = num_bulk_in;serial->num_bulk_out = num_bulk_out;serial->num_interrupt_in = num_interrupt_in;serial->num_interrupt_out = num_interrupt_out;/* create our ports, we need as many as the max endpoints *//* we don't use num_ports here cauz some devices have more endpoint pairs than ports *///对于generic的驱动来说一般都只有一个bulk in,一个bulk out,一个interrupt in,一个interrupt outmax_endpoints = max(num_bulk_in, num_bulk_out);max_endpoints = max(max_endpoints,num_interrupt_in);max_endpoints = max(max_endpoints,num_interrupt_out);max_endpoints = max(max_endpoints,(int)serial->num_ports);//到这一步,对于generic来说大多数情况下max_endpoints 还是为1serial->num_port_pointers = max_endpoints;dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);for (i = 0; i < max_endpoints; ++i) {port = kmalloc(sizeof(structusb_serial_port), GFP_KERNEL); //分配一个port对象 if (!port)goto probe_error;//初始化port对象memset(port, 0x00, sizeof(structusb_serial_port));port->number = i + serial->minor;port->serial = serial; //保存usb_serial 对象, 便于以后通过port对象访问到usb_serial对象 spin_lock_init(&port->lock);sema_init(&port->sem, 1);INIT_WORK(&port->work,usb_serial_port_softint, port);serial->port[i] = port;}//由上面的对port的初始化可知,每个port都有一套自己的工作机制, port间互不干扰/* set up the endpoint information */for (i = 0; i < num_bulk_in; ++i) {//初始化bulk in 端点, 并把它保存到相应的port里 endpoint = bulk_in_endpoint[i];port = serial->port[i];port->read_urb = usb_alloc_urb (0,GFP_KERNEL); //分配urbif (!port->read_urb) {dev_err(&interface->dev, "No free urbs available\n");goto probe_error;}buffer_size =le16_to_cpu(endpoint->wMaxPacketSize);port->bulk_in_size = buffer_size;port->bulk_in_endpointAddress =endpoint->bEndpointAddress; //保存端点地址port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); //分配传输缓存if (!port->bulk_in_buffer) {dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n");goto probe_error;}//设置好该urb.usb_fill_bulk_urb (port->read_urb, dev, usb_rcvbulkpipe (dev,endpoint->bE ndpointAddress),port->bulk_in_buffer, buffer_size,serial->type->read_bulk_c allback,port);}for (i = 0; i < num_bulk_out; ++i) {//初始化bulk out 端点, 并把它保存到相应的port里 endpoint = bulk_out_endpoint[i];port = serial->port[i];port->write_urb = usb_alloc_urb(0,GFP_KERNEL);if (!port->write_urb) {dev_err(&interface->dev, "No free urbs available\n");goto probe_error;}buffer_size =le16_to_cpu(endpoint->wMaxPacketSize);port->bulk_out_size = buffer_size;port->bulk_out_endpointAddress =endpoint->bEndpointAddress;port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);if (!port->bulk_out_buffer) {dev_err(&interface->dev, "Couldn't allocate bulk_out_buffer\n");。

usb之python(pyusb)

usb之python(pyusb)

usb之python(pyusb)电脑系统为WIN7 64位python:为python3.6 32位需要插件PyUSB-1.0.0.tar,pywinusb-0.4.2。

按照的步骤我偷懒了,⾃⼰百度⼀下。

我们先看设备管理的测试代码如下#!/usr/bin/python# -*- coding:utf-8 -*-import usb.utilimport sys#USB\VID_1C4F&PID_0051dev = usb.core.find(idVendor= 0x1C4F, idProduct= 0x0051)if dev is None:raise ValueError('Device not found')print(dev)# set the active configuration. With no arguments, the first# configuration will be the active onecfg = dev.get_active_configuration()测试结果Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] on win32Type "copyright", "credits"or"license()"for more information.>>>================== RESTART: C:\Users\libra\Desktop\2222.py ==================DEVICE ID 1c4f:0051 on Bus 003 Address 002 =================bLength : 0x12 (18 bytes)bDescriptorType : 0x1 DevicebcdUSB : 0x110 USB 1.1bDeviceClass : 0x0 Specified at interfacebDeviceSubClass : 0x0bDeviceProtocol : 0x0bMaxPacketSize0 : 0x8 (8 bytes)idVendor : 0x1c4fidProduct : 0x0051bcdDevice : 0x110 Device 1.1iManufacturer : 0x1iProduct : 0x2iSerialNumber : 0x0bNumConfigurations : 0x1CONFIGURATION 1: 100 mA ==================================bLength : 0x9 (9 bytes)bDescriptorType : 0x2 ConfigurationwTotalLength : 0x22 (34 bytes)bNumInterfaces : 0x1bConfigurationValue : 0x1iConfiguration : 0x0bmAttributes : 0xa0 Bus Powered, Remote WakeupbMaxPower : 0x32 (100 mA)INTERFACE 0: Human Interface Device ====================bLength : 0x9 (9 bytes)bDescriptorType : 0x4 InterfacebInterfaceNumber : 0x0bAlternateSetting : 0x0bNumEndpoints : 0x1bInterfaceClass : 0x3 Human Interface DevicebInterfaceSubClass : 0x1bInterfaceProtocol : 0x2iInterface : 0x0ENDPOINT 0x81: Interrupt IN ==========================bLength : 0x7 (7 bytes)bDescriptorType : 0x5 EndpointbEndpointAddress : 0x81 INbmAttributes : 0x3 InterruptwMaxPacketSize : 0x4 (4 bytes)bInterval : 0xa如果先出现系统⽆法识别的话可以参考I downloaded latest libusb windows binaries from here: then I copied libusb1.dll according to this: when you are on 64-bit Windows, MS64\dll\libusb-1.0.dll must be copied into C:\Windows\System32 and (for running 32-bit applications that use libusb) MS32\dll\libusb-1.0.dll must be copied into C:\Windows\SysWOW64. and then I copied libusb1.lib from binaries to lib dir in python directory and now pyusb works for me. hope it helps.继续#!/usr/bin/python# -*- coding:utf-8 -*-import usb.coreimport usb.utilimport sys#USB\VID_1C4F&PID_0051dev = usb.core.find(idVendor= 0x1C4F, idProduct= 0x0051)if dev is None:raise ValueError('Device not found')print(dev)# set the active configuration. With no arguments, the first# configuration will be the active onecfg = dev.get_active_configuration()print("#"*60)print(cfg)================= RESTART: C:/Users/libra/Desktop/3333333.py =================DEVICE ID 1c4f:0051 on Bus 003 Address 002 =================bLength : 0x12 (18 bytes)bDescriptorType : 0x1 DevicebcdUSB : 0x110 USB 1.1bDeviceClass : 0x0 Specified at interfacebDeviceSubClass : 0x0bDeviceProtocol : 0x0bMaxPacketSize0 : 0x8 (8 bytes)idVendor : 0x1c4fidProduct : 0x0051bcdDevice : 0x110 Device 1.1iManufacturer : 0x1iProduct : 0x2iSerialNumber : 0x0bNumConfigurations : 0x1CONFIGURATION 1: 100 mA ==================================bLength : 0x9 (9 bytes)bDescriptorType : 0x2 ConfigurationwTotalLength : 0x22 (34 bytes)bNumInterfaces : 0x1bConfigurationValue : 0x1iConfiguration : 0x0bmAttributes : 0xa0 Bus Powered, Remote WakeupbMaxPower : 0x32 (100 mA)INTERFACE 0: Human Interface Device ====================bLength : 0x9 (9 bytes)bDescriptorType : 0x4 InterfacebInterfaceNumber : 0x0bAlternateSetting : 0x0bNumEndpoints : 0x1bInterfaceClass : 0x3 Human Interface DevicebInterfaceSubClass : 0x1bInterfaceProtocol : 0x2iInterface : 0x0ENDPOINT 0x81: Interrupt IN ==========================bLength : 0x7 (7 bytes)bDescriptorType : 0x5 EndpointbEndpointAddress : 0x81 INbmAttributes : 0x3 InterruptwMaxPacketSize : 0x4 (4 bytes)bInterval : 0xa############################################################CONFIGURATION 1: 100 mA ==================================bLength : 0x9 (9 bytes)bDescriptorType : 0x2 ConfigurationwTotalLength : 0x22 (34 bytes)bNumInterfaces : 0x1bConfigurationValue : 0x1iConfiguration : 0x0bmAttributes : 0xa0 Bus Powered, Remote WakeupbMaxPower : 0x32 (100 mA)INTERFACE 0: Human Interface Device ====================bLength : 0x9 (9 bytes)bDescriptorType : 0x4 InterfacebInterfaceNumber : 0x0bAlternateSetting : 0x0bNumEndpoints : 0x1bInterfaceClass : 0x3 Human Interface DevicebInterfaceSubClass : 0x1bInterfaceProtocol : 0x2iInterface : 0x0ENDPOINT 0x81: Interrupt IN ========================== bLength : 0x7 (7 bytes)bDescriptorType : 0x5 EndpointbEndpointAddress : 0x81 INbmAttributes : 0x3 InterruptwMaxPacketSize : 0x4 (4 bytes)bInterval : 0xaView Code。

USBClassCodesusb设备类型代码

USBClassCodesusb设备类型代码

USBClassCodesusb设备类型代码Defined 1.0 Class CodesUSB Class Codes March 2, 2006USB defines class code information that is used to identify a device’s functionality and to nominally load a device driver based on that functionality. The information is contained in three bytes with the names Base Class, SubClass, and Protocol. (Note that ‘Base Class’ is used in this description to identify the first byte of the Class Code triple. That terminology is not used in the USB Specification). There are two places on a device where class code information can be placed.One place is in the Device Descriptor, and the other is in Interface Descriptors. Some defined class codes are allowed to be used only in a Device Descriptor, others can be used in both Device and Interface Descriptors, and some can only be used in Interface Descriptors. The table below shows the currently defined set of Base Class values, what the generic usage is, and where that Base Class can be used (either Device or Interface Descriptors or both).Base Class Descriptor Usage Description00h Device01h Interface02h Both03h Interface05h Interface06h Interface07h Interface08h Interface09h Device0Ah Interface0Bh Interface0Dh Interface0Eh Interface0Fh InterfaceDCh BothE0h InterfaceFEh InterfaceFFh BothBase Class 00h (Device)This base class is defined to be used in Device Descriptors to indicate that class information should be determined from the Interface Descriptors in the device. There is one class code definition in this base class. All other values are reserved.This value is also used in Interface Descriptors to indicate a null class code triple.Base Class SubClass Protocol Meaning00h00h00h Use class code info from Interface DescriptorsBase Class 01h (Audio)This base class is defined for Audio capable devices that conform to the Audio Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes may only be used in Interface Descriptors.Base Class SubClass Protocol Meaning01h xxh xxh Audio deviceBase Class 02h (Communications and CDC Control)This base class is defined for devices that conform to the Communications Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. Note that the Communication Device Class spec requires some class code values (triples) to be used in Device Descriptors and some to be used in Interface Descriptors.Base Class SubClass Protocol Meaning02h xxh xxh Communication device classBase Class 03h (HID – Human Interface Device)This base class is defined for devices that conform to the HID Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.Base Class SubClass Protocol Meaning03h xxh xxh HID device classBase Class 05h (Physical)This base class is defined for devices that conform to the Physical Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.Base Class SubClass Protocol Meaning05h xxh xxh Physical device classBase Class 06h (Still Imaging)This base class is defined for devices that conform to the Imaging Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved.Base Class SubClass Protocol Meaning06h01h01h Still Imaging deviceBase Class 07h (Printer)This base class is defined for devices that conform to the Printer Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.Base Class SubClass Protocol Meaning07h xxh xxh Printer deviceBase Class 08h (Mass Storage)This base class is defined for devices that conform to the Mass Storage Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.Base Class SubClass Protocol Meaning08h xxh xxh Mass Storage deviceBase Class 09h (Hub)This base class is defined for devices that are USB hubs and conform to the definition in the USB specification. That specification defines the complete triples as shown below. All other values are reserved. These class codes can only be used in Device Descriptors.Base Class SubClass Protocol Meaning09h00h00h Full speed Hub01h Hi-speed hub with single TT02h Hi-speed hub with multiple TTsBase Class 0Ah (CDC-Data)This base class is defined for devices that conform to the Communications Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values.Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.Base Class SubClass Protocol Meaning0Ah xxh xxh CDC data deviceBase Class 0Bh (Smart Card)This base class is defined for devices that conform to the Smart Card Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values.Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.Base Class SubClass Protocol Meaning0Bh xxh xxh Smart Card deviceBase Class 0Dh (Content Security)This base class is defined for devices that conform to the Content Security Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.Base Class SubClass Protocol Meaning0Dh00h00h Content Security deviceBase Class 0Eh (Video)This base class is defined for devices that conform to the Video Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.Base Class SubClass Protocol Meaning0Eh xxh xxh Video deviceBase Class 0Fh (Personal Healthcare)This base class is defined for devices that conform to the Personal Healthcare Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec arereserved. These class codes should only be used in Interface Descriptors.Base Class SubClass Protocol Meaning0Fh xxh xxh Personal Healthcare deviceBase Class DCh (Diagnostic Device)This base class is defined for devices that diagnostic devices. There is currently only one value defined. All other values are reserved. This class code can be used in Device or Interface Descriptors.Base Class SubClass Protocol MeaningDCh01h01h USB2 Compliance Device. Definition for this device can be found at。

USB驱动源代码

USB驱动源代码

作者: UserVC// usblistenDlg.cpp : implementation file //#include "stdafx.h"#include "usblisten.h"#include "usblistenDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////// //////////////////////////////////// CAboutDlg dialog used for App About class CAboutDlg : public CDialog{public:CAboutDlg();// Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg() :CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}voidCAboutDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)//{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////// //////////////////////////////////// CUsblistenDlg dialogCUsblistenDlg::CUsblistenDlg(CWnd* pParent /*=NULL*/): CDialog(CUsblistenDlg::IDD, pParent) {//{{AFX_DATA_INIT(CUsblistenDlg)// NOTE: the ClassWizard will add member initialization here//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon =AfxGetApp()->LoadIcon(IDR_MAINFRAME);}voidCUsblistenDlg::DoDataExchange(CDataExchange * pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CUsblistenDlg)// NOTE: the ClassWizard will add DDX and DDV calls here//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CUsblistenDlg, CDialog) //{{AFX_MSG_MAP(CUsblistenDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_SEND, OnSend)ON_WM_TIMER()ON_WM_CTLCOLOR()//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////// //////////////////////////////////// CUsblistenDlg message handlersBOOL CUsblistenDlg::OnInitDialog()CDialog::OnInitDialog();// Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range.ASSERT((IDM_ABOUTBOX & 0xFFF0) ==IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);SetTimer(1,3000,NULL);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX, strAboutMenu);}// Set the icon for this dialog. The framework does this automatically// when the application's main window is not a dialogSetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon// TODO: Add extra initialization herereturn TRUE; // return TRUE unless you set the focus to a control}void CUsblistenDlg::OnSysCommand(UINT nID, LPARAM lParam){if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID, lParam);}}// If you add a minimize button to your dialog, you will need the code below// to draw the icon. For MFC applications using the document/view model,// this is automatically done for you by the framework.void CUsblistenDlg::OnPaint(){if (IsIconic()){CPaintDC dc(this); // device context forpaintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icondc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}}// The system calls this to obtain the cursor to display while the user drags// the minimized window.HCURSOR CUsblistenDlg::OnQueryDragIcon() {return (HCURSOR) m_hIcon;}//-----------------Initilize USBport---------unsigned int VendorID,ProductID;char temp_buffer[100];unsigned char DataBuffer[1],BufferLength; //接收unsigned charSendDataBuffer[1],SendBufferLength; //发送int HIDCounter=0;GUID hidGuid;HDEVINFO AllHIDDeviceInfo=NULL;HANDLE HIDDevice=NULL,ReadHIDDevice=NULL; HIDD_ATTRIBUTES Attributes;PSP_DEVICE_INTERFACE_DETAIL_DATA ClassDeviceData;SP_INTERFACE_DEVICE_DATA deviceInfoData; ULONG neededLength,requiredLength; DWORD bytesRead;bool InitUSB(){VendorID = 0x0000;ProductID = 0x0000;// 查找设备// 本例程使用HID设备的API,它查找HID设备列表,找出与Vendor ID 和 Product ID匹配的设备ClassDeviceData =NULL;HIDDevice =NULL;deviceInfoData.cbSize=sizeof(deviceInfoData);// 从操作系统获取HIDs 的GUIDHidD_GetHidGuid(&hidGuid);// 获取所有HIDs的设备信息AllHIDDeviceInfo=SetupDiGetClassDevs(&hidGu id,NULL,NULL,DIGCF_PRESENT|DIGCF_INTERFACEDEVICE); HIDCounter=0;while (TRUE){// 这个API将发现的设备信息写入deviceInfoData// HIDCounter 允许这个API重复调用所有HID设备// 如果API调用返回0,没有更多的HID设备发现if(!SetupDiEnumDeviceInterfaces(AllHIDDeviceI nfo,0,&hidGuid,HIDCounter,&deviceInfoData))// 没有发现与Vendor ID 和 Product ID匹配的HID 设备SetupDiDestroyDeviceInfoList(AllHIDDeviceIn fo);return FALSE;}else{// 发现一个HID设备,获取设备的详细信息// 第一次调用SetupDiGetDeviceInterfaceDetail得到ClassDeviceData// 的大小,但返回错误SetupDiGetDeviceInterfaceDetail(AllHIDDevic eInfo,&deviceInfoData,NULL,0,&requiredLength,NULL);neededLength =requiredLength; ClassDeviceData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(n eededLength);ClassDeviceData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);//第二次调用SetupDiGetDeviceInterfaceDetail // 使用合适的neededLength.if(!SetupDiGetDeviceInterfaceDetail(AllHIDDev iceInfo,&deviceInfoData,ClassDeviceData,neededLength,&requiredLengt h,NULL)){free(ClassDeviceData); SetupDiDestroyDeviceInfoList(AllHIDDeviceIn fo);return FALSE;// 建立HID设备的句柄HIDDevice=CreateFile(ClassDeviceData->Devic ePath,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);// 获取 attributes 以便得到Vendor ID 和Product IDHidD_GetAttributes(HIDDevice,&Attributes);if ((Attributes.VendorID == VendorID) && (Attributes.ProductID == ProductID)){// 找到了匹配的Vendor ID 和 Product ID的HID 设备// 建立ReadHIDDevice设备的句柄以便读取信息ReadHIDDevice=CreateFile(ClassDeviceData->D evicePath,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);free(ClassDeviceData); SetupDiDestroyDeviceInfoList(AllHIDDeviceIn fo);//初始化成功return TRUE;}else{CloseHandle(HIDDevice);}free(ClassDeviceData);HIDCounter = HIDCounter+1;}}//Read from usb prot,that is listen to usb port ,if it has character,system would display it on user interfacebool ReadUSB(){BufferLength=1;memset(DataBuffer,0,1);if(!ReadFile(ReadHIDDevice,DataBuffer,Buffe rLength,&bytesRead,NULL)) //失败return false; //读数失败立即返回elsereturn true;}//Wirte a character or a string to usb port bool WriteUSB()CString str;SendBufferLength=1;SendDataBuffer[0]=65;str=SendDataBuffer;if(!WriteFile(ReadHIDDevice,SendDataBuffer,Se ndBufferLength,&bytesRead,NULL)){return false;//失败}elseAfxMessageBox("Success!");return true;//成功}}void CUsblistenDlg::OnCancel(){int button;button=AfxMessageBox("Do you want to exit?",MB_YESNO+MB_ICONWARNING);if(button==IDYES){KillTimer(1);EndDialog(IDYES);}}//Thread callback functionvoid CUsblistenDlg::OnSend(){// TODO: Add your control notification handler code hereSendDataBuffer[0]='C';WriteUSB();}void CUsblistenDlg::OnTimer(UINT nIDEvent) {// TODO: Add your message handler code here and/or call default//CString str;//ReadUSB();//str=DataBuffer;//if(DataBuffer[0]!=0)//{// CListBox*listbox=(CListBox*)GetDlgItem(IDC_LIST1);// listbox->AddString(str);//}//else//{// CListBox*listbox=(CListBox*)GetDlgItem(IDC_LIST1); // listbox->AddString("No Charcters is sent to usb port");//}WriteUSB();CDialog::OnTimer(nIDEvent);}void CUsblistenDlg::OnOK(){// TODO: Add extra validation hereCDialog::OnOK();}HBRUSH CUsblistenDlg::OnCtlColor(CDC* pDC,CWnd* pWnd, UINT nCtlColor){HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);UINT uID=pWnd->GetDlgCtrlID();switch(uID){case IDC_LIST1:pDC->SetTextColor(RGB(255,255,0));pDC->SetBkColor(RGB(255,0,0));break;}// TODO: Change any attributes of the DC here// TODO: Return a different brush if the default is not desiredreturn hbr;}。

C#实现USB接口的程序代码

C#实现USB接口的程序代码
C#实现 USB接口的程序代码
C#实现USB接口的程序代码.
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
USB usb; usb = new UDisk();//插入U盘 usb.OutputFile();//从U盘读出文件 usb.InputFile();//往U盘写入文件 usb.Dispose();//拔出U盘 Console.WriteLine(""); usb = new MDisk();//插入移动硬盘 usb.OutputFile();//从移动硬盘读出文件 usb.InputFile();//往移动硬盘写入文件 usb.Dispose();//拔出移动硬盘 Console.WriteLine(""); usb = new MP4();//插入MP4 usb.OutputFile();//从MP4读出文件 usb.InputFile();//往MP4写入文件 usb.Dispose();//拔出MP4 Console.ReadKey(); }
public MDisk() {
Console.WriteLine("移动硬盘准备就绪..."); } public void OutputFile() {
Console.WriteLine("从移动硬盘读出文件"); }
} public void InputFile() {
Console.WriteLine("往移动硬盘写入文件"); } public void Dispose() {
Console.WriteLine("往MP4写入文件"); } public void Dispose() {
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

项目报告7USB驱动程序源代码作者:罗仕波一.头文件go7007sb.h/**go7007sb.h - this file includes all relative header files that*will be used in go7007sb vedio usb interface driver, and it*also defines all relative driver private data structures and*it's io control commands.*/#ifndef _GO7007SB_H#define _GO7007SB_H#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <asm/uaccess.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/ioctl.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/fs.h>#include <linux/devfs_fs_kernel.h>//#define DEBUG#define DRIVER_VERSION "1.0.0"#define DRIVER_DESC "USB GO7007SB Driver"#include <linux/usb.h>MODULE_AUTHOR("Luo Shibo");MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);MODULE_LICENSE("GPL");/**io control commands definition,these commands will be*used to control the device in function iocntl_go7007sb*/#define GO7007SB_IOC_MAGIC 'U' //command magic number#define GO7007SB_IOC_RESET _IO(GO7007SB_IOC_MAGIC,0) //software reset the device#define GO7007SB_IOC_SHUTDOWN _IO(GO7007SB_IOC_MAGIC,1) //shutdown the device#define GO7007SB_IOC_PAUSE _IO(GO7007SB_IOC_MAGIC,2) //pause compression#define GO7007SB_IOC_RESUME _IO(GO7007SB_IOC_MAGIC,3) //resume from pause status#define GO7007SB_IOC_GETSTATE _IOR(GO7007SB_IOC_MAGIC,4,unsigned int)//get state of dev/**go7007sb device file number,the major of all USB devices have been defined as 180,*we just need to define minors here,currently,we accept only 4 devices*their minors start from 64,so minors:64,65,66,67 should be ok.*/#ifdef __KERNEL__ /*__KERNEL__*/#define GO7007SB_MAX_MNR 4#define GO7007SB_BASE_MNR 64#define USB_GO7007SB_MINOR(inode) MINOR((inode)->i_rdev)-GO7007SB_BASE_MNR/**go7007sb video interface number*/#define GO7007SB_VIDEO_IFNUM 0/**endpoints definition*/#define GO7007SB_MAX_EP_NUM 4 //maximum endpoint number#define GO7007SB_EP_BULK_IN 1 //in endpoint for stream#define GO7007SB_EP_CTRL 2 //out endpoint for control#define GO7007SB_EP_BULK_OUT 3 //out endpoint for initialization#define GO7007SB_EP_INTR 4 //in endpoint for interrupt#define IS_EP_BULK(ep) ((ep).bmAttributes==USB_ENDPOINT_XFER_BULK ? 1 : 0)#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep)&& \((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK)==USB_DIR_IN)#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep)&& \((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK)==USB_DIR_OUT)#define IS_EP_INTR(ep) ((ep).bmAttributes==USB_ENDPOINT_XFER_INT ? 1 : 0)#define IS_EP_CTRL(ep) ((ep).bmAttributes==USB_ENDPOINT_XFER_CONTROL ? 1 : 0)#define USB_ENDPOINT_NUM(ep) ((ep).bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)#define USB_EP_DIR_IN 0#define USB_EP_DIR_OUT 1/**buffer sizes*/#define GO7007SB_STRM_BUF_SZ 128 //streaming buffer#define GO7007SB_INIT_BUF_SZ 64 //initial buffer#define IN_URB_BUF_SZ 1024 //buffer for in urb#define OUT_URB_BUF_SZ 4*GO7007SB_INIT_BUF_SZ //buffer for out urb/**times*/#define GO7007SB_INT_INTERVAL 5 //interrupt interval:5ms#define GO7007SB_RD_TIMEOUT 3*HZ //timeout per read:3s#define GO7007SB_RD_EXPIRE 3 //expires after 3 read timeouts#define GO7007SB_WR_TIMEOUT 3*HZ#define GO7007SB_WR_EXPIRE 10/**interrupts and command values:values with REQ are requests sent from go7007sb*values with CMD are commands sent from host to control go7007sb*/#define GO7007SB_IRQ_VALUE_MASK 0xFFFF0000#define go7007sb_irq_value(u32_data) (((u32_data) & GO7007SB_IRQ_VALUE_MASK) >> 16)#define GO7007SB_IRQ_BOOT 0x55AA //boota : go7007sb request to boot#define GO7007SB_IRQ_INIT 0x5A5A //bootb2: boot done, request to init#define GO7007SB_IRQ_RUN 0x0000 //initz : init done, request to run#define GO7007SB_IRQ_PAUSE 0x0020 //the ack of PAUSE command#define GO7007SB_IRQ_SHUTDOWN 0xA55A //fatal error,request to shutdown#define GO7007SB_CMD_BOOT 0x55AA //boot go7007sb,write it into init buffer#define GO7007SB_CMD_INIT_BICP 0x1000 //use Block-Init-Config-Package to init#define GO7007SB_CMD_INIT_RICP 0x2000 //use Register-Init_Config-Package to init#define GO7007SB_CMD_INIT_DICP 0x4000 //use DRAM-Init-Config-Packet to init#define GO7007SB_CMD_START 0x8000 //start encoding#define GO7007SB_CMD_PAUSE 0x0020 //pause encoding#define GO7007SB_CMD_SHUTDOWN 0x0081 //shutdown the device#define GO7007SB_CMD_SOFTRESET 0x0082 //software reset the device#define XRISC_EXCODE_START_ADDR 0x0200 //xrisc executable code starting address#define NUM_OF_FIRMWARE_PKT 1 //number of firmware packet downloaded/**file paths*/#define PKT_TYPE_FIRMWARE 0#define PKT_TYPE_INITPKT 1#define DEFAULT_FIRMWARE_PATH "/etc/go7007sb/go7007fw.bin"#define DEFAULT_INITPKT_PATH "/etc/go7007sb/go7007in.bin"#define DEFAULT_CONF_FILE_PATH "/etc/go7007sb.conf"/**go7007sb device id:this will be used for system to*find the driver for a hotpluged go7007sb vedio device*here we only need to match vendor and productor id.*/static struct usb_device_id go7007sb_device_id={match_flags: USB_DEVICE_ID_MATCH_DEVICE |USB_DEVICE_ID_MATCH_INT_CLASS |USB_DEVICE_ID_MATCH_INT_SUBCLASS,idVendor: 0x0EB1,idProduct: 0x7007,bInterfaceClass: 0xFF,bInterfaceSubClass: 0x00,};#endif /*__KERNEL__*//**go7007sb device private data:this struct descripts the*relative info about this device.*/#define GO7007SB_STATE_NOTBOOTED 0 //before bootA state#define GO7007SB_STATE_BOOTFAILED 1 //failed to bootup the device#define GO7007SB_STATE_BOOTDONE 2 //succeeded to boot the device#define GO7007SB_STATE_INITFAILED 3 //failed to initialize the device #define GO7007SB_STATE_PAUSED 4 //paused#define GO7007SB_STATE_HALTED 5 //device halted#define GO7007SB_STATE_RUNNING 6 //device is running#define GO7007SB_STATE_READY 7 //start-coding command sent#ifdef __KERNEL__ /*__KERNEL__*/struct go7007sb_usb_data{struct usb_device *go7007sb_dev; //the usb device structstruct urb go7007sb_irq;//the interrupt urb of this deviceunsigned int ifnum; //interface number of the vedio interface kdev_t go7007sb_minor; //the device minor number of go7007sb char isopen; //not zero if the device is openchar present; //not zero if the device is presentunsigned int state; //device state__u32 irq; //buffer for interrupt endpoint,4 bytes__u64 ctrl; //buffer for control endpoint,8 byteschar *out_buf,*in_buf;//the io buffers used to transferchar bulk_in_ep; //data in endpoint,should be 1char ctrl_ep; //control out endpoint num,should be 2char bulk_out_ep; //init out endpoint,should be 3char intr_ep; //interrupt listening endpoint,should be 4 wait_queue_head_t rd_wait_q; //wait queue on read requestwait_queue_head_t wr_wait_q; //wait queue on write requeststruct semaphore sem; //semphore to prevent concurrent operation unsigned int rd_nak_timeout; //seconds to wait before timeoutunsigned int wr_nak_timeout; //seconds to wait before timeout};#endif /*__KERNEL__*/#endif二.源代码go7007sb.c/**go7007sb.c - defines all the global varibales and functions of the driver*/#ifndef MODULE#define MODULE#endif#ifndef __KERNEL__#define __KERNEL__#endif#include "go7007sb.h"/**global variables*/struct go7007sb_usb_data *p_go7007sb_data_table[GO7007SB_MAX_MNR]={NULL,/*...*/};static DECLARE_MUTEX(go7007sb_mutex);/**macroes to get/set the device state*/#define set_state(go_data,s) \do{ \(go_data)->state=(s); \}while(0)#define get_state(go_data) ((go_data)->state)/**function to build the initial buffer to send command to the device */static inline int build_cmd_buffer(char *buf,__u16 cmd){__u16 *u16_buf=(__u16 *)buf;if(!u16_buf)return -ENOMEM;switch(cmd){case GO7007SB_CMD_BOOT :u16_buf[0]=cpu_to_le16(GO7007SB_CMD_BOOT);u16_buf[1]=cpu_to_le16(XRISC_EXCODE_START_ADDR);u16_buf[3]=cpu_to_le16(NUM_OF_FIRMWARE_PKT);break;case GO7007SB_CMD_START :u16_buf[0]=cpu_to_le16(GO7007SB_CMD_START);/*note:buffer[1]-buffer[31]should reffer to*//*the vendor sdk and to be handled later */break;case GO7007SB_CMD_PAUSE :u16_buf[0]=cpu_to_le16(GO7007SB_CMD_PAUSE);break;case GO7007SB_CMD_SHUTDOWN :u16_buf[0]=cpu_to_le16(GO7007SB_CMD_SHUTDOWN);break;case GO7007SB_CMD_SOFTRESET :u16_buf[0]=cpu_to_le16(GO7007SB_CMD_SOFTRESET);break;default:return -EINVAL;}return 0;}/**function to locate the paths of firmware and config packet*/static struct file *locate_vendor_image(int type){struct file *filp;switch(type){case PKT_TYPE_FIRMWARE :filp=filp_open(DEFAULT_FIRMWARE_PATH,O_RDONLY,0644);if(IS_ERR(filp))goto error;break;case PKT_TYPE_INITPKT :filp=filp_open(DEFAULT_INITPKT_PATH,O_RDONLY,0644);if(IS_ERR(filp))goto error;break;default:goto error;}return filp;error:return NULL;}/**function to send command to device through bulk out endpoint*/static int send_command(struct go7007sb_usb_data *go_data,__u16 cmd) {int retval;int bytes;int wr_expires=GO7007SB_WR_EXPIRE;struct usb_device *dev;char *cmd_buf=go_data->out_buf;kdev_t go_minor=go_data->go7007sb_minor;if(!cmd_buf)return -ENOMEM;/**build the initial buffer*/if((retval=build_cmd_buffer(cmd_buf,cmd))!=0)return retval;/**fill the urb and then submit it*/dev=go_data->go7007sb_dev;try_again:retval=usb_bulk_msg(dev,usb_sndbulkpipe(dev,go_data->bulk_out_ep),cmd_buf,GO7007SB_INIT_BUF_SZ,&bytes,GO7007SB_WR_TIMEOUT);/**check the result*/if(retval==USB_ST_TIMEOUT && !bytes){//timeout and no data sentif(--wr_expires<=0){err("send_command(%d):sending command timed out!",go_minor);}elsegoto try_again;;}else if(retval==-EPIPE){ //endpoint haltedif(usb_clear_halt(dev,go_data->bulk_out_ep)){err("send_command(%d):endpoint halted!",go_minor);}goto try_again;}else if(retval<0){ //other errorserr("send_command(%d):sending command failed!",go_minor);}return retval;}/**function to download file to initial buffer*/static int download_file(struct go7007sb_usb_data *go_data,struct file *fp){char *buf;int count;int partial;int this_write;int result;int wr_expires;struct usb_device *dev;kdev_t go_minor=go_data->go7007sb_minor;buf=go_data->out_buf;if(!buf){return -ENOMEM;}dev=go_data->go7007sb_dev;result=0;wr_expires=GO7007SB_WR_EXPIRE;while((count=kernel_read(fp,fp->f_pos,buf,OUT_URB_BUF_SZ))>0){this_write=(count < OUT_URB_BUF_SZ) ? count : OUT_URB_BUF_SZ;result=usb_bulk_msg(dev,usb_sndbulkpipe(dev,go_data->bulk_out_ep),buf,this_write,&partial,GO7007SB_WR_TIMEOUT);if(result==USB_ST_TIMEOUT && !partial){ //timed out and no data writen if(--wr_expires<=0){err("download_file(%d):downloading file timed out!",go_minor);break;}elsecontinue;}else if(result==-EPIPE){ //endpoint halted, try to repare itif(usb_clear_halt(dev,go_data->bulk_out_ep)){err("download_file(%d):bulk out endpoint halted!",go_minor);break;}continue; //if halt condition cleared}else if(result<0){ //we can not torrent any error in downloadingerr("download_file(%d):downloading file failed!",go_minor);break;}fp->f_pos+=partial;}return result;}///////////////////////////////////////////////////////////////////// go7007sb device file operations definition block////////////////////////////////////////////////////////////////////**function:open_go7007sb - to open the device*/static int open_go7007sb(struct inode *inode,struct file *file){struct go7007sb_usb_data *go_data;struct usb_device *dev;kdev_t go_minor;int err=0;down(&go7007sb_mutex);go_minor=USB_GO7007SB_MINOR(inode);dbg("open_go7007sb(%d): try to open device",go_minor);go_data=p_go7007sb_data_table[go_minor];if(!go_data){printk("<1>open_go7007sb(%d):unable to get private data of devide\n",go_minor);err=-ENODEV;goto out_error;}dev=go_data->go7007sb_dev;if(!dev){printk("<1>open_go7007sb(%d):device is not present!\n",go_minor);err=-ENODEV;goto out_error;}if(!go_data->present){printk("<1>open_go7007sb(%d):device is not present!\n",go_minor);err=-ENODEV;goto out_error;}if(go_data->isopen){printk("<1>open_go7007sb(%d):device is already opened!\n",go_minor);err=-EBUSY;goto out_error;}if(get_state(go_data)!=GO7007SB_STATE_READY){printk("<1>open_go7007sb(%d):device is not ready!\n",go_minor);err=-ENODEV;goto out_error;}down(&go_data->sem);/**then send the "start coding" command*/if((err=send_command(go_data,GO7007SB_CMD_START))!=0){printk("<1>open_go7007sb(%d):send \"start\" command failed!\n",go_minor);up(&go_data->sem);goto out_error;}up(&go_data->sem); //release the mutex before sleeping/**wait for the processing of command*/interruptible_sleep_on_timeout(&go_data->wr_wait_q,GO7007SB_WR_TIMEOUT);down(&go_data->sem); //regain the mutexif(signal_pending(current)){up(&go_data->sem);err=-EINTR;goto out_error;}if(get_state(go_data)!=GO7007SB_STATE_RUNNING){printk("<1>open_go7007sb(%d):process \"start\" command failed!\n",go_minor);up(&go_data->sem);err=-EAGAIN;goto out_error;}dbg("open_go7007sb(%d):device opened!",go_minor);go_data->isopen=1;up(&go_data->sem);file->private_data=go_data;MOD_INC_USE_COUNT;out_error:up(&go7007sb_mutex );return err;}/**function:close_go7007sb - to close the device*/static int close_go7007sb(struct inode *inode,struct file *file){struct go7007sb_usb_data *go_data;kdev_t go_minor;int err=0;down(&go7007sb_mutex);go_minor=USB_GO7007SB_MINOR(inode);dbg("close_go7007sb(%d):try to close device",go_minor);go_data=p_go7007sb_data_table[go_minor];if(!go_data){printk("<1>close_go7007sb(%d):invalid device minor\n",go_minor);err=-ENODEV;goto out_error;}down(&go_data->sem);if((err=send_command(go_data,GO7007SB_CMD_PAUSE))!=0){printk("<1>close_go7007sb(%d):send \"pause\" command failed!\n",go_minor);up(&go_data->sem);goto out_error;}up(&go_data->sem);interruptible_sleep_on_timeout(&go_data->wr_wait_q,GO7007SB_WR_TIMEOUT);down(&go_data->sem);if(signal_pending(current)){up(&go_data->sem);err=-EINTR;goto out_error;}if(get_state(go_data)!=GO7007SB_STATE_READY){printk("<1>close_go7007sb(%d):send \"pause\" command failed!\n",go_minor);err=-EAGAIN;up(&go_data->sem);goto out_error;}dbg("close_go7007sb:device(%d):device closed!\n",go_minor);go_data->isopen=0;up(&go_data->sem);file->private_data=NULL;MOD_DEC_USE_COUNT;out_error:up(&go7007sb_mutex);return err;}/**function:read_go7007sb - to read data from go7007sb device*/static ssize_t read_go7007sb(struct file *file,char *buffer,size_t count,loff_t *ppos){struct go7007sb_usb_data *go_data;struct usb_device *dev;ssize_t ret; //return valuessize_t bytes_read; //totally bytes readkdev_t go_minor;int result; //function statusint partial; //actually bytes per readint this_read; //bytes wanted per readint rd_expire; //how many timeouts will drive us mad char *urb_buf;go_data=file->private_data;down(&go_data->sem); //enter the critical sectiondev=go_data->go7007sb_dev;go_minor=go_data->go7007sb_minor;urb_buf=go_data->in_buf;bytes_read=0;ret=0;rd_expire=GO7007SB_RD_EXPIRE;/**update the access time*/file->f_dentry->d_inode->i_atime=CURRENT_TIME;while(count>0){this_read=(count > IN_URB_BUF_SZ) ? IN_URB_BUF_SZ : count;result=usb_bulk_msg(dev,usb_rcvbulkpipe(dev,go_data->bulk_in_ep),urb_buf,this_read,&partial,GO7007SB_RD_TIMEOUT);/**now check the return status of submited urb*/if(result==-ETIMEDOUT){ //timed outif(!partial){ //no data readif(--rd_expire<=0){warn("read_go7007sb(%d):excessive NAKs received!",go_minor);ret=result;break;}else //keep trying to read datacontinue;}else //timed out,but did receive some datagoto data_rcvd;if(result==-EPIPE){ //endpoint halted, try to recover itif(usb_clear_halt(dev,go_data->bulk_in_ep))err("read_go7007sb(%d):failed to clear endpoint halt condition!",go_minor);ret=result;break;}}else if(result<0 && result!=USB_ST_DATAUNDERRUN){//funky packetwarn("read_scanner(%d):funky result!",go_minor);ret=-EIO;break;}data_rcvd:if(partial){ //there received some dataif(copy_to_user(buffer,urb_buf,partial)){//copy data to user's bufferret=-EFAULT;break;}count-=partial; //update bytes leftbytes_read+=partial; //update bytes have been readbuffer+=partial; //adjust buffer pointer}else{ //no error or data-underrun,but read 0 byte ret=0;break;}}//whileup(&go_data->sem);return ret ? ret : bytes_read;}/**function:write_go7007sb - to write data to go7007sb device,*commonly,this happens when trying to initialize the device*/static ssize_t write_go7007sb(struct file *file,const char *buffer,size_t count,loff_t *ppos){/**write operation is not allowed*/return -EOPNOTSUPP;}/**function:ioctl_go7007sb - to control the device*/static int reset_go7007sb(struct go7007sb_usb_data *go_data){kdev_t go_minor=go_data->go7007sb_minor;int err=0;down(&go_data->sem);*reset the state*/set_state(go_data,GO7007SB_STATE_NOTBOOTED);/**this command has no response,if succeeded,*go7007sb will send BootA irq to the host*/if((err=send_command(go_data,GO7007SB_CMD_SOFTRESET))!=0){printk("<1>reset_go7007sb(%d):send \"reset\" command failed!\n",go_minor);goto out_error;}/**then we must wait for the boot and initial procedure done*so sleep and wait for the state is set to "standby", and*then send the start-coding command to the device*/up(&go_data->sem); //release mutex before sleepingerr=wait_event_interruptible(go_data->wr_wait_q,get_state(go_data)==GO7007SB_STATE_READY);if(!err) //interrupted by signalsreturn err;down(&go_data->sem); //regain the mutexif((err=send_command(go_data,GO7007SB_CMD_START))!=0){printk("<1>reset_go7007sb(%d):send \"start\" command failed!\n",go_minor);goto out_error;}/**wait for the device to start coding*/up(&go_data->sem);interruptible_sleep_on_timeout(&go_data->wr_wait_q,GO7007SB_WR_TIMEOUT);down(&go_data->sem);if(signal_pending(current)){err=-EINTR;goto out_error;}if(get_state(go_data)!=GO7007SB_STATE_RUNNING){printk("<1>reset_go7007sb(%d):process \"start\" command failed!\n",go_minor);err=-EAGAIN;goto out_error;}dbg("reset_go7007sb(%d):reset device succeeded!",go_minor);out_error:up(&go_data->sem);return err;}static int shutdown_go7007sb(struct go7007sb_usb_data *go_data){int err=0;kdev_t go_minor=go_data->go7007sb_minor;down(&go_data->sem);if((err=send_command(go_data,GO7007SB_CMD_SHUTDOWN))!=0){printk("<1>shutdown_go7007sb(%d):send \"shutdown\" command failed!\n",go_minor);goto out_error;}up(&go_data->sem); //release mutex before sleepinginterruptible_sleep_on_timeout(&go_data->wr_wait_q,GO7007SB_WR_TIMEOUT);down(&go_data->sem); //regain mutexif(signal_pending(current)){err=-EINTR;goto out_error;}if(get_state(go_data)!=GO7007SB_STATE_HALTED){printk("<1>shutdown_go7007sb(%d):process \"shutdown\" command failed\n",go_minor);err=-EAGAIN;goto out_error;}dbg("shutdown_go7007sb(%d):shutdown device succeeded!",go_minor);out_error:up(&go_data->sem);return err;}static int pause_go7007sb(struct go7007sb_usb_data *go_data){int err=0;kdev_t go_minor=go_data->go7007sb_minor;down(&go_data->sem);if((err=send_command(go_data,GO7007SB_CMD_PAUSE))!=0){printk("<1>pause_go7007sb(%d):send \"pause\" command failed!\n",go_minor);goto out_error;}up(&go_data->sem); //release mutex before sleepinginterruptible_sleep_on_timeout(&go_data->wr_wait_q,GO7007SB_WR_TIMEOUT);down(&go_data->sem); //regain mutexif(signal_pending(current)){err=-EINTR;goto out_error;}if(get_state(go_data)!=GO7007SB_STATE_PAUSED){printk("<1>pause_go7007sb(%d):process \"pause\" command failed\n",go_minor);err=-EAGAIN;goto out_error;}dbg("pause_go7007sb(%d):pause device succeeded!",go_minor);out_error:up(&go_data->sem);return err;}static int resume_go7007sb(struct go7007sb_usb_data *go_data){int err=0;kdev_t go_minor=go_data->go7007sb_minor;down(&go_data->sem);if((err=send_command(go_data,GO7007SB_CMD_START))!=0){printk("<1>resume_go7007sb(%d):send \"resume\" command failed!\n",go_minor);goto out_error;}up(&go_data->sem); //release mutex before sleepinginterruptible_sleep_on_timeout(&go_data->wr_wait_q,GO7007SB_WR_TIMEOUT);down(&go_data->sem); //regain mutexif(signal_pending(current)){err=-EINTR;goto out_error;}if(get_state(go_data)!=GO7007SB_STATE_RUNNING){printk("<1>resume_go7007sb(%d):process \"resume\" command failed\n",go_minor);err=-EAGAIN;goto out_error;}dbg("resume_go7007sb(%d):resume device succeeded!",go_minor);out_error:up(&go_data->sem);return err;}static int ioctl_go7007sb(struct inode *inode,struct file *file, unsigned int cmd,unsigned long arg) {struct usb_device *dev;struct go7007sb_usb_data *go_data;int result;kdev_t go_minor;go_data=(struct go7007sb_usb_data *)file->private_data;dev=go_data->go7007sb_dev;go_minor=USB_GO7007SB_MINOR(inode);switch(cmd){case GO7007SB_IOC_GETSTATE :down(&go_data->sem);result=put_user(get_state(go_data),(int *)arg);up(&go_data->sem);break;case GO7007SB_IOC_RESET :result=reset_go7007sb(go_data);break;case GO7007SB_IOC_SHUTDOWN :result=shutdown_go7007sb(go_data);break;case GO7007SB_IOC_PAUSE :result=pause_go7007sb(go_data);break;case GO7007SB_IOC_RESUME :result=resume_go7007sb(go_data);default:result=-ENOIOCTLCMD;}return result;}/**global variable:usb_go7007sb_fops - this variable*defines the operations of go7007sb,the functions*in the struct will be called when access the device*/static struct file_operations usb_go7007sb_fops={owner: THIS_MODULE,read: read_go7007sb,write: write_go7007sb,ioctl: ioctl_go7007sb,open: open_go7007sb,release: close_go7007sb,};/////////////////////////////////////////////////////////////////////// //// go7007sb device driver definition block///////////////////////////////////////////////////////////////////////// /**functions to handle interrupts from go7007sb,*if succeed,return 0, otherwise, return a nonzero number*/static int handle_go7007sb_boot(struct go7007sb_usb_data *go_data){struct file *fm_fp;int retval;kdev_t go_minor=go_data->go7007sb_minor;/**get the file-pointers of firmware and init config packet files*if failed, boot procedure will abort*/if(!(fm_fp=locate_vendor_image(PKT_TYPE_FIRMWARE))){printk("<1>handle_go7007sb_boot(%d):could not locate firmware file!\n",go_minor);return retval;}down(&go_data->sem);/**now send the "start boot" command to the device through bulk out endpoint*this command notify the device we will begin to download firmware data.*/if((retval=send_command(go_data,GO7007SB_CMD_BOOT))<0){printk("<1>handle_go7007sb_boo(%d)t:send \"boot\" command failed!\n",go_minor);goto failed;}/**the begin download the data*/if((retval=download_file(go_data,fm_fp))!=0){printk("<1>handle_go7007sb_boot(%d):download firmware failed!\n",go_minor);goto failed;}set_state(go_data,GO7007SB_STATE_BOOTDONE);goto out;failed:set_state(go_data,GO7007SB_STATE_BOOTFAILED);out:up(&go_data->sem);wake_up_interruptible(&go_data->wr_wait_q);return retval;}static int handle_go7007sb_init(struct go7007sb_usb_data *go_data){struct file *cfg_fp;int retval;kdev_t go_minor=go_data->go7007sb_minor;/**get the file pointer of init configuration packet*/retval=-EINVAL;if(!(cfg_fp=locate_vendor_image(PKT_TYPE_INITPKT))){printk("<1>handle_go7007sb_init(%d):could not locate init packet file!\n",go_minor);return retval;}down(&go_data->sem);/**then download the file*/if((retval=download_file(go_data,cfg_fp))!=0){printk("<1>handle_go7007sb_init(%d):download init packet failed!\n",go_minor);goto failed;}set_state(go_data,GO7007SB_STATE_READY);dbg("handle_go7007sb_init(%d):device is now ready!",go_minor);goto out;failed:set_state(go_data,GO7007SB_STATE_INITFAILED);out:up(&go_data->sem);wake_up_interruptible(&go_data->wr_wait_q);return retval;}static int handle_go7007sb_run(struct go7007sb_usb_data *go_data){down(&go_data->sem);/**just need to change the state*/set_state(go_data,GO7007SB_STATE_RUNNING);up(&go_data->sem);/**wakeup the process in the wr_wait_q*it slept after sending the command*/wake_up_interruptible(&go_data->wr_wait_q);return 0;}static int handle_go7007sb_pause(struct go7007sb_usb_data *go_data) {down(&go_data->sem);/**just need to change the state*/set_state(go_data,GO7007SB_STATE_READY);up(&go_data->sem);wake_up_interruptible(&go_data->wr_wait_q);return 0;}static int handle_go7007sb_shutdown(struct go7007sb_usb_data *go_data) {down(&go_data->sem);/**just need to change the state*/。

相关文档
最新文档