USB驱动程序编写
USB接口通信(驱动)的设计与实现
![USB接口通信(驱动)的设计与实现](https://img.taocdn.com/s3/m/62c92659f01dc281e53af01c.png)
引言WDM是“Windows驱动程序模型”的简称,即“Windows Driver Model”。
实际上它是一系列集成在操作系统之中的常规系统服务集,用于简化硬件驱动程序的编写,并保证它们在Windows 98/Me/2000中的二进制兼容,WDM(Windows Driver Model)模型是从WinNT3.51和WinNT4的内核模式设备驱动程序发展而来的。
WDM主要的变化是增加了对即插即用、电源管理、Windows Management Interface(WMI)、设备接口的支持。
WDM模型的主要目标,是实现能够跨平台使用、更安全、更灵活、编制更简单的Windows 设备驱动程序。
WDM采用了“基于对象”的技术,建立了一个分层的驱动程序结构。
WDM 首先在Windows98中实现,在Windows2000中得到了进一步的完善,并在后续开发的Windows操作系统中都将存在,比如Windows Me和Windows XP。
微软在通过WDM 模型的引入,希望减轻设备驱动程序的开发难度和周期,逐渐规范设备驱动程序的开发,应该说,WDM将成为以后设备驱动程序的主流。
USB技术的全称是通用串行总线,是英文Universal Serial Bus的缩写。
它是一种应用在PC领域的新型接口技术,虽然USB2.0已经被广泛应用,但是初始的Windows 2000是支持USB1.0协议的,如果希望支持USB2.0协议,需要在微软网站上下载升级包。
实际上,对于键盘或者鼠标来说,传输的速度非常小,使用USB1.0或者是USB2.0的区别并不大。
闪存盘之类的存储设备,则需要重视传输速度。
USB1.0版本主要应用在鼠标,键盘等HID设备上,这就是本驱动程序中引用的头文件版本是USB1.0的原因。
本毕业设计的目的是希望对Windows 2000操作系统体系结构和驱动程序开发以及调试等方面的问题有一个比较深入的了解,对USB协议和USB体系有做一个比较深入的了解。
USB驱动程序的编写采用WDM 驱动程序
![USB驱动程序的编写采用WDM 驱动程序](https://img.taocdn.com/s3/m/2c1e74270722192e4536f60f.png)
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设备的驱动程序实现](https://img.taocdn.com/s3/m/7f1f49f91b37f111f18583d049649b6648d709e2.png)
USB设备的驱动程序实现
USB驱动是用来控制使用USB接口的设备的软件程序,其实现是将实
际的硬件设备抽象为虚拟的设备,使其能够在计算机操作系统上应用。
一
般来讲,当你将USB设备插入你的计算机时,它将通过计算机的USB主控
芯片找到USB设备,然后测试它的功能,并决定它是否能够被用来通信,
最后安装相应的驱动程序。
实际的USB驱动程序的实现有若干方法,其中
有两种常用的技术:应用程序编程接口(API)和驱动程序模板。
1、应用程序编程接口(API)
API是一组用于访问操作系统提供的服务和功能的特殊指令序列。
应
用程序编程接口(API)可以用来创建USB驱动程序,其实现包括以下步骤:
(1)定义硬件设备的描述
在编写USB驱动程序时,首先需要定义硬件设备,即定义设备的功能,记录其编号、最大支持通信速率、硬件连接方式、发送和接收设备数据的
方式以及支持的驱动软件要求等信息。
(2)实现设备驱动的关键函数
关键函数是控制USB设备正常工作所必需的函数,包括初始化函数、
发送和接收数据的函数、获取设备状态的函数以及关闭设备的函数等。
嵌入式Linux系统下的USB驱动程序开发
![嵌入式Linux系统下的USB驱动程序开发](https://img.taocdn.com/s3/m/49fc497431b765ce050814ff.png)
程 中 的关键技 术 。
关键 词 : 嵌入 式 ; L i n u x ; U S B ; 驱动 开发 中图分 类号 : T P 3 1 6 文献标 识码 : A
De v e l o p me n t o f US B Dr i v e r Ba s e d o n Em b e d d e d Li n u x S y s t e m
L I C h u n - b o , C HE N We i - f e n g , L A I X u e - j i n
( C h e n g d u U n i v e r s i t y o f T e c h n o l o g y , C h e n g d u 6 1 0 0 5 9 , C h i n a )
Abs t r a c t : The a p pl i c a t i o n s o f Emb e d de d L i n ux s y s t e m a r e mo r e a n d mo r e wi de l y , i t s f u n c t i o ns a r e a l s o mo r e a n d mo r e
H O S T) 、 U S B设 备 ( U S B D E V I C E) 、 U S B 集 线 器
哑 I … ● I _ l C 【 l h 】 i n 国 a I n 集 t e g r 成 a t e d 电 C i r 路 c u i t
————— 珏 斗 。 ]I
嵌入式 L i n u x系统下的 US B驱动程序开发
基于USB接口设备的驱动程序设计
![基于USB接口设备的驱动程序设计](https://img.taocdn.com/s3/m/d1d32e7902768e9951e738ed.png)
De i n o i ePr g a Ba e n US I t ra eDe i e sg fDrv o r m s d o B n e f c v c
TU a g mi g, EIY u g o DUAN o J , I W n — n W o .u , Da — u L ANG ic e g ZHANG e z i XI n J— h n , Xu - h , E Cu
O 引 言
US ( iesl e a u )ห้องสมุดไป่ตู้ 用 串行 总 线 已成 B Unv ra r l s Si B
文 章 编 号 : 10 — 5 6 ( 0 7 50 8 — 3 0 6 1 7 2 0 )0 —0 9 0
2 0 , 12 , 0 7 Vo . 6 No 5 .
基 于 US B接 口设 备 的驱 动程 序 设计
涂 望 明 ,魏友 国,段 道聚 ,梁季 程 ,张 学 志 ,谢存
( 武汉 军 械士 官 学校 火控 雷 达教 研 室 ,湖北 武 汉 4 0 7 ) 3 05 摘 要 :采用 P I B 2芯 片的基 于 US D US D1 B接 口设 备驱 动程 序 ,模 型 最上 层 的 函数驱 动 程序 ,管理 应 用程 序 与较 低 级总 线驱 动 程序 间的通 信 。底 层 的总 线驱 动程 序 ,管 理 函数驱 动程 序 与设 备硬 件 间通信 。中 间的过 滤 器驱 动程 序 , 辅 助 函数 驱 动 程序 与 总线 驱动 程序 .US B设 备 函数驱 动 程序 与 总 线驱 动程 序 ,使 用 I0信 息 包处 理 US / B的 通信 . 同 时 ,根据 US 通信 协议 ,使 用 Dr eWok 的 工具 模块 进 行 WDM 设备 驱 动程 序 的开 发 . B i r rs v 关键 词 :US B接 口;设备 驱 动程 序 ;P I B 2芯 片;Dr eWok D US D1 i r rs v
USB设备驱动程序的研究与开发
![USB设备驱动程序的研究与开发](https://img.taocdn.com/s3/m/ef3b1541cf84b9d528ea7a28.png)
种 例 程 的指 针 等 。其 相关 代码 如下 :
H ̄插 即用例 程人 口 l l J D i r be t > r eE tni > d D v e : r eO jc - D i r xe s n- A d ei v v o c
口。而要 实 现U B 件 设备 与 主机 间 稳定 的数 据 S硬
传 输 ,则 不 可避 免 的要 编 写适 合U B 件要 求 的 S硬
驱 动 程序 。为此 ,本 文结 合 实 例 ,论 述 了U B S 设
备 驱动 程序 的具 体实 现机 制和 开发 方法 。
示 是其 体 系结构 图。
/ R 发送 给下 层 的U B / 将U B S 总线 驱动 程序
D i r bet > aoF n t n【R _ _ R — r eO jc 一 M jru c o I P MJC E v i
A E =D v rae T] rC et;
nSa s sC l S D fo ub tt u =U b a U B I( , r); t l d
4 U B 备 驱 动 程 序 的 实现 S设
驱 动程 序 是一 些例 程 的集 合 ,它 一般 被 动地 存 在 ,以等 待 主 机 系统 软 件 (n 管 理 器 、I PP / O管 理 器 、 电源管 理器 1来 调用 。典 型 的U B 备 驱 S设 动 程序 主要 包 括若 干 例程 ,其 中有 驱 动程 序入 口
31 I P 求包 . R 请
个U B S 系统 的分 层 结 构 。 图 中 ,功 能层 负 责 实 现
U B 备 的特 定 功能 。该 层 不 需 要 理 解U B 体 S设 S具
Silicon Labs USB 驱动程序定制 - AN220说明书
![Silicon Labs USB 驱动程序定制 - AN220说明书](https://img.taocdn.com/s3/m/dd93fc8ab9f67c1cfad6195f312b3169a451ea8a.png)
AN220: USB Driver Customization Many of Silicon Labs' USB devices require device drivers to oper-ate within Windows. Default driver installers are provided for these devices. However, if the devices are customized with a non-default VID and/or PID, the drivers must also be customized. This application note provides a tool that creates custom driver installers for Windows to match a device's configuration. This tool also provides additional driver and installation options, such as silent install.The following drivers are available in this tool:• A Virtual COM Port Driver is available for the CP210x device family.• A WinUSB driver is available for the CP2130 device.•Direct Access Drivers(formerly called USBXpress) are available for the CP210x, C8051F32x, C8051F34x, C8051F38x, C8051T32x, C8051T62x, and EFM8UBx de-vice families.This document describes the steps necessary to customize the Windows device driver installation using the Custom USB Driver Installation Wizard.KEY POINT•Use the Custom USB Driver Installation Wizard to create a custom Windows driver installer with your unique VID/PID and installation options.APPLICABLE DEVICES•CP210x•CP2130•C8051F32x•C8051F34x•C8051F38x•C8051T32x•C8051T62x•EFM8UBxCustomizing Driver Installations 1. Customizing Driver InstallationsThe driver installation is customizable by modifying certain sections of the hardware installation files (.inf). The strings contained in the .inf files affect what is displayed in the “Found New Hardware Wizard” dialogs, Device Manager, and the Registry. The changes to the VID and PID in the driver installation should match the VID and PID contained in the EPROM/FLASH of your product. See “AN721: USBXpress™ Device Configuration and Programming Guide” for more information on changing the VID and PID for your product. Note: Any changes to the Windows installation .inf files will require new Windows Hardware Quality Labs (WHQL) tests.2. Using the Custom USB Driver Installation WizardThe Custom USB Driver Installation Wizard generates a custom driver installation for distribution to end-users. This customized installa-tion consists of modified .inf files, optional installation support files, and driver files for Windows 7/8/8.1/10.The optional installation executable provided can be used to copy driver files and register a device on a PC before or after the device has been connected. It will also add an entry in the add/remove programs listing. When the device is connected to the PC for the first time, the drivers will be installed with little interaction from the user.Note: A customized installation does not contain certified drivers for Windows 7/8/8.1/10. Certification must be performed by Microsoft for the new driver installation. Uncertified drivers cannot be installed in Windows 7/8/8.1/10 except under certain testing conditions.To run the Custom USB Driver Installation Wizard, open CustomUSBDriverWizard.exe, which is included in the AN220SW.zip down-load. The figure below shows the first screen of the Custom USB Driver Installation Wizard. Choose the type of driver installation de-sired. For detailed instructions on creating a custom driver installation, see 3. Creating a Custom Driver . This description goes through the process of customizing a CP210x driver. The process for creating a Direct Access (USBXpress) driver or CP2130 driver is the same as this description, only select “USBXpress WinUSB Driver Installation” or "CP2130 WinUSB Driver Installation" on the starting screenof the wizard, respectively.Figure 2.1. Driver Installation SelectionUsing the Custom USB Driver Installation Wizard3. Creating a Custom DriverThis section describes how to create a custom driver. To begin, choose the type of installation to customize: “Virtual COM Port Driver Installation”, “USBXpress WinUSB Installation”, or "CP2130 WinUSB Driver Installation". Differences between the three installations are noted, but a sample CP210x customization is shown in the figures. Next, determine if an installation executable should be generated (see 3.5 Installation String Options and 3.8 Generation Directory for more information on the generated installer), and click Next.3.1 Driver Certification WarningThe first screen is the warning explaining that the generated driver installation will not be certified. (See figure below.) Click Next to begin customizing your driver installation.Figure 3.1. Driver Certification Warning3.2 Operating System SelectionThe first step in the customization utility (shown in the figure below) is to specify the operating system for which the custom driver is being generated.Figure 3.2. Operating System Selection3.3 String and File Name CustomizationThe next step in the customization utility (shown in Figure 3.3 String and File Customization on page 6) is to specify your preferred strings and filenames. Each field is described in further detail below.3.3.1 Company Name (Long Name for .inf File Entries)The company name appears in the .inf file entries and has a maximum length of 255 characters.3.3.2 Company Abbreviation (Short Name for .inf File Entries)The abbreviation appears in the .inf file entries and has a maximum length of 31 characters.3.3.3 File Name for .infThis field allows for specification of a unique name for the .inf file. The maximum length of this string is eight characters. The generated file will be named xxxxxxxx.inf.Figure 3.3. String and File Customization3.4 VID, PID, and Device Name CustomizationThe next step in the customization utility (shown in Figure 3.4 VID and PID Customization on page 7) allows multiple VID/PID combi-nations in one driver. This entry is also where the Device Name, which appears in Windows Device Manager, is specified. An example for Windows 7 is shown in Figure 3.6 Windows 7 Device Manager Example on page 9.3.4.1 General Device Installation NameThis field is the general description of device installation. This will not appear in Device Manager, but will show up during installation if the user is prompted for a disk.The Device List allows multiple VID and PID combinations to be added to one driver. Current devices can be edited by double-clicking an entry.Figure 3.4. VID and PID CustomizationTo add a new entry, click the Add button. A new dialog box (shown in Figure 3.5 Add VID/PID/Device Name to Installation on page 8) will appear with the following options.3.4.3 Device TypeThis specifies which device is being customized. If the VCP driver for the CP2105 Dual UART Bridge is being customized, two interface names will appear. Likewise, if the VCP driver for the CP2108 Quad UART Bridge is being customized, four interface names will ap-pear. Otherwise, only one interface name will appear.3.4.4 VIDAllows specification of a new vendor ID (VID).3.4.5 PIDAllows specification of a new product ID (PID).This string will be displayed in Device Manager under the Ports or USB tab. If the VCP driver is being customized for a multiple-inter-face bridge device, one string will be displayed per interface.Figure 3.5. Add VID/PID/Device Name to InstallationFigure 3.6. Windows 7 Device Manager ExampleIf an installer is not being generated, then skip to 3.9 Option Verification.3.5 Installation String OptionsThe next step in the customization process is to specify options for the driver installer. The driver installer will allow for a device to be installed before or after a device has been connected to the PC. If this is run before a device is plugged in, drivers will already be regis-tered for devices that belong to that installation. If a device is already plugged in, the installer will rescan the bus for any devices for that installation. This section covers adding the installer's strings and is shown in Figure 3.7 Installation Strings on page 10. The driver installer and its corresponding setup.ini file are explained in further detail in “AN335: USB DRIVER INSTALLATION METHODS”.3.5.1 Product NameThis is the string that identifies the product installation in the Add/Remove Programs listing. The string shows up as “<Product Name String> (Driver Removal)” for easy identification.3.5.2 Name for Installation FileThis is will be the name of the installation executable and shows up as “<InstallName>.exe”.Figure 3.7. Installation Strings3.6 Device OptionsThe next step in the customization utility (shown in 3.6.2 Selective Suspend Support) is to configure the serial enumeration and selec-tive suspend options.3.6.1 Serial Enumeration SupportThis allows Windows to “enumerate” a device(s), such as serial mice or an external modem, connected to the CP210x . If your device always presents data to the PC (such as a GPS device), then disable this to prevent false serial enumerations.3.6.2 Selective Suspend SupportEnabling this feature will put the device to sleep if it has not been opened for a time longer than the specified Timeout Value. This is used to save power on the PC and is recommended unless your CP210x needs to be powered if a handle to the device is not opened.Figure 3.8. Device Options3.7 Installation OptionsSpecific options for the GUI should now be specified.3.7.1 Display GUI Window during InstallCheck this option when using the generated Installer as a stand-alone application. The Installer will display several GUI windows during the installation process. Uncheck this option to run the Installer in Quiet Mode. When running in Quiet Mode, no GUI will be displayed. This is useful when using another application to launch this Installer.3.7.2 Copy Files to Target Directory during Install:Check this option if a copy of the drivers will be needed on the hard drive. This is useful when installing the drivers from a CD. Uncheck this option if copies of the driver files are not needed on the hard drive.3.7.3 Target DirectorySelects the hard drive location that will contain a copy of the driver files. The default location is C:\Program Files\Silabs\MCU\CP210x for the VCP Driver and C:\ProgramFiles\Silabs\MCU\USBXpress for the USBXpress driver. If the “Display GUI window during Installa-tion” option is selected, this path can be changed during installation by clicking the Browse button. However, if the “Display GUI window during Installation” option is not selected, then the default directory is always used unless a directory is specified through the command line. This option is ignored if the “Copy Files to Directory during Setup” option is not selected.Note: The Target Directory must be different for each product released.3.7.4 Display GUI Window during UninstallCheck this option when using the generated Uninstaller as a stand-alone application. The Uninstaller will display several GUI windows during the uninstall process. Uncheck this option if the Uninstaller will be launched by another application. The Uninstaller then runs in Quiet Mode. When running in Quiet Mode, no GUI will be displayed.3.7.5 Remove Files from Target Directory during UninstallCheck this option if the files copied to the Target directory should be removed upon uninstallation. This option is ignored if the “Copy Files to Directory during Setup” option is not selected.Figure 3.9. Installation Options3.8 Generation DirectoryThe next step in the customization utility is to specify where this custom driver’s installation files will be generated. The default directory for a VCP driver is C:\Silabs\MCU\CustomCP210xDriverInstall, and the default for a USBXpress Driver is C:\Silabs\MCU\CustomUSBX-pressDriverInstall. However, a different directory can be selected or created. This step is shown in the figure below.Note: This is not an actual installation of the drivers. This is simply a directory to output all installation files needed for the installation. These files can be added to a CD or OEM installation for distribution to the end-user.Figure 3.10. Generation Directory3.9 Option VerificationThe final step in the customization utility is to review all of the selected options. If anything needs to be changed, the Back button can be used to go back to previous pages to change items. Once all options have been verified, press Finish to create the customized driver files. This step is shown in the figure below.Figure 3.11. Option VerificationCustomizing Driver Installations, macOS (Mac OS X) 4. Customizing Driver Installations, macOS (Mac OS X)If the VID or PID is changed from the default factory settings, contact Silicon Laboratories Support (https:///support) to obtain drivers that incorporate the new values. Mac OS X requires that the drivers be compiled with the values that will be used by the production CP210x device.Revision History 5. Revision HistoryRevision 1.1Jun, 2021•Updated the title of AN335.•Replaced the AN144 with the AN721.•Updated Figure 3.2.Revision 1.0August, 2018•Converted to new Appnote format.•Updated screenshots to match the current release of the customization tool.•Added references to CP2130 driver.•Updated Windows versions to currently supported versions 7/8/8.1/10.•Updated references to USBXpress drivers to mention the current name "Direct Access Drivers."•Added EFM8UBx devices to supported device list.Revision 0.7•Added CP2108 to Relevant Devices list.Revision 0.6•Added support for C8051F38x, C8051T32x, and C8051T62x devices.•Updated Figures 1 through 12.Revision 0.5•Added support for CP2104 and CP2105.•Added support for Windows 7.•Updated all screen shots of the AN220 software.•Updated explanations of AN220 software.Revision 0.4•Updated diagrams and wording to reflect 4.1 and later versions of the Custom Driver Wizard.•Updated to include documented support of C8051F34x devices.•Updated to reflect Vista support.Revision 0.3•Updated figures and customization description to reflect version 3.4 and later of the Custom Driver Wizard.•Removed USBXpress specific customization description. Version 3.4 and later contains the same process for customizing both VCP and USBXpress driver installations.•Removed preinstaller explanations and added descriptions on how the new Driver Installer is used.Revision 0.2•Added CP2103 to Relevant Devices on page 1.Revision 0.1•Initial revision.Silicon Laboratories Inc.400 West Cesar Chavez Austin, TX 78701USAIoT Portfolio/IoTSW/HW/simplicityQuality /qualitySupport & Community/communityDisclaimerSilicon Labs intends to provide customers with the latest, accurate, and in-depth documentation of all peripherals and modules available for system and software imple-menters using or intending to use the Silicon Labs products. Characterization data, available modules and peripherals, memory sizes and memory addresses refer to each specific device, and “Typical” parameters provided can and do vary in different applications. Application examples described herein are for illustrative purposes only. Silicon Labs reserves the right to make changes without further notice to the product information, specifications, and descriptions herein, and does not give warranties as to the accuracy or completeness of the included information. Without prior notification, Silicon Labs may update product firmware during the manufacturing process for security or reliability reasons. Such changes will not alter the specifications or the performance of the product. Silicon Labs shall have no liability for the consequences of use of the infor -mation supplied in this document. This document does not imply or expressly grant any license to design or fabricate any integrated circuits. The products are not designed or authorized to be used within any FDA Class III devices, applications for which FDA premarket approval is required or Life Support Systems without the specific written consent of Silicon Labs. A “Life Support System” is any product or system intended to support or sustain life and/or health, which, if it fails, can be reasonably expected to result in significant personal injury or death. Silicon Labs products are not designed or authorized for military applications. Silicon Labs products shall under no circumstances be used in weapons of mass destruction including (but not limited to) nuclear, biological or chemical weapons, or missiles capable of delivering such weapons. Silicon Labs disclaims all express and implied warranties and shall not be responsible or liable for any injuries or damages related to use of a Silicon Labs product in such unauthorized applications. Note: This content may contain offensive terminology that is now obsolete. Silicon Labs is replacing these terms with inclusive language wherever possible. For more information, visit /about-us/inclusive-lexicon-projectTrademark InformationSilicon Laboratories Inc.®, Silicon Laboratories ®, Silicon Labs ®, SiLabs ® and the Silicon Labs logo ®, Bluegiga ®, Bluegiga Logo ®, Clockbuilder ®, CMEMS ®, DSPLL ®, EFM ®, EFM32®, EFR, Ember ®, Energy Micro, Energy Micro logo and combinations thereof, “the world’s most energy friendly microcontrollers”, Ember ®, EZLink ®, EZRadio ®, EZRadioPRO ®, Gecko ®, Gecko OS, Gecko OS Studio, ISOmodem ®, Precision32®, ProSLIC ®, Simplicity Studio ®, SiPHY ®, Telegesis, the Telegesis Logo ®, USBXpress ® , Zentri, the Zentri logo and Zentri DMS, Z-Wave ®, and others are trademarks or registered trademarks of Silicon Labs. ARM, CORTEX, Cortex-M3 and THUMB are trademarks or registered trademarks of ARM Hold-ings. Keil is a registered trademark of ARM Limited. Wi-Fi is a registered trademark of the Wi-Fi Alliance. All other products or brand names mentioned herein are trademarks of their respective holders.。
Windows下的USB驱动程序 简单框架
![Windows下的USB驱动程序 简单框架](https://img.taocdn.com/s3/m/a533c21c0c22590103029d17.png)
设备非自然弹出 USB设备对应操作
IRP_MN_SURPRISE_REMOVAL
IRP_MJ_PNP
来自: 即插即用管理器
注册标准的WDM回调(Callback)函数
USB设备读写 USB设备热插拔 USB设备初始化
பைடு நூலகம்
Windows下的USB驱动程序 简单框架
(背景知识)
USB功能驱动(FDO)
IRP(URB为参数)
a 尽快结束IRP并逐个取消掉 b 标记设备扩展当前状态为“停止”
设备关闭前 USB驱动程序对应操作
IRP_MN_STOP_DEVICE
a 强迫结束并取消 所有未完成的读写IRP b 标记设备状态为被拔掉
设备正常弹出前 USB驱动程序对应操作
IRP_MN_EJECT
a 强迫结束并取消 所有未完成的读写IRP b 标记设备状态为被拔掉
等待完成IRP
同步
(不做处理)
异步(STATUS_PENDING)
KeWaitForSingleObject
设备堆栈
USB物理总线驱动(PDO) 解释 转化 请求
USB Host 或 USB Hub驱动
PDO完成了大部分工作, 封装了USB协议细节
并为FDO提供了标准的接口
端点描述符
描述处理事务(Transaction)的端点 接口描述符
各种描述符
描述设备提供的功能接口
配置描述符
自下而上 (除端点描述符 可以为0个之外)
设置 IRP_MJ_READ / IRP_MJ_WRITE 派遣函数 调用 API 进行 ReadFile / WriteFile
驱动程序 应用程序
80%走Bulk管道
Linux系统下USB驱动程序的设计与开发
![Linux系统下USB驱动程序的设计与开发](https://img.taocdn.com/s3/m/c73216056c85ec3a87c2c509.png)
Ln x g iu  ̄ 动程序 的架构 , 分析 了US B设备 的用途与角 色, 出 了US 给 B程序 的设计 和开发 实现 。
关键词 :Ln x i ;US u B;设备 ;驱动程序 ;程序设 计 中图分类号 : P 1 T 39 文献标识码 : A 文章编号 :0 6 8 2 (0 1 O — 7 0 1 0 — 2 8 2 1 )7 3 — 2
究了 US B驱动程序的实现技术 。
每 次只能有 一个配 置是可 用的 , 而一旦 该配置 激活 , 的接 里面
口和端 口就 都可 以同时使 用 。主机 根据 设备发过 来的描述 符
1 Ln x 动 程序 基础 iu 驱
设备驱动程序是 操作系统 内核和机器 硬件之间 的接 口, 为
中来判 断用的是哪个配置或 哪个 接 口等等 , 而这些描述字 符通
点, 已被广泛应用在 P C机及嵌入式 系统上 。
一
般称作 为缺 省管道 。对于 同样性质 的一组 端 口的组 合叫作
在已经研制的家庭网关中,P C U通过自带的U B S 接口控制 接 口, 如果—个设备包含不 止 —个接 口, 就可以称之为复合设备。 U B设备 。本 文介 绍了 Lnx S i 驱动 程序的架构 和总线 , 点研 u 重 同理 , 于同样类型 的接 口的组合可 以称之 为配置。但是 对
对设备进行初始化, 使设备投入运行和退出服务; 把数据从内核 主机用主, 副协议来 与外 部U B设备通讯 。U B上的通汛主要 S S 传送到设备和从设备接受数据; 检测和处理设备出现的错误等 。 两个方 向进行 : 一个是 主机 到设备的下行方 向 ,一个是设备到
Lnx 统的设 备一般 分为字 符设备 、 设备 和网络 设备 主机的上行方 向 , i 系 u 块 不支持设 备间的直接通 讯。依 靠不同的设备 三种 。字符 设备是 指存取 时没有缓 存的设 备 。块 设备 的读 写 类 型 , S U B主 要 有 四 种 数 据 传 输 方 式 : 制 ( n o) 中断 : 控 c t 1、 or
(简易USB驱动)开发指导
![(简易USB驱动)开发指导](https://img.taocdn.com/s3/m/ec75393b580216fc700afdf3.png)
实验七(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块设备)的实际访问操作。
如何编写Linux下的USB键盘驱动
![如何编写Linux下的USB键盘驱动](https://img.taocdn.com/s3/m/9867af4d2b160b4e767fcf3d.png)
{
int result = usb_register(&usb_kbd_driver);/*注册USB键盘驱动*/
if (result == 0) /*注册失败*/
info(DRIVER_VERSION ":" DRIVER_DESC);
return result;
}
7. 编写模块卸载函数(每个驱动都会有一个卸载函数,由 module_exit 调用):
/*若同时只按下1个按键则在第[2]个字节,若同时有两个按键则第二个在第[3]字节,类推最多 可有6个按键同时按下*/ for (i = 2; i < 8; i++) { /*获取键盘离开的中断*/
if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {/* 同时没有该KEY的按下状态*/
if (usb_kbd_keycode[kbd->old[i]]) {
input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); } else
info("Unknown key (scancode %#x) released.", kbd->old[i]); }
接口类;鼠标为3,1,2*/
{}
/* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);/*指定设备 ID 表*/
4. 定义 USB 键盘结构体:
USB键盘驱动程序
![USB键盘驱动程序](https://img.taocdn.com/s3/m/83f44755227916888486d77f.png)
/** $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $** Copyright (c) 1999-2001 Vojtech Pavlik** USB HIDBP Keyboard support*//** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** Should you need to contact me, the author, you can do so either by* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic*/#include <linux/kernel.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/input.h>#include <linux/init.h>#include <linux/usb.h>#include <linux/usb_input.h>/** Version Information*/#define DRIVER_VERSION ""#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"#define DRIVER_LICENSE "GPL"MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE(DRIVER_LICENSE);static unsigned char usb_kbd_keycode[256] = {0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,150,158,159,128,136,177,178,176,142,152,173,140};struct usb_kbd {struct input_dev *dev;struct usb_device *usbdev;unsigned char old[8];struct urb *irq, *led;unsigned char newleds;char name[128];char phys[64];unsigned char *new;struct usb_ctrlrequest *cr;unsigned char *leds;dma_addr_t cr_dma;dma_addr_t new_dma;dma_addr_t leds_dma;};static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs){struct usb_kbd *kbd = urb->context;int i;switch (urb->status) {case 0: /* success */break;case -ECONNRESET: /* unlink */case -ENOENT:case -ESHUTDOWN:return;/* -EPIPE: should clear the halt */default: /* error */goto resubmit;}input_regs(kbd->dev, regs);for (i = 0; i < 8; i++)input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);for (i = 2; i < 8; i++) {if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { if (usb_kbd_keycode[kbd->old[i]])input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);elseinfo("Unknown key (scancode %#x) released.", kbd->old[i]);}if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { if (usb_kbd_keycode[kbd->new[i]])input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);elseinfo("Unknown key (scancode %#x) pressed.", kbd->new[i]);}}input_sync(kbd->dev);memcpy(kbd->old, kbd->new, 8);resubmit:i = usb_submit_urb (urb, SLAB_ATOMIC);if (i)err ("can't resubmit intr, %s-%s/input0, status %d",kbd->usbdev->bus->bus_name,kbd->usbdev->devpath, i);}static int usb_kbd_event(struct input_dev *dev, unsigned int type,unsigned int code, int value){struct usb_kbd *kbd = dev->private;if (type != EV_LED)return -1;kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |(!!test_bit(LED_NUML, dev->led));if (kbd->led->status == -EINPROGRESS)return 0;if (*(kbd->leds) == kbd->newleds)return 0;*(kbd->leds) = kbd->newleds;kbd->led->dev = kbd->usbdev;if (usb_submit_urb(kbd->led, GFP_ATOMIC))err("usb_submit_urb(leds) failed");return 0;}static void usb_kbd_led(struct urb *urb, struct pt_regs *regs){struct usb_kbd *kbd = urb->context;if (urb->status)warn("led urb status %d received", urb->status);if (*(kbd->leds) == kbd->newleds)return;*(kbd->leds) = kbd->newleds;kbd->led->dev = kbd->usbdev;if (usb_submit_urb(kbd->led, GFP_ATOMIC))err("usb_submit_urb(leds) failed");}static int usb_kbd_open(struct input_dev *dev){struct usb_kbd *kbd = dev->private;kbd->irq->dev = kbd->usbdev;if (usb_submit_urb(kbd->irq, GFP_KERNEL))return -EIO;return 0;}static void usb_kbd_close(struct input_dev *dev){struct usb_kbd *kbd = dev->private;usb_kill_urb(kbd->irq);}static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd){if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))return -1;if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))return -1;if (!(kbd->new = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbd->new_dma)))return -1;if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), SLAB_ATOMIC, &kbd->cr_dma)))return -1;if (!(kbd->leds = usb_buffer_alloc(dev, 1, SLAB_ATOMIC, &kbd->leds_dma)))return -1;return 0;}static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd){if (kbd->irq)usb_free_urb(kbd->irq);if (kbd->led)usb_free_urb(kbd->led);if (kbd->new)usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);if (kbd->cr)usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);if (kbd->leds)usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);}static int usb_kbd_probe(struct usb_interface *iface,const struct usb_device_id *id){struct usb_device *dev = interface_to_usbdev(iface);struct usb_host_interface *interface;struct usb_endpoint_descriptor *endpoint;struct usb_kbd *kbd;struct input_dev *input_dev;int i, pipe, maxp;interface = iface->cur_altsetting;if (interface->desc.bNumEndpoints != 1)return -ENODEV;endpoint = &interface->endpoint[0].desc;if (!(endpoint->bEndpointAddress & USB_DIR_IN))return -ENODEV;if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)return -ENODEV;pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);input_dev = input_allocate_device();if (!kbd || !input_dev)goto fail1;if (usb_kbd_alloc_mem(dev, kbd))goto fail2;kbd->usbdev = dev;kbd->dev = input_dev;if (dev->manufacturer)strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));if (dev->product) {if (dev->manufacturer)strlcat(kbd->name, " ", sizeof(kbd->name));strlcat(kbd->name, dev->product, sizeof(kbd->name));}if (!strlen(kbd->name))snprintf(kbd->name, sizeof(kbd->name),"USB HIDBP Keyboard %04x:%04x",le16_to_cpu(dev->descriptor.idVendor),le16_to_cpu(dev->descriptor.idProduct));usb_make_path(dev, kbd->phys, sizeof(kbd->phys));strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));input_dev->name = kbd->name;input_dev->phys = kbd->phys;usb_to_input_id(dev, &input_dev->id);input_dev->cdev.dev = &iface->dev;input_dev->private = kbd;input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);for (i = 0; i < 255; i++)set_bit(usb_kbd_keycode[i], input_dev->keybit);clear_bit(0, input_dev->keybit);input_dev->event = usb_kbd_event;input_dev->open = usb_kbd_open;input_dev->close = usb_kbd_close;usb_fill_int_urb(kbd->irq, dev, pipe,kbd->new, (maxp > 8 ? 8 : maxp),usb_kbd_irq, kbd, endpoint->bInterval);kbd->irq->transfer_dma = kbd->new_dma;kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;kbd->cr->bRequest = 0x09;kbd->cr->wValue = cpu_to_le16(0x200);kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);kbd->cr->wLength = cpu_to_le16(1);usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),(void *) kbd->cr, kbd->leds, 1,usb_kbd_led, kbd);kbd->led->setup_dma = kbd->cr_dma;kbd->led->transfer_dma = kbd->leds_dma;kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);input_register_device(kbd->dev);usb_set_intfdata(iface, kbd);return 0;fail2:usb_kbd_free_mem(dev, kbd);fail1:input_free_device(input_dev);kfree(kbd);return -ENOMEM;}static void usb_kbd_disconnect(struct usb_interface *intf){struct usb_kbd *kbd = usb_get_intfdata (intf);usb_set_intfdata(intf, NULL);if (kbd) {usb_kill_urb(kbd->irq);input_unregister_device(kbd->dev);usb_kbd_free_mem(interface_to_usbdev(intf), kbd);kfree(kbd);}}static struct usb_device_id usb_kbd_id_table [] = {{ USB_INTERFACE_INFO(3, 1, 1) },{ } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);static struct usb_driver usb_kbd_driver = {.name = "usbkbd",.probe = usb_kbd_probe,.disconnect = usb_kbd_disconnect,.id_table = usb_kbd_id_table,};static int __init usb_kbd_init(void){int result = usb_register(&usb_kbd_driver);if (result == 0)info(DRIVER_VERSION ":" DRIVER_DESC);return result;}static void __exit usb_kbd_exit(void){usb_deregister(&usb_kbd_driver);}module_init(usb_kbd_init);module_exit(usb_kbd_exit);。
usb 转串口驱动程序
![usb 转串口驱动程序](https://img.taocdn.com/s3/m/8eb0fbfb04a1b0717fd5dd67.png)
* Prolific PL2303 USB to serial adaptor driver** Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@)* Copyright (C) 2003 IBM Corp.** Original driver for 2.2.x by anonymous** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation.** See Documentation/usb/usb-serial.txt for more information on using this * driver**/#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/spinlock.h>#include <linux/uaccess.h>#include <linux/usb.h>#include <linux/usb/serial.h>#include "pl2303.h"/** Version Information*/#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"static int debug;#define PL2303_CLOSING_WAIT (30*HZ)#define PL2303_BUF_SIZE 1024#define PL2303_TMP_BUF_SIZE 1024struct pl2303_buf {unsigned int buf_size;char *buf_buf;char *buf_get;char *buf_put;};static struct usb_device_id id_table [] = {{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },{ } /* Terminating entry */};MODULE_DEVICE_TABLE(usb, id_table);static struct usb_driver pl2303_driver = {.name = "pl2303",.probe = usb_serial_probe,.disconnect = usb_serial_disconnect,.id_table = id_table,.suspend = usb_serial_suspend,.resume = usb_serial_resume,.no_dynamic_id = 1,.supports_autosuspend = 1,};#define SET_LINE_REQUEST_TYPE 0x21#define SET_LINE_REQUEST 0x20#define SET_CONTROL_REQUEST_TYPE 0x21#define SET_CONTROL_REQUEST 0x22#define CONTROL_DTR 0x01#define CONTROL_RTS 0x02#define BREAK_REQUEST_TYPE 0x21#define BREAK_REQUEST 0x23#define BREAK_ON 0xffff#define BREAK_OFF 0x0000#define GET_LINE_REQUEST_TYPE 0xa1#define GET_LINE_REQUEST 0x21#define VENDOR_WRITE_REQUEST_TYPE 0x40#define VENDOR_WRITE_REQUEST 0x01#define VENDOR_READ_REQUEST_TYPE 0xc0#define VENDOR_READ_REQUEST 0x01#define UART_STATE 0x08#define UART_STATE_TRANSIENT_MASK 0x74#define UART_DCD 0x01#define UART_DSR 0x02#define UART_BREAK_ERROR 0x04#define UART_RING 0x08#define UART_FRAME_ERROR 0x10#define UART_PARITY_ERROR 0x20#define UART_OVERRUN_ERROR 0x40#define UART_CTS 0x80enum pl2303_type {type_0, /* don't know the difference between type 0 and */ type_1, /* type 1, until someone from prolific tells us... */HX, /* HX version of the pl2303 chip */};struct pl2303_private {spinlock_t lock;struct pl2303_buf *buf;int write_urb_in_use;wait_queue_head_t delta_msr_wait;u8 line_control;u8 line_status;enum pl2303_type type;};/** pl2303_buf_alloc** Allocate a circular buffer and all associated memory.*/static struct pl2303_buf *pl2303_buf_alloc(unsigned int size){struct pl2303_buf *pb;if (size == 0)return NULL;pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);if (pb == NULL)return NULL;pb->buf_buf = kmalloc(size, GFP_KERNEL);if (pb->buf_buf == NULL) {kfree(pb);return NULL;}pb->buf_size = size;pb->buf_get = pb->buf_put = pb->buf_buf;return pb;}/** pl2303_buf_free** Free the buffer and all associated memory.*/static void pl2303_buf_free(struct pl2303_buf *pb){if (pb) {kfree(pb->buf_buf);kfree(pb);}}/** pl2303_buf_clear** Clear out all data in the circular buffer.*/static void pl2303_buf_clear(struct pl2303_buf *pb){if (pb != NULL)pb->buf_get = pb->buf_put;/* equivalent to a get of all data available */}/** pl2303_buf_data_avail** Return the number of bytes of data available in the circular * buffer.*/static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb){if (pb == NULL)return 0;return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;}/** pl2303_buf_space_avail** Return the number of bytes of space available in the circular* buffer.*/static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb){if (pb == NULL)return 0;return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size; }/** pl2303_buf_put** Copy data data from a user buffer and put it into the circular buffer.* Restrict to the amount of space available.** Return the number of bytes copied.*/static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,unsigned int count){unsigned int len;if (pb == NULL)return 0;len = pl2303_buf_space_avail(pb);if (count > len)count = len;if (count == 0)return 0;len = pb->buf_buf + pb->buf_size - pb->buf_put;if (count > len) {memcpy(pb->buf_put, buf, len);memcpy(pb->buf_buf, buf+len, count - len);pb->buf_put = pb->buf_buf + count - len;} else {memcpy(pb->buf_put, buf, count);if (count < len)pb->buf_put += count;else /* count == len */pb->buf_put = pb->buf_buf;}return count;}/** pl2303_buf_get** Get data from the circular buffer and copy to the given buffer.* Restrict to the amount of data available.** Return the number of bytes copied.*/static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,unsigned int count){unsigned int len;if (pb == NULL)return 0;len = pl2303_buf_data_avail(pb);if (count > len)count = len;if (count == 0)return 0;len = pb->buf_buf + pb->buf_size - pb->buf_get;if (count > len) {memcpy(buf, pb->buf_get, len);memcpy(buf+len, pb->buf_buf, count - len);pb->buf_get = pb->buf_buf + count - len;} else {memcpy(buf, pb->buf_get, count);if (count < len)pb->buf_get += count;else /* count == len */pb->buf_get = pb->buf_buf;}return count;}static int pl2303_vendor_read(__u16 value, __u16 index,struct usb_serial *serial, unsigned char *buf){int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,value, index, buf, 1, 100);dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index, res, buf[0]);return res;}static int pl2303_vendor_write(__u16 value, __u16 index,struct usb_serial *serial){int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,value, index, NULL, 0, 100);dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index, res);return res;}static int pl2303_startup(struct usb_serial *serial){struct pl2303_private *priv;enum pl2303_type type = type_0;unsigned char *buf;int i;buf = kmalloc(10, GFP_KERNEL);if (buf == NULL)return -ENOMEM;if (serial->dev->descriptor.bDeviceClass == 0x02)type = type_0;else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) type = HX;else if (serial->dev->descriptor.bDeviceClass == 0x00) type = type_1;else if (serial->dev->descriptor.bDeviceClass == 0xFF) type = type_1;dbg("device type: %d", type);for (i = 0; i < serial->num_ports; ++i) {priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);if (!priv)goto cleanup;spin_lock_init(&priv->lock);priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);if (priv->buf == NULL) {kfree(priv);goto cleanup;}init_waitqueue_head(&priv->delta_msr_wait);priv->type = type;usb_set_serial_port_data(serial->port[i], priv);}pl2303_vendor_read(0x8484, 0, serial, buf);pl2303_vendor_write(0x0404, 0, serial);pl2303_vendor_read(0x8484, 0, serial, buf);pl2303_vendor_read(0x8383, 0, serial, buf);pl2303_vendor_read(0x8484, 0, serial, buf);pl2303_vendor_write(0x0404, 1, serial);pl2303_vendor_read(0x8484, 0, serial, buf);pl2303_vendor_read(0x8383, 0, serial, buf);pl2303_vendor_write(0, 1, serial);pl2303_vendor_write(1, 0, serial);if (type == HX)pl2303_vendor_write(2, 0x44, serial);elsepl2303_vendor_write(2, 0x24, serial);kfree(buf);return 0;cleanup:kfree(buf);for (--i; i >= 0; --i) {priv = usb_get_serial_port_data(serial->port[i]);pl2303_buf_free(priv->buf);kfree(priv);usb_set_serial_port_data(serial->port[i], NULL);}return -ENOMEM;}static int set_control_lines(struct usb_device *dev, u8 value){int retval;retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,value, 0, NULL, 0, 100);dbg("%s - value = %d, retval = %d", __func__, value, retval);return retval;}static void pl2303_send(struct usb_serial_port *port){int count, result;struct pl2303_private *priv = usb_get_serial_port_data(port);unsigned long flags;dbg("%s - port %d", __func__, port->number);spin_lock_irqsave(&priv->lock, flags);if (priv->write_urb_in_use) {spin_unlock_irqrestore(&priv->lock, flags);return;}count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,port->bulk_out_size);if (count == 0) {spin_unlock_irqrestore(&priv->lock, flags);return;}priv->write_urb_in_use = 1;spin_unlock_irqrestore(&priv->lock, flags);usb_serial_debug_data(debug, &port->dev, __func__, count,port->write_urb->transfer_buffer);port->write_urb->transfer_buffer_length = count;port->write_urb->dev = port->serial->dev;result = usb_submit_urb(port->write_urb, GFP_ATOMIC);if (result) {dev_err(&port->dev, "%s - failed submitting write urb,"" error %d\n", __func__, result);priv->write_urb_in_use = 0;/* TODO: reschedule pl2303_send */}usb_serial_port_softint(port);}static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,const unsigned char *buf, int count){struct pl2303_private *priv = usb_get_serial_port_data(port);unsigned long flags;dbg("%s - port %d, %d bytes", __func__, port->number, count);if (!count)return count;spin_lock_irqsave(&priv->lock, flags);count = pl2303_buf_put(priv->buf, buf, count);spin_unlock_irqrestore(&priv->lock, flags);pl2303_send(port);return count;}static int pl2303_write_room(struct tty_struct *tty){struct usb_serial_port *port = tty->driver_data;struct pl2303_private *priv = usb_get_serial_port_data(port);int room = 0;unsigned long flags;dbg("%s - port %d", __func__, port->number);spin_lock_irqsave(&priv->lock, flags);room = pl2303_buf_space_avail(priv->buf);spin_unlock_irqrestore(&priv->lock, flags);dbg("%s - returns %d", __func__, room);return room;}static int pl2303_chars_in_buffer(struct tty_struct *tty){struct usb_serial_port *port = tty->driver_data;struct pl2303_private *priv = usb_get_serial_port_data(port);int chars = 0;unsigned long flags;dbg("%s - port %d", __func__, port->number);spin_lock_irqsave(&priv->lock, flags);chars = pl2303_buf_data_avail(priv->buf);spin_unlock_irqrestore(&priv->lock, flags);dbg("%s - returns %d", __func__, chars);return chars;}static void pl2303_set_termios(struct tty_struct *tty,struct usb_serial_port *port, struct ktermios *old_termios) {struct usb_serial *serial = port->serial;struct pl2303_private *priv = usb_get_serial_port_data(port);unsigned long flags;unsigned int cflag;unsigned char *buf;int baud;int i;u8 control;dbg("%s - port %d", __func__, port->number);/* The PL2303 is reported to lose bytes if you change serial settings even to the same values as before. Thuswe actually need to filter in this specific case */if (!tty_termios_hw_change(tty->termios, old_termios)) return;cflag = tty->termios->c_cflag;buf = kzalloc(7, GFP_KERNEL);if (!buf) {dev_err(&port->dev, "%s - out of memory.\n", __func__);/* Report back no change occurred */*tty->termios = *old_termios;return;}i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,0, 0, buf, 7, 100);dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);if (cflag & CSIZE) {switch (cflag & CSIZE) {case CS5:buf[6] = 5;break;case CS6:buf[6] = 6;break;case CS7:buf[6] = 7;break;default:case CS8:buf[6] = 8;break;}dbg("%s - data bits = %d", __func__, buf[6]);}baud = tty_get_baud_rate(tty);dbg("%s - baud = %d", __func__, baud);if (baud) {buf[0] = baud & 0xff;buf[1] = (baud >> 8) & 0xff;buf[2] = (baud >> 16) & 0xff;buf[3] = (baud >> 24) & 0xff;}/* For reference buf[4]=0 is 1 stop bits *//* For reference buf[4]=1 is 1.5 stop bits *//* For reference buf[4]=2 is 2 stop bits */if (cflag & CSTOPB) {buf[4] = 2;dbg("%s - stop bits = 2", __func__);} else {buf[4] = 0;dbg("%s - stop bits = 1", __func__);}if (cflag & PARENB) {/* For reference buf[5]=0 is none parity *//* For reference buf[5]=1 is odd parity *//* For reference buf[5]=2 is even parity *//* For reference buf[5]=3 is mark parity *//* For reference buf[5]=4 is space parity */if (cflag & PARODD) {buf[5] = 1;dbg("%s - parity = odd", __func__);} else {buf[5] = 2;dbg("%s - parity = even", __func__);}} else {buf[5] = 0;dbg("%s - parity = none", __func__);}i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,0, 0, buf, 7, 100);dbg("0x21:0x20:0:0 %d", i);/* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags);control = priv->line_control;if ((cflag & CBAUD) == B0)priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);elsepriv->line_control |= (CONTROL_DTR | CONTROL_RTS);if (control != priv->line_control) {control = priv->line_control;spin_unlock_irqrestore(&priv->lock, flags);set_control_lines(serial->dev, control);} else {spin_unlock_irqrestore(&priv->lock, flags);}buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,0, 0, buf, 7, 100);dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);if (cflag & CRTSCTS) {if (priv->type == HX)pl2303_vendor_write(0x0, 0x61, serial);elsepl2303_vendor_write(0x0, 0x41, serial);} else {pl2303_vendor_write(0x0, 0x0, serial);}/* FIXME: Need to read back resulting baud rate */if (baud)tty_encode_baud_rate(tty, baud, baud);kfree(buf);}static void pl2303_close(struct tty_struct *tty,struct usb_serial_port *port, struct file *filp){struct pl2303_private *priv = usb_get_serial_port_data(port);unsigned long flags;unsigned int c_cflag;int bps;long timeout;wait_queue_t wait;dbg("%s - port %d", __func__, port->number);/* wait for data to drain from the buffer */spin_lock_irqsave(&priv->lock, flags);timeout = PL2303_CLOSING_WAIT;init_waitqueue_entry(&wait, current);add_wait_queue(&tty->write_wait, &wait);for (;;) {set_current_state(TASK_INTERRUPTIBLE);if (pl2303_buf_data_avail(priv->buf) == 0 ||timeout == 0 || signal_pending(current) ||port->serial->disconnected)break;spin_unlock_irqrestore(&priv->lock, flags);timeout = schedule_timeout(timeout);spin_lock_irqsave(&priv->lock, flags);}set_current_state(TASK_RUNNING);remove_wait_queue(&tty->write_wait, &wait);/* clear out any remaining data in the buffer */pl2303_buf_clear(priv->buf);spin_unlock_irqrestore(&priv->lock, flags);/* wait for characters to drain from the device *//* (this is long enough for the entire 256 byte *//* pl2303 hardware buffer to drain with no flow *//* control for data rates of 1200 bps or more, *//* for lower rates we should really know how much */ /* data is in the buffer to compute a delay *//* that is not unnecessarily long) */bps = tty_get_baud_rate(tty);if (bps > 1200)timeout = max((HZ*2560)/bps, HZ/10);elsetimeout = 2*HZ;schedule_timeout_interruptible(timeout);/* shutdown our urbs */dbg("%s - shutting down urbs", __func__);usb_kill_urb(port->write_urb);usb_kill_urb(port->read_urb);usb_kill_urb(port->interrupt_in_urb);if (tty) {c_cflag = tty->termios->c_cflag;if (c_cflag & HUPCL) {/* drop DTR and RTS */spin_lock_irqsave(&priv->lock, flags);priv->line_control = 0;spin_unlock_irqrestore(&priv->lock, flags);set_control_lines(port->serial->dev, 0);}}}static int pl2303_open(struct tty_struct *tty,struct usb_serial_port *port, struct file *filp){struct ktermios tmp_termios;struct usb_serial *serial = port->serial;struct pl2303_private *priv = usb_get_serial_port_data(port);int result;dbg("%s - port %d", __func__, port->number);if (priv->type != HX) {usb_clear_halt(serial->dev, port->write_urb->pipe);usb_clear_halt(serial->dev, port->read_urb->pipe);} else {/* reset upstream data pipes */pl2303_vendor_write(8, 0, serial);pl2303_vendor_write(9, 0, serial);}/* Setup termios */if (tty)pl2303_set_termios(tty, port, &tmp_termios);/* FIXME: need to assert RTS and DTR if CRTSCTS off */dbg("%s - submitting read urb", __func__);port->read_urb->dev = serial->dev;result = usb_submit_urb(port->read_urb, GFP_KERNEL);if (result) {dev_err(&port->dev, "%s - failed submitting read urb,"" error %d\n", __func__, result);pl2303_close(tty, port, NULL);return -EPROTO;}dbg("%s - submitting interrupt urb", __func__);port->interrupt_in_urb->dev = serial->dev;result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);if (result) {dev_err(&port->dev, "%s - failed submitting interrupt urb,"" error %d\n", __func__, result);pl2303_close(tty, port, NULL);return -EPROTO;}return 0;}static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,unsigned int set, unsigned int clear){struct usb_serial_port *port = tty->driver_data;struct pl2303_private *priv = usb_get_serial_port_data(port);unsigned long flags;u8 control;if (!usb_get_intfdata(port->serial->interface))return -ENODEV;spin_lock_irqsave(&priv->lock, flags);if (set & TIOCM_RTS)priv->line_control |= CONTROL_RTS;if (set & TIOCM_DTR)priv->line_control |= CONTROL_DTR;if (clear & TIOCM_RTS)priv->line_control &= ~CONTROL_RTS;if (clear & TIOCM_DTR)priv->line_control &= ~CONTROL_DTR;control = priv->line_control;spin_unlock_irqrestore(&priv->lock, flags);return set_control_lines(port->serial->dev, control);}static int pl2303_tiocmget(struct tty_struct *tty, struct file *file){struct usb_serial_port *port = tty->driver_data;struct pl2303_private *priv = usb_get_serial_port_data(port);unsigned long flags;unsigned int mcr;unsigned int status;unsigned int result;dbg("%s (%d)", __func__, port->number);if (!usb_get_intfdata(port->serial->interface))return -ENODEV;spin_lock_irqsave(&priv->lock, flags);mcr = priv->line_control;status = priv->line_status;spin_unlock_irqrestore(&priv->lock, flags);result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)| ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)| ((status & UART_CTS) ? TIOCM_CTS : 0)| ((status & UART_DSR) ? TIOCM_DSR : 0)| ((status & UART_RING) ? TIOCM_RI : 0)| ((status & UART_DCD) ? TIOCM_CD : 0);dbg("%s - result = %x", __func__, result);return result;}static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) {struct pl2303_private *priv = usb_get_serial_port_data(port);unsigned long flags;unsigned int prevstatus;unsigned int status;unsigned int changed;spin_lock_irqsave(&priv->lock, flags);prevstatus = priv->line_status;spin_unlock_irqrestore(&priv->lock, flags);while (1) {interruptible_sleep_on(&priv->delta_msr_wait);/* see if a signal did it */if (signal_pending(current))return -ERESTARTSYS;spin_lock_irqsave(&priv->lock, flags);status = priv->line_status;spin_unlock_irqrestore(&priv->lock, flags);changed = prevstatus ^ status;if (((arg & TIOCM_RNG) && (changed & UART_RING)) || ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||((arg & TIOCM_CD) && (changed & UART_DCD)) ||((arg & TIOCM_CTS) && (changed & UART_CTS))) {return 0;}prevstatus = status;}/* NOTREACHED */return 0;}static int pl2303_ioctl(struct tty_struct *tty, struct file *file,unsigned int cmd, unsigned long arg){struct usb_serial_port *port = tty->driver_data;dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);switch (cmd) {case TIOCMIWAIT:dbg("%s (%d) TIOCMIWAIT", __func__, port->number);return wait_modem_info(port, arg);default:dbg("%s not supported = 0x%04x", __func__, cmd);break;}return -ENOIOCTLCMD;}static void pl2303_break_ctl(struct tty_struct *tty, int break_state) {struct usb_serial_port *port = tty->driver_data;struct usb_serial *serial = port->serial;u16 state;int result;dbg("%s - port %d", __func__, port->number);if (break_state == 0)state = BREAK_OFF;elsestate = BREAK_ON;dbg("%s - turning break %s", __func__,state == BREAK_OFF ? "off" : "on");result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),BREAK_REQUEST, BREAK_REQUEST_TYPE, state,0, NULL, 0, 100);if (result)dbg("%s - error sending break = %d", __func__, result);}static void pl2303_shutdown(struct usb_serial *serial){int i;struct pl2303_private *priv;dbg("%s", __func__);for (i = 0; i < serial->num_ports; ++i) {priv = usb_get_serial_port_data(serial->port[i]);if (priv) {pl2303_buf_free(priv->buf);kfree(priv);usb_set_serial_port_data(serial->port[i], NULL);}}}static void pl2303_update_line_status(struct usb_serial_port *port,unsigned char *data,unsigned int actual_length){struct pl2303_private *priv = usb_get_serial_port_data(port);unsigned long flags;u8 status_idx = UART_STATE;u8 length = UART_STATE + 1;u16 idv, idp;idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);if (idv == SIEMENS_VENDOR_ID) {if (idp == SIEMENS_PRODUCT_ID_X65 ||idp == SIEMENS_PRODUCT_ID_SX1 ||idp == SIEMENS_PRODUCT_ID_X75) {length = 1;status_idx = 0;}}if (actual_length < length)return;/* Save off the uart status for others to look at */spin_lock_irqsave(&priv->lock, flags);priv->line_status = data[status_idx];spin_unlock_irqrestore(&priv->lock, flags);wake_up_interruptible(&priv->delta_msr_wait);}static void pl2303_read_int_callback(struct urb *urb){struct usb_serial_port *port = urb->context;unsigned char *data = urb->transfer_buffer;unsigned int actual_length = urb->actual_length;int status = urb->status;int retval;dbg("%s (%d)", __func__, port->number);switch (status) {case 0:/* success */break;case -ECONNRESET:case -ENOENT:case -ESHUTDOWN:/* this urb is terminated, clean up */。
基于Windows的USB驱动程序开发
![基于Windows的USB驱动程序开发](https://img.taocdn.com/s3/m/c1f722e4f8c75fbfc77db2f3.png)
摘 要 :为 了配 合 US B驱 动 程 序 的 开发 ,首 先 详 细 阐 述 了微 软 所提 倡 的 WDM 驱 动 模 型 。 并 以 L C 3 8为例i 具 包 ,开发 US r rtdo工 v B设 备 驱 动 程 序 的 过程 和 US 驱 动 程 序 的调 用过 程 。利 用 Dr eWok 发 驱 动程 序 B i r rs开 v 快 捷 方便 ,必 将 有 着 广 阔 的应 用 前 景 。 关 键 词 :WDM 驱 动 模 型 ;D DK;Dr eSu i;US 驱 动 i rtdo v B
程 序 负责 的 工 作有 :枚举 总 线 上 的 设 备 ;向操 作 系 统 报 告 总 线上 的动 态事 件 ; 响应 即插 即用 和 电源 管理 的 I /O 请 求 ; 管理 总线上 的设备 。 总线驱动程序创建一个物理设备对象 来 代 表 它 发现 的 设备 。 发 现 总 线 上 的 所 有 设 备 和 检 测 设 备添 即 加 或 者 删 除 ,创 建 物 理 设 备 对 象 P DO; 功能驱动程序 处理 设备 的 I / O请求包 (R ) I P ,负责创 建 功 能设 备对象 F DO; 其 他 层 的 驱 动 程 序 是 一 些 过 滤 程 序 ( ie Dr e) 对 应 的 设 备 对 象 是 过 滤 器 设 备 。 安 装硬 件 Fl r i r, t v
驱 动 程 序 完 成 不 同 的操 作 ,不 同层 之 间 可 以 互 相 调 用 , 在
设备 时操作系 统的即插 即用管理器 按照设备驱 动程序 的要 求构造设备的对象 , 首先是最 底层 的总线驱动程序检测 到实
际 的物 理 设 备 ,创 建 物 理 设 备对 象 P DO,然 后 , 即插 即用 管理器查询注册表 , 按注册表信 息依次 加载过滤驱动程序和
一文入门usb设备的驱动编写方法
![一文入门usb设备的驱动编写方法](https://img.taocdn.com/s3/m/650b27b84793daef5ef7ba0d4a7302768e996fbc.png)
一文入门usb设备的驱动编写方法USB设备驱动编写入门USB(通用串行总线)是一种广泛使用的协议,用于在计算机和外围设备之间建立通信渠道。
编写USB设备驱动程序需要对USB规范以及操作系统提供的底层机制有深入的理解。
1. 理解USB规范USB规范定义了设备之间的通信协议、设备类型和描述符格式等方面。
理解规范对于编写符合标准且能够与其他USB设备交互的驱动程序至关重要。
2. 选择操作系统平台不同操作系统对USB设备驱动程序的要求有所不同。
为Windows环境编写驱动程序与为Linux或macOS编写驱动程序具有不同的方法。
了解目标操作系统的特定要求至关重要。
3. 设置开发环境设置开发环境包括安装必要的工具和库。
这可能需要安装USB 开发工具包或编译器。
阅读操作系统的文档以设置正确的环境。
4. 创建USB描述符USB描述符是描述设备功能和配置的数据结构。
驱动程序需要创建这些描述符才能注册设备并向操作系统公开其功能。
5. 实现USB端点USB端点是设备与计算机之间的数据传输通道。
驱动程序需要实现端点处理程序来处理数据传输和控制请求。
6. 处理USB事件驱动程序需要处理各种USB事件,例如设备插入、拔出和配置更改。
实现事件处理程序来响应这些事件并更新设备状态。
7. 使用USB堆栈操作系统提供USB堆栈,为驱动程序提供与底层USB硬件接口的抽象层。
了解USB堆栈的API和功能对于与硬件交互至关重要。
8. 调试驱动程序调试USB设备驱动程序需要专门的工具和技术。
使用调试器、日志记录和分析工具来识别并解决问题。
9. 测试驱动程序在不同环境和条件下全面测试驱动程序至关重要。
执行功能测试、兼容性测试和压力测试以验证驱动程序的可靠性和稳定性。
10. 提交并分发驱动程序开发完成后,需要向操作系统供应商提交驱动程序以进行认证和分发。
遵守供应商的准则并提供必要的文档。
USB接口技术及驱动程序开发
![USB接口技术及驱动程序开发](https://img.taocdn.com/s3/m/d518ed7931b765ce0508140c.png)
的设备驱动程序需要有“即插即用(PnP)”模块以及安装标识的INF文件。
在上述不同模块之间需要交互,其中的一些交互可以直接通过函数调用,而大量信息需要通过数据结构传递(比如在”设备对象”之类的数据结构中可以存储每个设备的信息)。
IRP,每个设备对象有一个内部的IRP队列,驱动程序的分发例程把1RP插入到这个设备队列中,内核I/O管理器从该队列一个个取出IRP,并传递到驱动程序的Startlo例程,Startlo例程串行处理IRP,以确保不与其它IRP处理程序冲突,但是StartIo例程仍然需要通过临界段例程避免与硬件中断发生冲突。
中断是用于停止处理器对一个任务的执行,而被强制运行某个中断去处理代码。
中断包括软件中断和硬件中断。
中断具有优先级,低优先级中断会被高优先级的中断所中断,以保证重要任务会优先执行。
硬件产生的中断总是比软件产生的中断优先级要高。
硬件中断类型包括:设备中断请求级处理程序的执行、配置文件定时器、时钟、同步器、处理器之间中断级、电源故障级;软件中断包括异步过程调用执行、线程调度、延迟过程调用执行。
至于常规线程执行则没有中断。
基本驱动程序例程Ifo控制伊腰派遣规程必须的驱动程序例程处理请求队列聪包含戳artlo_【蹙备产生中断需要包舍中断服务和OPc洲程DMA设备需要包含AdapterContro橱腥可选的l刚书R遣例程图3-2WDM设备驱动程序的模块组驱动程序的主要的初始化入口点是一个称为DriverEntry的例程。
多数WDM设备对象是由PIlP管理器调用AddDevice入15点创建,该例程在插入新设备和安装INF文件指示相对应的驱动程序时被调用,之后,一系列P11PIRP被发送到。
通用串行总线USB的驱动程序设计
![通用串行总线USB的驱动程序设计](https://img.taocdn.com/s3/m/23eb600abed5b9f3f90f1cfe.png)
文章编号:1009-8119(2005)04-0040-03基于WDM的USB驱动程序设计赵娟1 仲顺安1 郭磊2(1.北京理工大学信息科学技术学院,北京 1000812.石家庄陆军参谋指挥学院教育技术专业,石家庄 050064)摘要简单介绍了USB的特性。
为了介绍USB驱动,重点阐述了WDM驱动程序的原理和Windows系统内核管理机制和应用程序的区别。
并给出了利用Driverstudio的C++语言编写的例程。
关键词 USB设备,WDM,操作系统,驱动程序The Implementation of the USB Driver Based on WDMZhao Juan Zhong Shun'an Guo LeiAbstrct The attribute of the USB is descripted in the paper. For developing usb driver, the mechanism of kenerl management and the privilege level of applications in window2000 are introduced in the paper. An example of the driver handling USB transfer programmed by using C++ with the help of the driverstudio is given. Keyword USB device,WDM,OS,Driver1 引言USB,全称是Universal Serial Bus(通用串行总线),它是由Compaq、Microsoft、Intel、IBM等七家公司共同开发的,旨在解决日益增加的PC外设与有限的主板插槽和端口之间的矛盾而制定的一种串行通信的标准,自1995年在Comdex上亮相以来已广泛地为各PC厂家支持。
USB.设备的WDM.驱动程序设计
![USB.设备的WDM.驱动程序设计](https://img.taocdn.com/s3/m/d942048271fe910ef12df82e.png)
USB设备的WDM驱动程序设计卡拉河海大学计算机及信息工程学院niekele2010@yahoo.fr摘要:本文介绍了WDM驱动模型,并且针对USB总线给出了USB设备的WDM驱动程序的设计方法。
关键词: WDM、USB总线、驱动程序一, W DM驱动模型介绍为了方便用户进行WINDOWS平台的驱动程序开发,Microsoft于1996年宣布了一种适用于当前广泛使用的WIN2000及WINDOWS XP操作系统的Win32驱动程序模型。
这个驱动模型就是WDM(Windows Driver Model)——WINDOWS驱动模型。
WDM驱动具有以下几个特点。
详见参考文献[1]第一章。
1)可移植性好,采用WDM模型的设备驱动程序在不同的Windows操作系统上基本上是二进制兼容的,而在不同的CPU平台Windows操作系统上是源代码兼容的。
2)分层结构。
WDM模型使用了如图1的层次结构。
图中左边是一个设备对象堆栈。
设备对象是系统为帮助软件管理硬件而创建的数据结构。
一个物理硬件可以有多个这样的数据结构。
处于堆栈最底层的设备对象称为物理设备对象(physical device object),或简称为PDO。
在设备对象堆栈的中间某处有一个对象称为功能设备对象(functional device object),或简称FDO。
在FDO的上面和下面还会有一些过滤器设备对象(filter device object)。
位于FDO上面的过滤器设备对象称为上层过滤器,位于FDO下面(但仍在PDO 之上)的过滤器设备对象称为下层过滤器。
3)可配置性好。
WDM驱动程序通过其底层的类(总线)驱动程序枚举和访问硬件资源,使得设备的配置变得相对简单和容易。
而且WDM驱动程序还可以支持WMI(Windows Management Instrumentation),通过WMI,用户可以控制驱动程序的某些行为和属性。
4)支持即插即用和电源管理。
usb设备驱动程序usb gadget driver(4)
![usb设备驱动程序usb gadget driver(4)](https://img.taocdn.com/s3/m/5e0613d005087632311212ca.png)
USB设备驱动程序-USB Gadget Driver(4) Gadget 功能层Gadget功能层完成USB设备的具体功能,其表现的形式各不相同,如键盘、鼠标、存储和网卡等等。
功能层不仅涉及到Gadget驱动相关的内容,还涉及到其功能相关的内核子系统。
如存储还涉及到内核存储子系统,网卡还涉及到网络驱动子系统。
因此,Gadget功能的代码非常复杂。
这里以zero.c为例,这个模块只是简单地将接收的数据回显回去。
一、数据结构首先需要实现usb_composite_driver函数集:static structusb_composite_driver zero_driver ={ .name ="zero", .dev =&device_desc, .strings =dev_strings, .bind =zero_bind, .unbind =zero_unbind, .suspend =zero_suspend, .resume =zero_resume, }; 二、主要函数这个模块的实现就是这么简单:static int __init init(void){ returnusb_composite_register(&zero_driver); }module_init(init); static void __exit cleanup(void){ usb_composite_unregister(&zero_driver);} Bind函数是功能层需要实现与设备层关联的重要函数:static int __init zero_bind(struct usb_composite_dev *cdev) { int gcnum;struct usb_gadget *gadget = cdev->gadget; //Gadget设备int id; /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue.*/ /*分配字符串描述符的id,并赋值给设备描述符中字符串索引*/ id = usb_string_id(cdev); strings_dev[STRING_MANUFACTURER_IDX].id = id; device_desc.iManufacturer = id; id =usb_string_id(cdev); istrings_dev[STRING_PRODUCT_IDX].id = id;device_desc.iProduct = id; id =usb_string_id(cdev);strings_dev[STRING_SERIAL_IDX].id = id;device_desc.iSerialNumber = id; /*设置挂起后,设备自动恢复的定时器*/setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); /*核心代码,实现功能*/ if (loopdefault){ loopback_add(cdev, autoresume != 0); //数据简单回显功能if (!gadget_is_sh(gadget))sourcesink_add(cdev, autoresume != 0); } else{ sourcesink_add(cdev, autoresume != 0); if(!gadget_is_sh(gadget))loopback_add(cdev, autoresume != 0); } /*初始化设备描述符*/ gcnum =usb_gadget_controller_number(gadget); if (gcnum >= 0)device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);else { device_desc.bcdDevice = cpu_to_le16(0x9999); } return 0; } /*增加数据简单回显功能*/ int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) { int id;/*获取字符串描述符id索引*/id = usb_string_id(cdev);strings_loopback[0].id = id;loopback_intf.iInterface = id;loopback_driver.iConfiguration = id;/* support autoresume for remote wakeup testing */if (autoresume)sourcesink_driver.bmAttributes |=USB_CONFIG_ATT_WAKEUP;/* support OTG systems */ if (gadget_is_otg(cdev->gadget)){loopback_driver.descriptors = otg_desc;loopback_driver.bmAttributes |=USB_CONFIG_ATT_WAKEUP;} returnusb_add_config(cdev, &loopback_driver); //增加一个配置} /*loopback配置*/ static struct usb_configuration loopback_driver = { .label = "loopback", .strings = loopback_strings, .bind = loopback_bind_config, .bC onfigurationValue =2, .bmAttributes =USB_CONFIG_ATT_SELFPOWER,/* .iConfiguration = DYNAMIC */ }; 将增加配置的usb_add_config函数中会调用其bind函数,即loopback_bind_config函数,来分配这个配置所需要的资源。
mtb usb驱动程序
![mtb usb驱动程序](https://img.taocdn.com/s3/m/4b2ea7740812a21614791711cc7931b765ce7bc4.png)
mtb usb驱动程序MTB USB驱动程序摘要本文档介绍了MTB(Mountain Bike)USB驱动程序的基本知识,并提供了相关信息和指导,以帮助用户安装和使用MTB USB驱动程序。
MTB USB驱动程序是一种允许计算机系统与MTB设备之间进行通信的软件。
本文档包括了USB驱动程序的重要性、安装步骤、常见问题解决方案等内容。
1. 简介MTB USB驱动程序是一种允许计算机系统与MTB设备进行通信的软件。
它通过USB接口连接计算机和MTB设备,使用户能够在计算机上管理和控制MTB设备。
MTB USB驱动程序通常由MTB设备制造商提供,并需将其安装在计算机上,以便实现设备与计算机之间的通信。
2. 安装步骤以下是安装MTB USB驱动程序的基本步骤:1)确定驱动程序版本:在安装MTB USB驱动程序之前,确保在制造商的官方网站上获取最新版本的驱动程序。
2)下载驱动程序:从制造商的官方网站上下载适用于您的操作系统的MTB USB驱动程序。
3)安装驱动程序:双击下载的驱动程序文件以启动安装过程。
按照屏幕上的指示完成安装。
在安装过程中可能需要重启计算机。
4)连接设备:在安装MTB USB驱动程序之后,使用USB线缆将MTB设备与计算机连接。
5)验证连接:确认MTB设备已正确连接到计算机,并可以正常识别。
3. 常见问题解决方案3.1 驱动程序无法安装如果您遇到无法安装MTB USB驱动程序的问题,请检查以下几点:1)确认系统兼容性:确保您的操作系统与驱动程序的兼容性。
有时驱动程序可能仅支持特定的操作系统版本。
2)禁用防病毒软件:某些防病毒软件可能会阻止驱动程序的安装。
尝试禁用防病毒软件,并重新运行安装程序。
3)更新操作系统:将操作系统更新到最新版本可能会解决与驱动程序安装相关的问题。
3.2 设备无法被识别如果您的MTB设备无法被计算机正常识别,请尝试以下解决方案:1)检查连接:确保MTB设备正确连接到计算机,并且USB线缆没有损坏或松动。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
USB驱动程序编写linux下usb驱动编写(内核2.4)——2.6与此接口有区别2006-09-15 14:57我们知道了在Linux 下如何去使用一些最常见的USB设备。
但对于做系统设计的程序员来说,这是远远不够的,我们还需要具有驱动程序的阅读、修改和开发能力。
在此下篇中,就是要通过简单的USB驱动的例子,随您一起进入USB驱动开发的世界。
USB骨架程序(usb-skeleton),是USB驱动程序的基础,通过对它源码的学习和理解,可以使我们迅速地了解USB驱动架构,迅速地开发我们自己的USB硬件的驱动。
USB驱动开发在掌握了USB设备的配置后,对于程序员,我们就可以尝试进行一些简单的USB驱动的修改和开发了。
这一段落,我们会讲解一个最基础USB框架的基础上,做两个小的USB驱动的例子。
USB骨架在Linux kernel源码目录中driver/usb/usb-skeleton.c为我们提供了一个最基础的USB驱动程序。
我们称为USB骨架。
通过它我们仅需要修改极少的部分,就可以完成一个USB设备的驱动。
我们的USB驱动开发也是从她开始的。
那些linux下不支持的USB设备几乎都是生产厂商特定的产品。
如果生产厂商在他们的产品中使用自己定义的协议,他们就需要为此设备创建特定的驱动程序。
当然我们知道,有些生产厂商公开他们的USB协议,并帮助Linux驱动程序的开发,然而有些生产厂商却根本不公开他们的USB协议。
因为每一个不同的协议都会产生一个新的驱动程序,所以就有了这个通用的USB驱动骨架程序,它是以pci 骨架为模板的。
如果你准备写一个linux驱动程序,首先要熟悉USB协议规范。
USB主页上有它的帮助。
一些比较典型的驱动可以在上面发现,同时还介绍了USB urbs的概念,而这个是usb驱动程序中最基本的。
Linux USB 驱动程序需要做的第一件事情就是在Linux USB 子系统里注册,并提供一些相关信息,例如这个驱动程序支持那种设备,当被支持的设备从系统插入或拔出时,会有哪些动作。
所有这些信息都传送到USB 子系统中,在usb骨架驱动程序中是这样来表示的:static struct usb_driver skel_driver = {name: skeleton,probe: skel_probe,disconnect: skel_disconnect,fops: &skel_fops,minor: USB_SKEL_MINOR_BASE,id_table: skel_table,};变量name是一个字符串,它对驱动程序进行描述。
probe 和disconnect 是函数指针,当设备与在id_table 中变量信息匹配时,此函数被调用。
fops和minor变量是可选的。
大多usb驱动程序钩住另外一个驱动系统,例如SCSI,网络或者tty子系统。
这些驱动程序在其他驱动系统中注册,同时任何用户空间的交互操作通过那些接口提供,比如我们把SCSI设备驱动作为我们USB驱动所钩住的另外一个驱动系统,那么我们此USB设备的read、write等操作,就相应按SCSI设备的read、write函数进行访问。
但是对于扫描仪等驱动程序来说,并没有一个匹配的驱动系统可以使用,那我们就要自己处理与用户空间的read、write等交互函数。
Usb子系统提供一种方法去注册一个次设备号和函数指针,这样就可以与用户空间实现方便地交互。
USB骨架程序的关键几点如下:USB驱动的注册和注销Usb驱动程序在注册时会发送一个命令给usb_register,通常在驱动程序的初始化函数里。
当要从系统卸载驱动程序时,需要注销usb子系统。
即需要usb_unregister 函数处理:static void __exit usb_skel_exit(void){/* deregister this driver with the USB subsystem */usb_deregister(&skel_driver);}module_exit(usb_skel_exit);当usb设备插入时,为了使linux-hotplug(Linux中PCI、USB等设备热插拔支持)系统自动装载驱动程序,你需要创建一个MODULE_DEVICE_TABLE。
代码如下(这个模块仅支持某一特定设备):/* table of devices that work with this driver */static struct usb_device_id skel_table [] = {{ USB_DEVICE(USB_SKEL_VENDOR_ID,USB_SKEL_PRODUCT_ID) },{ } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, skel_table);USB_DEVICE宏利用厂商ID和产品ID为我们提供了一个设备的唯一标识。
当系统插入一个ID 匹配的USB设备到USB总线时,驱动会在USB core中注册。
驱动程序中probe 函数也就会被调用。
usb_device 结构指针、接口号和接口ID都会被传递到函数中。
static void * skel_probe(struct usb_device *dev,unsigned int ifnum, const struct usb_device_id *id)驱动程序需要确认插入的设备是否可以被接受,如果不接受,或者在初始化的过程中发生任何错误,probe函数返回一个NULL值。
否则返回一个含有设备驱动程序状态的指针。
通过这个指针,就可以访问所有结构中的回调函数。
在骨架驱动程序里,最后一点是我们要注册devfs。
我们创建一个缓冲用来保存那些被发送给usb 设备的数据和那些从设备上接受的数据,同时USB urb 被初始化,并且我们在devfs子系统中注册设备,允许devfs用户访问我们的设备。
注册过程如下:/* initialize the devfs node for this deviceand register it */sprintf(name, skel%d, skel->minor);skel->devfs = devfs_register(usb_devfs_handle, name,DEVFS_FL_DEFAULT, USB_MAJOR,USB_SKEL_MINOR_BASE + skel->minor,S_IFCHR | S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP | S_IROTH,&skel_fops, NULL);如果devfs_register函数失败,不用担心,devfs子系统会将此情况报告给用户。
当然最后,如果设备从usb总线拔掉,设备指针会调用disconnect 函数。
驱动程序就需要清除那些被分配了的所有私有数据、关闭urbs,并且从devfs上注销调自己。
/* remove our devfs node */devfs_unregister(skel->devfs);现在,skeleton驱动就已经和设备绑定上了,任何用户态程序要操作此设备都可以通过结构所定义的函数进行了。
首先,我们要open此设备。
在open函数中MODULE_INC_USE_COUNT 宏是一个关键,它的作用是起到一个计数的作用,有一个用户态程序打开一个设备,计数器就加一,例如,我们以模块方式加入一个驱动,若计数器不为零,就说明仍然有用户程序在使用此驱动,这时候,你就不能通过rmmod命令卸载驱动模块了。
/* increment our usage count for the module */MOD_INC_USE_COUNT;++skel->open_count;/* save our object in the file's private structure */file->private_data = skel;当open完设备后,read、write函数就可以收、发数据了。
skel的write、和read函数他们是完成驱动对读写等操作的响应。
在skel_write中,一个FILL_BULK_URB函数,就完成了urb 系统callbak和我们自己的skel_write_bulk_callback之间的联系。
注意skel_write_bulk_callback是中断方式,所以要注意时间不能太久,本程序中它就只是报告一些urb的状态等。
read 函数与write 函数稍有不同在于:程序并没有用urb 将数据从设备传送到驱动程序,而是我们用usb_bulk_msg 函数代替,这个函数能够不需要创建urbs 和操作urb函数的情况下,来发送数据给设备,或者从设备来接收数据。
我们调用usb_bulk_msg函数并传提一个存储空间,用来缓冲和放置驱动收到的数据,若没有收到数据,就失败并返回一个错误信息。
usb_bulk_msg函数当对usb设备进行一次读或者写时,usb_bulk_msg 函数是非常有用的; 然而, 当你需要连续地对设备进行读/写时,建议你建立一个自己的urbs,同时将urbs 提交给usb子系统。
skel_disconnect函数当我们释放设备文件句柄时,这个函数会被调用。
MOD_DEC_USE_COUNT宏会被用到(和MOD_INC_USE_COUNT刚好对应,它减少一个计数器),首先确认当前是否有其它的程序正在访问这个设备,如果是最后一个用户在使用,我们可以关闭任何正在发生的写,操作如下:/* decrement our usage count for the device */--skel->open_count;if (skel->open_count <= 0) {/* shutdown any bulk writes that might begoing on */usb_unlink_urb (skel->write_urb);skel->open_count = 0;}/* decrement our usage count for the module */MOD_DEC_USE_COUNT;最困难的是,usb 设备可以在任何时间点从系统中取走,即使程序目前正在访问它。
usb驱动程序必须要能够很好地处理解决此问题,它需要能够切断任何当前的读写,同时通知用户空间程序:usb设备已经被取走。
如果程序有一个打开的设备句柄,在当前结构里,我们只要把它赋值为空,就像它已经消失了。