驱动SYS开发总结 - stretch的专栏 - CSDNBlog

合集下载

转载:linux驱动层到应用层的重要接口sys文件系统---sys目录详解

转载:linux驱动层到应用层的重要接口sys文件系统---sys目录详解

转载:linux驱动层到应⽤层的重要接⼝sys⽂件系统---sys⽬录详解linux驱动层到应⽤层的重要接⼝sys⽂件系统---/sys⽬录详解Linux2.6内核中引⼊了sysfs⽂件系统。

sysfs⽂件系统整理的设备驱动的相关⽂件节点,被视为dev⽂件系统的替代者。

同时也拥有类似proc ⽂件系统⼀样查看系统相关信息的功能。

最主要的作⽤是sysfs把连接在系统上的设备和总线组织成分级的⽂件,使其从⽤户空间可以访问或配置。

Sysfs被加载在 /sys/⽬录下,它的⼦⽬录包括:(本⽂以⾼通sdm630平台为例)1)Block:在系统中发现的每个块设备在该⽬录下对应⼀个⼦⽬录,如mmcblk0对应eMMC设备主节点(此部分可以参考⽂章:。

每个⼦⽬录中⼜包含⼀些属性⽂件,它们描述了这个块设备的各⽅⾯属性,如:设备⼤⼩。

(loop块设备是使⽤⽂件来模拟的)我们查看/sys/block⽬录的详细信息,发现都是链接⽂件,指向了/sys/devices/下的设备:2)Bus:在内核中注册的每条总线在该⽬录下对应⼀个⼦⽬录,如: ide pci scsi usbpcmcia 其中每个总线⽬录内⼜包含两个⼦⽬录:devices和drivers,devices⽬录包含了在整个系统中发现的属于该总线类型的设备,drivers⽬录包含了注册到该总线的所有驱动。

3)Class:将设备按照功能进⾏的分类,如/sys/class/net⽬录下包含了所有⽹络接⼝。

其中power_supply可以查看充电相关的信息:cat /sys/class/power_supply/battery/uevent4)Devices:包含系统所有的设备。

该⽬录层次与devicetree中描述的设备层次是相互对应的。

如上图中的soc⽂件夹对应dtsi⽂件中的:slv_wlan⽂件夹对应dtsi中的:5)Kernel:内核中的配置参数6)Module:系统中所有模块的信息7)Firmware:系统中的固件8)Fs:描述系统中的⽂件系统9)Power:系统中电源选项。

驱动开发学习笔记

驱动开发学习笔记

驱动开发学习笔记1很久没有网了,出了一段时间的差,近来,莫名的就有点郁闷!前不久在大富翁上发了一份帖子是关于delphi程序员的发展,大家的反应并不都是很好。

于是开始觉得可以考虑换个方向。

以前我是做MIS开发的。

换哪个方向呢?人越多的方向,好像越是没有前途。

想想当初上大学,那可是越多人考的学校,学费越贵啊!可现在的职业呢?越多人干的事,越是没有前途了。

考虑来考虑去,决定学习一下驱动程序的开发吧!于是从网上查找了一些资料,看的懂的觉得蛮不错适合我这种小学生的就贴了出来,算是学习笔记吧!用户模式与内核模式从Intel80386开始,出于安全性和稳定性的考虑,该系列的CPU可以运行于ring0~ring3从高到低四个不同的权限级,对数据也提供相应的四个保护级别。

运行于较低级别的代码不能随意调用高级别的代码和访问较高级别的数据,而且也只有运行在ring0层的代码可以直接对物理硬件进行访问。

由于WindowsNT是一个支持多平台的操作系统,为了与其他平台兼容,它只利用了CPU的两个运行级别。

一个被称为内核模式,对应80x86的ring0层,是操作系统的核心部分,设备驱动程序就是运行在该模式下;另一个被称为用户模式,对应80x86的ring3层,操作系统的用户接口部分(就是我们通常所说的win32 API)以及所有的用户应用程序都运行在该级别。

操作系统对运行在内核模式下的代码是不设防的,所以不管是建设还是破坏内核模式下的编程都是值得去研究的。

图1-WIN2000系统的分层结构在物理硬件与系统核心之间有一个硬件抽象层(HardwareAbstractionLayer),它屏蔽了不同平台硬件的差异,向操作系统的上层提供了一套统一的接口。

从图中我们还可以看到,设备驱动程序(DeviceDriver)是被I/O管理器(I/OManager)包围起来的,即驱动程序与操作系统上层的通信全部都要通过I/O管理器。

这给驱动程序的编写带来了很大的便利,因为很多诸如接收用户的请求、与用户程序交换数据、内存映射、挂接中断、同步等等麻烦的工作都由I/O管理器代劳了。

system的用法

system的用法

system的用法系统(system)是指由一系列有关联的组件、元素或部件组成的整体。

在计算机领域,系统通常指的是硬件和软件组合在一起形成的整个运行环境。

system是现代计算机科学中一个非常重要且广泛应用的概念,在不同情境下有着不同的含义和用法。

本文将探讨system在程序开发中的几个常见用法。

一、System类在Java编程语言中,System是一个预定义类,包含了与系统相关的方法和字段。

它提供了访问和操作系统级别功能的能力,方便开发者对程序进行底层控制。

1. System.out.println()System.out对象是一个PrintStream类型,代表标准输出流。

它提供了很多方法来方便打印各种数据类型到控制台输出。

其中最为常用且熟知的就是System.out.println()方法,它可以将内容打印到控制台并换行。

例如,在以下示例代码中:```javapublic class HelloWorld {public static void main(String[] args) {System.out.println("Hello, World!");}}```以上代码将会打印出"Hello, World!"这句话,并在结尾处增加一个换行符。

2. System.currentTimeMillis()System.currentTimeMillis()方法返回从1970年1月1日00:00:00 UTC到当前时间的毫秒数。

这个方法常用于计算程序的执行时间或者生成唯一标识符。

例如,以下代码段展示了如何使用System.currentTimeMillis()获取当前时间戳:```javalong currentTime = System.currentTimeMillis();System.out.println("Current time: " + currentTime);```以上代码将打印出当前的时间戳,可以用于记录程序运行时的起始点或者进行性能分析。

linux设备驱动(28)usb驱动开发过程总结

linux设备驱动(28)usb驱动开发过程总结

linux设备驱动(28)usb驱动开发过程总结设备驱动程序是操作系统内核和机器硬件之间的接⼝,由⼀组函数和⼀些私有数据组成,是应⽤程序和硬件设备之间的桥梁。

在应⽤程序看来,硬件设备只是⼀个设备⽂件,应⽤程序可以像操作普通⽂件⼀样对硬件设备进⾏操作。

设备驱动程序是内核的⼀部分,主要完成以下功能:对设备的初始化和释放;把数据从内核传送到硬件设备和从硬件设备读取数据;读取应⽤程序数据传送给设备⽂件和回送应⽤程序请求的数据;检测和处理硬件设备出现的错误。

1 Linux USB⼦系统分析在Linux系统中,USB主机驱动程序由3部分组成:USB主机控制器驱动(HCD)、USB核⼼驱动(USBD)和不同种类的USB设备类驱动,如下所⽰。

其中HCD和USBD被称为协议软件或者协议栈,这两部分共同处理与协议相关的操作。

USB设备类驱动可以包含多个,不同的功能接⼝对应不同的驱动程序,它们不直接与USB设备硬件打交道,⽽是通过协议软件的抽象处理来完成与设备的不同功能接⼝之间的通信。

在Linux USB⼦系统中,HCD是直接和硬件进⾏交互的软件模块,是USB协议栈的最底层部分,是USB主机控制器硬件和数据传输的⼀种抽象。

HCD向上仅对USB总线驱动程序服务,HCD提供了⼀个软件接⼝,即HCDI,使得各种USB主机控制器的硬件特性都被软件化,并受USB总线驱动程序的调⽤和管理。

HCD向下则直接管理和检测主控制器硬件的各种⾏为。

HCD提供的功能主要有:主机控制器硬件初始化;为USBD层提供相应的接⼝函数;提供根HUB(ROOT HUB)设备配置、控制功能;完成4种类型的数据传输等。

USBD部分是整个USB主机驱动的核⼼,主要实现的功能有:USB总线管理;USB总线设备管理、USB总线带宽管理、USB的4种类型数据传输、USB HUB驱动、为USB设备驱动提供相关接⼝、提供应⽤程序访问USB系统的⽂件接⼝等。

其中USB HUB作为⼀类特殊的USB设备,其驱动程序被包含在USBD层。

驱动开发培训

驱动开发培训

VC开发驱动步骤(四)
新建一个.c文件,编写驱动入口函数 #include <ntddk.h> NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { KdPrint(("First Driver!!!\n")); return STATUS_SUCCESS; }; 驱动程序都必须带一个名称为DriverEntry的入口函数。目前这 个驱动什么都没干,只是打印了一行测试信息。
VC开发驱动步骤(五)
新建一个source文件,没有后缀,写入至少如 下内容: TARGETNAME=testsys——驱动的名称 TARGETTYPE=DRIVER——类型 SOURCES = TestSys.c——需要编译的文件,.c文 件即可 不同类型的驱动,source文件中需要不同的内 容,以上3个是最基本的内容,其他参数含义 请自己网上查找。
VC开发驱动步骤(一)
新建一个工程,类型为makefile
VC开发驱动步骤(二)
设置编译的命令行
编译命令行说明
MakeDrvr c:\WINDDK\7600.16385.0 e: E:\testfile chk MakeDrvr是一个批处理文件,可以自己编写 或者重命名,主要就是根据输入参数设置编译 的环境变量,然后build。 第一个参数是DDK/WDM的安装目录,第二个 参数是源代码所在的盘符,第三个参数是源代 码所在目录,第四个参数表示是什么版本, chk表示debug版本,free表示release版本。
WinDbg查看Minidump(二)
若以上几个路径设置都没有问题,WinDbg 会直接定位到错误的源代码那里,如下图:

驱动总结

驱动总结
module_init(s3c2410_led_init);
PDF pdfFactorymodule_exit(s3c2410_led_exit);
MODULE_LICENSE("GPL");
测试程序如下:
#include"stdio.h" #include"stdlib.h" #include"unistd.h" #include"sys/types.h" #include"sys/ioctl.h" #include"termios.h" #include"sys/stat.h" #include"fcntl.h" #include"sys/time.h"
驱动代码如下:
#include<linux/kernel.h> #include<linux/module.h> #include<linux/device.h> #include<linux/types.h> #include<linux/ioctl.h> #include<linux/errno.h> #include<linux/init.h> #include<linux/cdev.h> #include<asm/uaccess.h> #include<linux/gpio.h> #include<linux/fs.h> #include<asm/io.h> #include<mach/regs-gpio.h>
static struct file_operations s3c2410_led_fops = {

驱动实验报告模板范文

驱动实验报告模板范文

驱动实验报告模板范文实验目的本实验的目的是通过编写驱动程序来控制设备并实现特定功能。

通过这个实验,我将学习驱动程序的开发流程和基本原理,并且掌握如何使用驱动程序与设备进行交互。

实验环境和工具- 操作系统:Windows 10- 开发工具:Visual Studio 2019- 设备:测试设备A实验内容设计驱动程序首先,我根据实验要求,设计了一个简单的驱动程序。

这个程序的主要功能是控制设备A的开关状态。

在设备A的驱动程序中,我定义了一些函数来实现设备的初始化和控制,例如`InitDevice()`和`ControlDevice()`函数。

同时,我还添加了与设备A交互的数据结构和变量。

编写驱动程序接下来,我使用Visual Studio 2019进行驱动程序的编写。

在新建的项目中,我选择了驱动开发模板,并添加了设备A的驱动程序文件。

在驱动开发过程中,我主要使用了Windows Driver Kit中提供的API函数来实现设备的初始化和控制。

通过仔细阅读API文档以及相关示例代码,我成功地编写出了一个功能完善的驱动程序。

编译和调试驱动程序完成驱动程序的编写后,我使用Visual Studio 2019进行了编译和调试。

在编译阶段,我检查了代码是否符合语法,并解决了一些潜在的错误。

然后,我选择了虚拟机作为调试环境,并配置好了相应的调试设置。

通过在调试过程中设置断点和观察变量的值,我成功地找到并解决了一些与设备交互的问题。

最后,我进行了一系列的功能测试,并对程序进行了性能优化。

通过与设备A的交互,我确认了驱动程序的功能正常,并且能够按照预期的方式控制设备A的开关状态。

实验结果和分析通过本次实验,我成功地完成了一个驱动程序的设计和开发,并且实现了设备A 的控制功能。

经过测试,这个驱动程序能够稳定地工作,并且在性能方面也能满足实际需求。

然而,在开发过程中,我也遇到了一些问题。

例如,在与设备A进行通信时,我发现了一些边界情况的处理不完善的问题。

windows驱动开发教程

windows驱动开发教程

windows驱动开发教程Windows驱动开发是指在Windows操作系统下编写、调试和部署驱动程序的过程。

驱动程序是操作系统的核心组成部分,它负责与硬件设备通信,使得操作系统能够正确地识别、管理和控制硬件设备。

在本教程中,我们将介绍Windows驱动开发的基本概念、工具和流程。

首先,为了进行Windows驱动开发,我们需要准备好相应的开发工具。

其中最重要的工具是Windows Driver Kit(WDK),它包含了用于驱动开发的各种工具和库文件。

我们可以从微软官方网站上下载并安装最新版本的WDK。

接下来,我们需要熟悉驱动程序的基本概念。

在Windows中,驱动程序可以分为内核驱动和用户模式驱动。

内核驱动运行在操作系统的内核空间,具有更高的权限和更广泛的硬件访问能力;而用户模式驱动则运行在用户空间,通过系统调用与内核驱动进行通信。

我们需要了解如何编写和编译这两种类型的驱动程序,并了解它们的工作原理和特点。

在编写驱动程序之前,我们还需要了解一些基本的Windows内核编程概念,例如驱动对象模型(Driver Object Model)、设备对象模型(Device Object Model)和驱动程序接口(Driver Interface)。

这些概念是驱动程序的基础,对于理解和设计驱动程序非常重要。

接下来,我们将介绍如何使用WDK的工具和库文件来编写驱动程序。

我们可以使用Visual Studio编写驱动程序的源代码,并使用WDK的编译工具将源代码编译成驱动程序二进制文件。

在编译过程中,我们需要配置驱动程序的环境和依赖项,并确保编译成功。

在编写和编译驱动程序之后,我们需要进行驱动程序的调试和部署。

对于驱动程序的调试,我们可以使用WDK提供的调试工具和技术,例如Kernel-Mode Debugging和WinDbg。

对于驱动程序的部署,我们需要将驱动程序二进制文件和相关的配置文件复制到操作系统的指定目录,并注册驱动程序的信息到操作系统的驱动程序数据库。

sys模块的常见用法

sys模块的常见用法

sys模块的常见⽤法 python的内置模块sys,提供了系统相关的⼀些变量和函数,在实际开发中,常见的有以下⼏种⽤法1. 获取操作系统信息>>> import sys# 在window上执⾏>>> sys.platform'win32'# 在linux上执⾏>>> sys.platform'linux2' 经典的使⽤场景,针对只适⽤于linux平台的代码,通过sys来判断当前操作系统是否符合要求。

2. 获取python版本信息>>> sys.version'3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 22:45:29) [MSC v.1916 32 bit (Intel)]'>>> sys.version_infosys.version_info(major=3, minor=8, micro=2, releaselevel='final', serial=0)>>> ver = sys.version_info>>> ver.major3>>> ver.minor8>>> ver.micro2 对于python版本有限制的代码,可以通过以上⽅法来判断python版本是否符合要求。

3. 获取编码⽅式>>> sys.getdefaultencoding()'utf-8' 在python3中,默认的编码⽅式为utf8, 所以不再需要像python2那样,⾃⼰⼿动设置编码格式为utf-8。

4. 标准输⼊,输出和错误流 sys模块提供了变量来表⽰标准输⼊,输出和错误流,列表如下1. sys.stdin, 标准输⼊流2. sys.stdout,标准输出流3. sys.stderr,标准错误流import sys# sys.stdin # 接收⽤户的输⼊,也就是读取键盘⾥输⼊的数据# stdin和stdout默认都是控制台# sys.stdout # 标准输出# sys.stderr # 错误输出s_in = sys.stdin # input就是读取sys.stdin⾥的数据while True:content = s_in.readline() # hello\nif content == '\n':breakprint(content)sys.stdout = open('stdout.txt', 'w', encoding='utf8')print('hello') # helloprint('yes')sys.stderr = open('stderr.txt', 'w', encoding='utf8')print(1 / 0) # 错误输出import syss_in = sys.stdinwhile True:content = s_in.readline().rstrip('\n') # hello\n ==> hello \n ==> ''if content == '':breakprint(content)5. 中断执⾏ 可以通过sys.exit函数来中断代码的执⾏,⽤法如下>>> sys.exit() 该函数也可以添加⼀个参数,默认为0,表⽰正常退出,其他参数表⽰⾮正常退出,⽀持⽤字符串来⾃定义错误信息。

sys在python中的用法

sys在python中的用法

sys在python中的用法一、概述sys是Python标准库中的一个模块,提供了与Python解释器和其环境相关的函数和变量。

sys模块包含了许多有用的函数和变量,可以帮助开发者更好地控制程序的执行流程、获取程序运行时的信息等。

二、sys模块中常用的函数1. sys.argv该函数是一个列表,其中包含了当前Python脚本所接收到的命令行参数。

例如,在命令行中执行“python script.py arg1 arg2”时,sys.argv将会是一个包含3个元素的列表:["script.py", "arg1", "arg2"]。

2. sys.exit([arg])该函数用于退出程序,并返回一个可选的退出码arg。

如果没有提供退出码,则默认为0。

通常情况下,exit()函数会在程序执行过程中发生错误或者遇到特定条件时被调用。

3. sys.path该变量是一个包含了Python解释器搜索模块文件路径的列表。

默认情况下,sys.path会包含当前工作目录、PYTHONPATH环境变量指定的目录以及Python安装目录下lib/pythonX.X/site-packages等目录。

4. sys.platform该变量返回当前Python解释器所运行的操作系统平台名称。

例如,在Windows系统上运行Python时,该变量值为"win32";在Linux系统上运行Python时,该变量值为"linux"等。

5. sys.stdin、sys.stdout和sys.stderr这三个变量分别代表标准输入、标准输出和标准错误流。

通常情况下,它们分别对应于键盘输入、终端输出和终端错误信息输出。

可以通过重定向这些流来实现输入输出的控制。

三、sys模块中常用的变量1. sys.version该变量返回当前Python解释器的版本信息。

Python标准库之Sys模块使用详解

Python标准库之Sys模块使用详解

Python标准库之Sys模块使⽤详解sys 模块提供了许多函数和变量来处理 Python 运⾏时环境的不同部分.处理命令⾏参数在解释器启动后, argv 列表包含了传递给脚本的所有参数, 列表的第⼀个元素为脚本⾃⾝的名称.使⽤sys模块获得脚本的参数复制代码代码如下:print "script name is", sys.argv[0] # 使⽤sys.argv[0]采集脚本名称if len(sys.argv) > 1:print "there are", len(sys.argv)-1, "arguments:" # 使⽤len(sys.argv)-1采集参数个数-1为减去[0]脚本名称for arg in sys.argv[1:]: #输出除了[0]外所有参数print argelse:print "there are no arguments!"如果是从标准输⼊读⼊脚本 (⽐如 "python < sys-argv-example-1.py"), 脚本的名称将被设置为空串.如果把脚本作为字符串传递给python (使⽤ -c 选项), 脚本名会被设置为 "-c".处理模块path 列表是⼀个由⽬录名构成的列表, Python 从中查找扩展模块( Python 源模块, 编译模块,或者⼆进制扩展).启动 Python 时,这个列表从根据内建规则, PYTHONPATH 环境变量的内容, 以及注册表( Windows 系统)等进⾏初始化.由于它只是⼀个普通的列表, 你可以在程序中对它进⾏操作,使⽤sys模块操作模块搜索路径复制代码代码如下:print "path has", len(sys.path), "members"sys.path.insert(0, "samples") #将路径插⼊到path,[0]中import samplesys.path = [] #删除path中所有路径import random使⽤sys模块查找内建模块builtin_module_names 列表包含 Python 解释器中所有内建模块的名称复制代码代码如下:def dump(module):print module, "=>",if module in sys.builtin_module_names: #查找内建模块是否存在print "<BUILTIN>"else:module = _ _import_ _(module) #⾮内建模块输出模块路径print module._ _file_ _dump("os")dump("sys")dump("string")dump("strop")dump("zlib")os => C:\python\lib\os.pycsys => <BUILTIN>string => C:\python\lib\string.pycstrop => <BUILTIN>zlib => C:\python\zlib.pyd使⽤sys模块查找已导⼊的模块modules 字典包含所有加载的模块. import 语句在从磁盘导⼊内容之前会先检查这个字典.Python 在处理你的脚本之前就已经导⼊了很多模块.复制代码代码如下:print sys.modules.keys()['os.path', 'os', 'exceptions', '_ _main_ _', 'ntpath', 'strop', 'nt','sys', '_ _builtin_ _', 'site', 'signal', 'UserDict', 'string', 'stat']使⽤sys模块获得当前平台sys.platform 返回当前平台出现如: "win32" "linux2" 等处理标准输出/输⼊标准输⼊和标准错误 (通常缩写为 stdout 和 stderr) 是内建在每⼀个 UNIX 系统中的管道。

利用windriver开发了个usb的驱动,写个开发心得

利用windriver开发了个usb的驱动,写个开发心得

利用windriver开发了个usb的驱动,写个开发心得利用windriver 开发了个usb的驱动,写个开发心得项目组需要利用2440采集数字电视的采样数据,所以让我开发一个usb的数据采集系统,就两个要求1 速度要达到500kbyte/s以上2 稳定由于之前没有做过windows驱动的经验,所以花了3,4天时间读了读ddk的文档,期间还上chinapub找个本书,读了免费的第1章,按照他配置了vc的编译环境,呵呵。

然后就吧ddk下面的bulkusb源代码进行了修改,写好usb device的驱动,有些了个应用程序,测试一下,采集数据是ok了,但是发现有时候蓝屏,特别是采集100m左右,就会出现蓝品!这下没办法了,由于我本身就对windows内核编程不熟悉,有调试了大概3,4天确认问题可能处在电源管理方面,联系到自己对这方面不是很熟悉,而且时间紧迫,没办法转向windriver开发!我安装的是9.21版本(请到迅雷下载)。

1. 驱动的开发:a 这步开发比较简单,首先确认你的device固件正确能枚举成功,然后将device连接到pc usb ho st 端。

b 按照向导指引刷出你的设备进行配置,然后点击编译按钮生成代码。

这部分内容请参考安装文档的快速开发向导!2.应用程序开发:最主要的几个函数是,opendevice 和readwrite 函数:其实大家只要摘录向导生成代码的内容即可,这里贴一个我的static WDU_DRIVER_HANDLE hDriver = 0;static DRIVER_CONTEXT DrvCtx ;static BOOL DLLCALLCONVDeviceAttach(WDU_DEVICE_HANDLE hDevice,WDU_DEVICE *pDeviceInfo, PVOID pUserData){DRIVER_CONTEXT *pDrvCtx = (DRIVER_CONTEXT *)pUserData;DEVICE_CONTEXT *pDevCtx, **ppDevCtx;DWORD dwInterfaceNum = pDeviceInfo->pActiveInterface[0]->pActiveAltSetting->Descript or.bInterf aceNumber;DWORD dwAlternateSetting = pDeviceInfo->pActiveInterface[0]->pActiveAltSetting->Descript or.bAlt ernateSetting;TRACE("\nDeviceAttach: received and accepted attach for vendor id 0x%x, ""product id 0x%x, interface %ld, device handle 0x%p\n",pDeviceInfo->Descriptor.idVendor,pDeviceInfo->Descriptor.idProduct,dwInterfaceNum, hDevice);/* Add our device to the device list */pDevCtx = (DEVICE_CONTEXT *)malloc(sizeof(DEVICE_CONTEXT));if (!pDevCtx){ERR("DeviceAttach: failed allocating memory\n");return FALSE;}BZERO(*pDevCtx);pDevCtx->hDevice = hDevice;pDevCtx->dwInterfaceNum = dwInterfaceNum;pDevCtx->dwVendorId = pDeviceInfo->Descriptor.idVendor;pDevCtx->dwProductId = pDeviceInfo->Descriptor.idProduct;pDevCtx->dwAlternateSetting = dwAlternateSetting;OsMutexLock(pDrvCtx->hMutex);for (ppDevCtx = &pDrvCtx->deviceContextList; *ppDevCtx;ppDevCtx = &((*ppDevCtx)->pNext));*ppDevCtx = pDevCtx;pDrvCtx->dwDeviceCount++;OsMutexUnlock(pDrvCtx->hMutex);OsEventSignal(pDrvCtx->hEvent);/* Accept control over this device */return TRUE;}static VOID DLLCALLCONV DeviceDetach(WDU_DEVICE_HANDLE hDevice, PVOID pUserData) {DRIVER_CONTEXT *pDrvCtx = (DRIVER_CONTEXT *)pUserData;DEVICE_CONTEXT **pCur;DEVICE_CONTEXT *pTmpDev;BOOL bDetachActiveDev = FALSE;TRACE("\nDeviceDetach: received detach for device handle 0x%p\n", hDevice);OsMutexLock(pDrvCtx->hMutex);for (pCur = &pDrvCtx->deviceContextList;*pCur && (*pCur)->hDevice != hDevice;pCur = &((*pCur)->pNext));if (*pCur == pDrvCtx->pActiveDev){pDrvCtx->pActiveDev = NULL;pTmpDev = *pCur;*pCur = pTmpDev->pNext;free(pTmpDev);pDrvCtx->dwDeviceCount--;OsMutexUnlock(pDrvCtx->hMutex);if (bDetachActiveDev){/* When hDeviceUnusedEvent is not signaled, hDevice is possibly in use,* and therefore the detach callback needs to wait on it until it is* certain that it cannot be used.* When it is signaled - hDevice is no longer used. */OsEventWait(pDrvCtx->hDeviceUnusedEvent, INFINITE);}}DWORD DriverInit(WDU_MATCH_TABLE *pMatchTables, DWORD dwNumMatchTables, const PCHAR sDriverName, const PCHAR sLicense, DRIVER_CONTEXT *pDrvCtx) {DWORD dwError;WDU_EVENT_TABLE eventTable;/* Set Driver Name */if (!WD_DriverName(sDriverName))ERR("Error: Could not set driver name to %s, exiting\n",sDriverName);return WD_SYSTEM_INTERNAL_ERROR;}dwError = OsEventCreate(&pDrvCtx->hEvent);if (dwError)ERR("DriverInit: OsEventCreate() failed on event 0x%p: error 0x%lx " "(\"%s\")\n", pDrvCtx->hEvent, dwError, Stat2Str(dwError));return dwError;}dwError = OsMutexCreate(&pDrvCtx->hMutex);if (dwError){ERR("DriverInit: OsMutexCreate() failed on mutex 0x%p: error 0x%lx " "(\"%s\")\n", pDrvCtx->hMutex, dwError, Stat2Str(dwError));return dwError;}dwError = OsEventCreate(&pDrvCtx->hDeviceUnusedEvent);if (dwError){ERR("DriverInit: OsEventCreate() failed on event 0x%p: error 0x%lx " "(\"%s\")\n", pDrvCtx->hDeviceUnusedEvent, dwError, Stat2Str(dwError));return dwError;OsEventSignal(pDrvCtx->hDeviceUnusedEvent);BZERO(eventTable);eventTable.pfDeviceAttach = DeviceAttach;eventTable.pfDeviceDetach = DeviceDetach;eventTable.pUserData = pDrvCtx;dwError = WDU_Init(&hDriver, pMatchTables, dwNumMatchTables, &eventTabl e, sLicense, WD_ACKNOWLEDGE);if (dwError)ERR("DriverInit: failed to initialize USB driver: error 0x%lx ""(\"%s\")\n", dwError, Stat2Str(dwError));return dwError;}return WD_STATUS_SUCCESS;}VOID DriverUninit(DRIVER_CONTEXT *pDrvCtx){DEVICE_CONTEXT *pCur, *pTmpDev;if (pDrvCtx->hEvent)OsEventClose(pDrvCtx->hEvent);if (pDrvCtx->hMutex)OsMutexClose(pDrvCtx->hMutex);if (pDrvCtx->hDeviceUnusedEvent)if (hDriver)WDU_Uninit(hDriver);/* Release any remaining devices */ pCur = pDrvCtx->deviceContextList; while (pCur){pTmpDev = pCur;pCur = pCur->pNext;free(pTmpDev);}}DWORD OpenUsbDevice( void){DWORD dwError;WORD wVendorId = 0;WORD wProductId = 0;WDU_MATCH_TABLE matchTable; BZERO(DrvCtx);wVendorId = USE_DEFAULT;wProductId = USE_DEFAULT;/* use defaults */if (wVendorId == USE_DEFAULT)if (wProductId == USE_DEFAULT)wProductId = DEFAULT_PRODUCT_ID;BZERO(matchTable);matchTable.wVendorId = wVendorId;matchTable.wProductId = wProductId;dwError = DriverInit(&matchTable, 1, DEFAULT_DRIVER_NAME,DEFAULT_LICENSE_STRING, &DrvCtx);if (dwError){goto Exit;}/* Wait for the device to be attached */dwError = OsEventWait(DrvCtx.hEvent, ATTACH_EVENT_TIMEOUT); if (dwError){if (dwError==WD_TIME_OUT_EXPIRED){ERR("Timeout expired for connection with the device.\n""Check that the device is connected and try again.\n");}else{ERR("main: OsEventWait() failed on event 0x%p: error 0x%lx " "(\"%s\")\n", DrvCtx.hEvent, dwError, Stat2Str(dwError));}goto Exit;OsMutexLock(DrvCtx.hMutex);if (!DrvCtx.dwDeviceCount){OsMutexUnlock(DrvCtx.hMutex);return 1;}OsMutexUnlock(DrvCtx.hMutex);if (!DrvCtx.pActiveDev)DrvCtx.pActiveDev = DrvCtx.deviceContextList; OsEventReset(DrvCtx.hDeviceUnusedEvent);return 0 ;Exit:DriverUninit(&DrvCtx);return dwError;}void CloseUsbDevice( void){DriverUninit(&DrvCtx);}DWORD UsbRead(char *pBuffer , DWORD dwBufferSize , PDWORD pdwBytesTransferred){DWORD dwError ;WDU_DEVICE_HANDLE hDevice;OsMutexLock(DrvCtx.hMutex);hDevice = DrvCtx.pActiveDev->hDevice;OsMutexUnlock(DrvCtx.hMutex);dwError = WDU_TransferBulk(hDevice, 0x81,TRUE, 0, pBuffer,dwBufferSize,pdwBytesTransferred, TRANSFER_TIMEOUT);return dwError ;}3.驱动程序的发布:这个也比较简单,请参考自带文档usb manual 的11章节,其实就是用到了他的一个wdreg工具,我写了个批处理文件,想安装的直接点批处理即可!windriver开发驱动是比较方便,至于稳定性,现在正在测试,看来比较稳定!速度方面500kB是没问题!不过速度方面pc驱动固然有影响,device的firmware影响也是很大的,特别是双缓冲的ep,处理不当速度很难上去!。

Windows驱动开发技术详解笔记

Windows驱动开发技术详解笔记

Windows驱动开发技术详解笔记(4) 基本语法回顾4、注册表操作和文件操作类似,在操作注册表之前需要首先打开注册表,获得一个句柄,这可以通过函数ZwCreateKey 完成。

与ZwCreateFile函数类似,它通过一个OBJECT_ATTRIBUTES 获得需要创建或打开的路径信息,但在内核中这个路径与用户模式下不相同,实际上,因为用户模式下的应用程序总是由某个“当前用户”打开的,因此在用户模式下可以直接访问HKEY_CLASSES_ROOT 和HKEY_CURRENT_USER,但工作在内核模式下的驱动程序不属于任何一个用户,因此不能直接访问这两个根键。

如果ZwCreateKey 指定的项不存在,则会直接创建该项,同时由函数的Disposition参数返回REG_CREATED_NEW_KEY;如果指定项已经存在了,则Disposition返回值REG_OPENED_EXISTING_KEY。

DDK同样提供了一个ZwOpenKey函数用以简化打开注册表的操作。

同时DDK还提供一系列以Rtl 开头的运行时函数,它们可以是对Zw系列函数的封装,可以有效地简化对注册表的操作过程。

表 Zw系统注册相关函数/en-us/library/ff566425%28VS.85%29.aspx表 Rtl系统注册相关函数/en-us/library/ff561822%28VS.85%29.aspx1)读写注册表注册表是以二元形式存储的,即“键名”和“键值”,通过键名来设置键值,其中键值分为多种情况。

表注册键类型通过ZwSetValueKe y 函数添加或修改注册表键值,通过ZwQueryValueKe y 函数查询相关键值。

2)枚举枚举注册表通常分两种情况:枚举一个注册表项的所有子项和枚举一个注册表项的所有子键。

枚举子项使用ZwQueryKey(注意不是ZwQueryValueKey)和ZwEnumerateKe y配合完成,枚举子键使用ZwQueryKey和ZwEnumerateValueKey配合完成。

linux设备驱动程序开发总结

linux设备驱动程序开发总结

不管我们学习什么编程语言,和我们见面的第一个程序就是“hello world!” 相信各位道上的朋友都遇到过这种个程序!!学习驱动程序也不例外,我学的第一个驱动程序就是“hello world!!”具体的程序代码如下:#include <linux/init.h>#include <linux/module.h>MODULE_LICENSE("Dual BSD/GPL");static int hello_init(void){printk(KERN_ALERT"Hello, world!\n");return 0;}static void hello_exit(void){printk(KERN_ALERT"byby FriendyARM mini2440!\n");}module_init(hello_init);module_exit(hello_exit);将其复制到工作目录下,并编写一个简单的Makefile文件:由于每个人使用的Linux系统不一样且每个人内核源代码所存放的位置也不是一样的。

所以编写Makefile文件的时候,参考别人的进行修改是一个很不错的的学习Makefile文件的方法。

当然你能把Linux内核的Makefile文件了解一下,对你了解Linux内核有很大的帮助的。

学习心得:1、驱动模块运行在内核空间,运行是不能依赖任何函数库和模块连接,所以在写驱动程序的时候所调用的函数只能是作为内核一部分的函数。

2、驱动模块和应用程序的一个重要不同是:应用程序退出时可不管资源释放或者其他的清除工作,但模块的退出啊哈念书必须仔细撤销初始化函数所做的一切,否则,在系统想重新引导之前某些东西就会残留在系统中。

3、处理器的多种工作模式其实就是为了操作系统的用户空间和内核空间设计的,在Unix类的操作系统中只是用到了两个级别:最高级别和最低级别。

SYSTEM文件夹下的delay文件夹学习小结

SYSTEM文件夹下的delay文件夹学习小结

SYSTEM⽂件夹下的delay⽂件夹学习⼩结SYSTEM⽂件夹1、STM32商家提供的⼀个底层核⼼驱动函数,可以⽅便初学者快速构建⾃⼰的⼯程。

2、SYSTEM⽂件夹下包含了delay、sys、usart三个⼦⽂件夹,分别包含了delay.c、sys.c、usart.c及其头⽂件。

通过这三个c⽂件可以构建最基本的框架。

delay⽂件夹1、delay⽂件夹内包含了delay.c和delay.h两个⽂件,⽤来实现系统的延时功能。

2、Cortex-M3内核的处理器内部包含了⼀个SysTick定时器(24位的倒计数定时器),利⽤SysTick来实现延时,既不占⽤中断,也不占⽤系统定时器。

3、delay函数采⽤时钟摘取法,只抓取SysTick计数器的变化,并不需要修改SysTick的任何状态,完全不影响SysTick作为µC/OS时钟节拍的功能。

delay_init函数1、该函数⽤来初始化fac_us和fac_ms两个重要参数;同时使⽤了条件编译来选择不同的初始化过程,如果不适⽤OS,则只是设置⼀下SysTick的时钟源以及确定fac_us和fac_ms的值,如果使⽤OS,则进⾏⼀些不同的配置。

2、SysTick是MDK定义了的⼀个结构体,⾥⾯包含CTRL、LOAD、VAL、CALLB这4个寄存器。

delay_us函数1、该函数⽤来延时指定的µs,其参数nus为要延时的微秒数。

该函数具有使⽤OS和不使⽤OS两个版本。

2、不使⽤OS的时候://延时nus//nus为要延时的us数.void delay_us(u32 nus){u32 temp;SysTick->LOAD=nus*fac_us; //时间加载SysTick->VAL=0x00; //清空计数器SysTick->CTRL=0x01 ; //开始倒数do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达SysTick->CTRL=0x00; //关闭计数器SysTick->VAL =0X00; //清空计数器}①先把要延时的µs数换算成SysTick的时钟数②写⼊LOAD寄存器③清空当前寄存器VAL的内容,再开启倒数功能,等倒数结束即延时了nus④最后关闭SysTick,清空VAL的值,实现⼀次延时nus的操作⑤“temp&0x01”这⼀句⽤来判断systick定时器是否还处于开启状态,防⽌systick被意外关闭导致的死循环。

字符设备驱动程序及数据结构简介-vincent_zou的专栏-CSDN博客

字符设备驱动程序及数据结构简介-vincent_zou的专栏-CSDN博客

字符设备驱动程序及数据结构简介-vincent_zou的专栏-CSDN博客展开全文1.设备号分为主次设备号,看上去像是两个号码,但在内核中用dev_t(<linux/types.h>)一种结构表示,同时不应该自己去假设赋值设备号,而是使用宏(<linux/kdev_t.h>)来取得.MAJOR(dev_t dev);MINOR(dev_t dev);即使你有确定的主,次设备号也要用dev=MKDEV(int major, int minor);1.1分配设备号<linux/fs.h>静态分配 //first就是上面的devint register_chrdev_region(dev_t first, unsigned int count, char *name);first 是你要分配的起始设备编号. first 的次编号部分常常是 0, 但是没有要求是那个效果.count 是你请求的连续设备编号的总数. (一般为1)注意, 如果count 太大, 你要求的范围可能溢出到下一个次编号; 但是只要你要求的编号范围可用, 一切都仍然会正确工作.name 是应当连接到这个编号范围的设备的名子(DEVICE_NAME); 它会出现在 /proc/devices 和 sysfs 中动态分配int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);dev 是一个只输出的参数, 它在函数成功完成时持有你的分配范围的第一个数.fisetminor 应当是请求的第一个要用的次编号; 它常常是 0.count 和 name 参数如同给 request_chrdev_region 的一样>>>应该始终使用动态分配,但最好为定制设备号留有接口,以参数形式,以name_major=0做为默认值,可能的操作如下:if (scull_major) {dev = MKDEV(scull_major, scull_minor);result = register_chrdev_region(dev, scull_nr_devs, "scull");} else {result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull");scull_major = MAJOR(dev);}if (result < 0) {printk(KERN_WARNING "scull: can't get major %d\n", scull_major);return result;}1.2释放设备号 //设备号void unregister_chrdev_region(dev_t first, unsigned int count);2.重要的数据结构2.1文件操作<linux/fs.h>中的file_operation结构,其成员struct module *owner 第一个 file_operations 成员根本不是一个操作; 几乎所有时间中, 它被简单初始化为THIS_MODULE, 一个在<linux/module.h> 中定义的宏.loff_t (*llseek) (struct file *, loff_t, int); llseek 方法用作改变文件中的当前读/写位置, 并且新位置作为(正的)返回值. loff_t 参数是一个"long offset", 并且就算在 32位平台上也至少 64 位宽. 错误由一个负返回值指示. 如果这个函数指针是 NULL, seek 调用会以潜在地无法预知的方式修改 file 结构中的位置计数器ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 用来从设备中获取数据. 在这个位置的一个空指针导致read 系统调用以-EINVAL("Invalid argument") 失败. 一个非负返回值代表了成功读取的字节数( 返回值是一个 "signed size" 类型, 常常是目标平台本地的整数类型).ssize_t (*aio_read)(struct kiocb *, char __user *, size_t, loff_t); 初始化一个异步读-- 可能在函数返回前不结束的读操作. 如果这个方法是 NULL, 所有的操作会由 read 代替进行(同步地).ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 发送数据给设备. 如果 NULL, -EINVAL 返回给调用 write 系统调用的程序. 如果非负, 返回值代表成功写的字节数.ssize_t (*aio_write)(struct kiocb *, const char __user *, size_t, loff_t *); 初始化设备上的一个异步写.int (*readdir) (struct file *, void *, filldir_t); 对于设备文件这个成员应当为 NULL; 它用来读取目录, 并且仅对文件系统有用.unsigned int (*poll) (struct file *, struct poll_table_struct *); poll 方法是 3 个系统调用的后端: poll, epoll, 和 select, 都用作查询对一个或多个文件描述符的读或写是否会阻塞. poll 方法应当返回一个位掩码指示是否非阻塞的读或写是可能的, 并且, 可能地, 提供给内核信息用来使调用进程睡眠直到I/O 变为可能. 如果一个驱动的poll 方法为NULL, 设备假定为不阻塞地可读可写.int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); ioctl 系统调用提供了发出设备特定命令的方法(例如格式化软盘的一个磁道, 这不是读也不是写). 另外, 几个 ioctl 命令被内核识别而不必引用 fops 表. 如果设备不提供 ioctl 方法, 对于任何未事先定义的请求(-ENOTTY, "设备无这样的 ioctl"), 系统调用返回一个错误.int (*mmap) (struct file *, struct vm_area_struct *); mmap 用来请求将设备内存映射到进程的地址空间. 如果这个方法是NULL, mmap 系统调用返回 -ENODEV.int (*open) (struct inode *, struct file *); 尽管这常常是对设备文件进行的第一个操作, 不要求驱动声明一个对应的方法. 如果这个项是NULL, 设备打开一直成功, 但是你的驱动不会得到通知.int (*flush) (struct file *); flush 操作在进程关闭它的设备文件描述符的拷贝时调用; 它应当执行(并且等待)设备的任何未完成的操作. 这个必须不要和用户查询请求的 fsync 操作混淆了. 当前, flush 在很少驱动中使用; SCSI 磁带驱动使用它, 例如, 为确保所有写的数据在设备关闭前写到磁带上. 如果 flush 为 NULL, 内核简单地忽略用户应用程序的请求.int (*release) (struct inode *, struct file *); 在文件结构被释放时引用这个操作. 如同 open, release 可以为 NULL.int (*fsync) (struct file *, struct dentry *, int); 这个方法是 fsync 系统调用的后端, 用户调用来刷新任何挂着的数据. 如果这个指针是NULL, 系统调用返回 -EINVAL.int (*aio_fsync)(struct kiocb *, int); 这是 fsync 方法的异步版本.int (*fasync) (int, struct file *, int); 这个操作用来通知设备它的FASYNC 标志的改变. 异步通知是一个高级的主题, 在第 6 章中描述. 这个成员可以是NULL 如果驱动不支持异步通知.int (*lock) (struct file *, int, struct file_lock *); lock 方法用来实现文件加锁; 加锁对常规文件是必不可少的特性, 但是设备驱动几乎从不实现它.ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); 这些方法实现发散/汇聚读和写操作. 应用程序偶尔需要做一个包含多个内存区的单个读或写操作; 这些系统调用允许它们这样做而不必对数据进行额外拷贝. 如果这些函数指针为 NULL, read 和 write 方法被调用( 可能多于一次 ).ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void *); 这个方法实现 sendfile 系统调用的读, 使用最少的拷贝从一个文件描述符搬移数据到另一个. 例如, 它被一个需要发送文件内容到一个网络连接的 web 服务器使用. 设备驱动常常使 sendfile 为 NULL.ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); sendpage 是 sendfile 的另一半; 它由内核调用来发送数据, 一次一页, 到对应的文件. 设备驱动实际上不实现 sendpage.unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 这个方法的目的是在进程的地址空间找一个合适的位置来映射在底层设备上的内存段中. 这个任务通常由内存管理代码进行; 这个方法存在为了使驱动能强制特殊设备可能有的任何的对齐请求. 大部分驱动可以置这个方法为 NULL.[10]int (*check_flags)(int) 这个方法允许模块检查传递给fnctl(F_SETFL...) 调用的标志.int (*dir_notify)(struct file *, unsigned long); 这个方法在应用程序使用 fcntl 来请求目录改变通知时调用. 只对文件系统有用; 驱动不需要实现 dir_notify.>>>下面是一个实现的可能例子,重要的函数被实现struct file_operations scull_fops = {.owner = THIS_MODULE,.llseek = scull_llseek,.read = scull_read,.write = scull_write,.ioctl = scull_ioctl,.open = scull_open,.release = scull_release,};这个声明使用标准的 C 标记式结构初始化语法.2.2文件结构struct file, 定义于 <linux/fs.h>其成员:mode_t f_mode; 文件模式确定文件是可读的或者是可写的(或者都是), 通过位FMODE_READ 和FMODE_WRITE. 你可能想在你的open 或者 ioctl 函数中检查这个成员的读写许可, 但是你不需要检查读写许可, 因为内核在调用你的方法之前检查. 当文件还没有为那种存取而打开时读或写的企图被拒绝, 驱动甚至不知道这个情况.loff_t f_pos; 当前读写位置. loff_t 在所有平台都是 64 位( 在 gcc 术语里是 long long ). 驱动可以读这个值, 如果它需要知道文件中的当前位置, 但是正常地不应该改变它; 读和写应当使用它们作为最后参数而收到的指针来更新一个位置, 代替直接作用于 filp->f_pos. 这个规则的一个例外是在 llseek 方法中, 它的目的就是改变文件位置.unsigned int f_flags; 这些是文件标志, 例如O_RDONLY, O_NONBLOCK, 和 O_SYNC. 驱动应当检查 O_NONBLOCK 标志来看是否是请求非阻塞操作( 我们在第一章的"阻塞和非阻塞操作"一节中讨论非阻塞 I/O ); 其他标志很少使用. 特别地, 应当检查读/写许可, 使用f_mode 而不是 f_flags. 所有的标志在头文件 <linux/fcntl.h> 中定义.struct file_operations *f_op; 和文件关联的操作. 内核安排指针作为它的open 实现的一部分, 接着读取它当它需要分派任何的操作时. filp->f_op 中的值从不由内核保存为后面的引用; 这意味着你可改变你的文件关联的文件操作, 在你返回调用者之后新方法会起作用. 例如, 关联到主编号 1 (/dev/null, /dev/zero, 等等)的 open 代码根据打开的次编号来替代 filp->f_op 中的操作. 这个做法允许实现几种行为, 在同一个主编号下而不必在每个系统调用中引入开销. 替换文件操作的能力是面向对象编程的"方法重载"的内核对等体.void *private_data; open 系统调用设置这个指针为 NULL, 在为驱动调用open 方法之前. 你可自由使用这个成员或者忽略它; 你可以使用这个成员来指向分配的数据, 但是接着你必须记住在内核销毁文件结构之前, 在 release 方法中释放那个内存. private_data 是一个有用的资源, 在系统调用间保留状态信息, 我们大部分例子模块都使用它.struct dentry *f_dentry; 关联到文件的目录入口( dentry )结构. 设备驱动编写者正常地不需要关心dentry 结构, 除了作为filp->f_dentry->d_inode 存取 inode 结构.2.3inode结构其成员:dev_t i_rdev; 对于代表设备文件的节点, 这个成员包含实际的设备编号.struct cdev *i_cdev; struct cdev 是内核的内部结构, 代表字符设备; 这个成员包含一个指针, 指向这个结构, 当节点指的是一个字符设备文件时.i_rdev 类型在 2.5 开发系列中改变了, 破坏了大量的驱动. 作为一个鼓励更可移植编程的方法, 内核开发者已经增加了 2 个宏, 可用来从一个 inode 中获取主次编号:unsigned int iminor(struct inode *inode);unsigned int imajor(struct inode *inode);//不太了解为了不要被下一次改动抓住, 应当使用这些宏代替直接操作 i_rdev3.字符设备的注册3.1添加struct cdev *my_cdev = cdev_alloc();my_cdev->ops = &my_fops;//有了cdev_init函数这个多余了但是, 偶尔你会想将 cdev 结构嵌入一个你自己的设备特定的结构; scull 这样做了. 在这种情况下, 你应当初始化你已经分配的结构, 使用: void cdev_init(struct cdev *cdev, struct file_operations *fops);任一方法, 有一个其他的struct cdev 成员你需要初始化. 象file_operations 结构, struct cdev 有一个拥有者成员, 应当设置为THIS_MODULE. 一旦 cdev 结构建立, 最后的步骤是把它告诉内核, 调用:int cdev_add(struct cdev *dev, dev_t num, unsigned int count);这里, dev 是cdev 结构, num 是这个设备响应的第一个设备号, count 是应当关联到设备的设备号的数目. 常常 count 是 1, 但是有多个设备号对应于一个特定的设备的情形.>>>在使用 cdev_add 是有几个重要事情要记住. 第一个是这个调用可能失败. 如果它返回一个负的错误码, 你的设备没有增加到系统中. 它几乎会一直成功, 但是, 并且带起了其他的点: cdev_add 一返回, 你的设备就是"活的"并且内核可以调用它的操作. 除非你的驱动完全准备好处理设备上的操作, 你不应当调用 cdev_add3.2去除一个字符设备, 调用:void cdev_del(struct cdev *dev);>>>实例,将cdev放入一个自定义的结构中:struct scull_dev {struct scull_qset *data; /* Pointer to first quantum set */int quantum; /* the current quantum size */int qset; /* the current array size */unsigned long size; /* amount of data stored here */unsigned int access_key; /* used by sculluid and scullpriv */ struct semaphore sem; /* mutual exclusion semaphore */struct cdev cdev; /* Char device structure */};以下代码是对其初始化:static void scull_setup_cdev(struct scull_dev *dev, int index){int err, devno = MKDEV(scull_major, scull_minor + index);cdev_init(&dev->cdev, &scull_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &scull_fops;err = cdev_add (&dev->cdev, devno, 1);/* Fail gracefully if need be */if (err)//it is importent!printk(KERN_NOTICE "Error %d adding scull%d", err, index);}五、open和releaseopen方法提供给驱动程序以初始化的能力,为以后的操作作准备。

VxWorks驱动开发笔记

VxWorks驱动开发笔记

VxWorks驱动开发笔记普通应用软件的开发,客户都会提出很明确的需求如功能、用户界面、外部接口以及开发周期经费等等要求,这些要求一般都相对直观且容易理解。

但是对于驱动程序的开发开说,开发周期以及经费这些需求往往都比较容易理解,可是对于功能、用户界面以及外部接口等需求就很难描述了,因为这需要对底层操作系统的理解,否则就无法提出适宜的需求来,而对底层操作系统的理解才是驱动程序开发之所以困难的主要原因。

1.1 驱动程序的结构驱动程序有两大基本特征:一是它实现了对硬件设备的访问(最根本目的),二是它实现了一系列与硬件设备无关的的访问接口。

通过这些接口,上层软件在控制此类硬件设备时无需对硬件进行详细的了解就可以进行访问,此外,当硬件设备更换时,只需要修改设备驱动的硬件相关的部分,而上层软件无需做任何更改。

这两个基本特征也正好决定了驱动程序的主体结构。

如图1.1所示,图中的阴影部分为设备驱动程序。

图1.1 驱动程序的结构1.2 驱动程序的工作流程不同设备在操作系统中完成的工作是不同的,但是就是工作流程来说,大致可以分为两个阶段。

第一个阶段是初始化阶段,在初始化阶段,驱动程序主要完成硬件以及设备驱动相关数据结构的初始化。

第二个阶段是硬件的访问阶段,根据设备工作模式的不同,可以分为中断模式和轮询模式,无论何种模式都可以通过与硬件设备无关的通用接口进行硬件设备的访问。

2.1 串口驱动原理串口因为调试简单在许多数据量不大的场合依然较为流行,可以借助串口对目标机中操作系统的运行情况进行监控等等。

下图为Tornado开发软件通过串口对目标机上运行的VxWorks操作系统进行监控的结构原理图。

图2.1 Tornado通过串口对vxWorks操作系统进行监控设备的驱动程序分为与硬件相关部分和硬件无关部分,而硬件相关部分则负责具体的硬件实现,硬件无关部分实现了一系列通用的数据接口,其中硬件无关部分实现是create、remove、open、close、read、write、ioctl等7个通用的函数接口。

Linux驱动开发相关常用命令和技巧

Linux驱动开发相关常用命令和技巧

内核编程技巧


Linux内核编程相对与window环境下的编程, 其调试和编译相对都比较麻烦一点。可以根据 自己的个人喜好和习惯选择自己的编辑工具和 调试方法。最简单的调试即在驱动程序中使用 打印语句,将信息打印出来,通过dmesg命令 查看打印信息。 还可以使用dgdb、kdb、kprobes等内核调试用 具调试内核模块。
Linux最常用的命令
2. cd命令 (实例如下:)
ls@ls-virtual-machine:~$ cd /usr/src ls@ls-virtual-machine:/usr/src$
功能:用于进入目标目录 说明:cd ..用于进入当前目录的上一级目录; cd /用于进入根目录;cd ~ 用于进入用户目 录(即/home)
内核编程技巧

在Linux系统中proc文件系统是一个虚拟文件系 统,是Linux内核信息的抽象文件接口,大量内 核中的信息以及可调参数都被作为常规文件映 射到一个目录树中,这样我们就可以简单直接 的通过echo或cat这样的文件操作命令对系统 信息进行查取,在Linux内核编程中,可以从 proc文件系统中查看到诸如中断信息、集成信 息、处理器信息、内核符号信息等许多重要且 实用的信息。
Linux最常用的命令
4.lsmod 命令(实例如下:)
root@ls-virtual-machine:/# lsmod Module Size Used by timer 90877 0 rfcomm 37292 0
功能:主要用于显示当前Linux系统中已加 载的模块。 说明:驱动编程过程中可以查看驱动是否 加载成功。
Linux最常用的命令
11. chmod命令(实例如下:)
root@ls-virtual-machine:/home/ls/works/timer# chmod 777 test.sh
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

驱动SYS开发总结1.驱动简介1.1.驱动是什么计算机的外部设备需要和计算机进行数据交换,生产外部设备的厂家如何使计算机和自己的设备交换数据呢,就是通过驱动程序,从设备中读入到计算机中,早期的Win3.1,Win9x设备驱动是vxd,Win NT是kdm, Win2k 统一发展成wdm模式。

1.2.sys文件sys文件是驱动程序的可执行代码,其扩展名为.sys,驱动程序安装后保存在windows/system32/drivers目录中。

对于PnP设备,在设备插入后,sys文件会被windows装载到内存中,系统线程调用sys中的函数来和设备进行通信。

1.3.inf文件inf文件是安装设备驱动程序时必须使用的文件,其扩展名为 .inf,驱动程序安装后保存在windows/inf目录中。

系统使用一个扩展名为INF的文本文件来控制与安装驱动程序相关的大部分活动。

INF文件应该由驱动程序开发人员随驱动程序一起提供。

通过INF文件可以告诉操作系统哪一个文件需要复制到用户硬盘上,应该增加或修改哪一个注册表项,如此等等。

inf中提供产品设备的产品id,以及对应的sys文件名,驱动class名, class guid,b-client driverHOST 与DEVICE, ENDPOINT与PIPE我们进行的USB驱动开发大多数是usb-client driver,系统厂商大多数都已经把USB类驱动做好,我们则是在类驱动之上开发针对自己设备的驱动,习惯上称做usb-client driver,其在整个软件构架中地位如下:UHCD--USBD--USB CLIENT DRIVER--DLL OR APPusb-client driver仍然遵守WDM模型,是WDM驱动。

因为要支持PnP,所以要很小心的处理自己的资源以及IRP, 随时准备处理拔出或者插入设备的情况; 电源处理不当也会使系统无法唤醒。

需要了解的知识:wdm,usbdi,our usedevice,wdm:目标: a, 能提供接口函数,b, 能实现pnp,电源消息处理,wmi,i/o等处理,usbdi:urb,irp,等时,中断,控制,批传输的概念our usedevice:我们的usb设备的传输类型,设备的能力。

2.WDM机制WINDOWS 9X 及以前版本VXD,WIN NT 使用KDM机制,WIN2000后的驱动程序都使用WDM机制。

2.1.WDM驱动的分层机制WDM驱动的分层图:2.2.PDO以及IRP机制一种设备使用相同的驱动程序,每层驱动程序装载后,有一个驱动对象(driver object)。

在驱动对象中,有设备链,一个节点是一个设备对象(device object), 称为pdo,对应一个设备,用设备链实现多个设备支持。

系统使用irp(i/o request package)和设备进行通信,调用驱动程序函数时候,会传递需要操作的的设备对象pdo,以及进行通信使用的irp。

2.3.WDM驱动程序code构成1, 函数构成:基本函数:driverentry,adddevice,unload 入口函数driverentry必须使用driverentry命名,并向系统注册其他函数名。

i/o控制函数:startio,oninterrupt,dpcforisr,adaptercontrol。

分发函数:Dispatchpnp,Dispatchpower,Dispatchwmi, dispatchread, dispatchwrite。

其它见到的函数:deviceioctl,Dispatchcreate,Dispatchclose。

这些函数除了driverentry外,其它的都可以可以自己命名,由driverentry向系统注册。

2,必要性说明:必须函数:基本函数:driverentry,adddevice,分发函数:Dispatchpnp,Dispatchpower, Dispatchwmi,可选函数:处理请求队列需要的函数:i/o控制例程:startio,如果设备需要产生中断:i/o控制例程:oninterrupt,dpcforisr, DMA操作需要的函数:i/o控制函数:adaptercontrol,分发函数:dispatchread,dispatchwrite,2.4.必需的处理基本函数:driverentry,adddevice,分发函数:Dispatchpnp,Dispatchpower, Dispatchwmi,在driverentry中必须完成所需要的其他函数的注册,使得系统可以调用这些函数与设备进行通信。

在有新的设备插入时系统会调用adddevice,由驱动程序自己调用IoCreateDevice创建设备对象,并attach到设备堆栈中,并初始化设备对象的Flag成员。

Dispatchpnp,处理PnP管理器的发出的主功能码为IRP_MJ_PNP 的i/ o请求,实现设备对即插即用的支持。

Dispatchpower,处理电源管理器发出的主功能码为IRP_MJ_PNP 的i/ o请求,实现设备对电源管理的支持。

Dispatchwmi,处理WMI管理器发出的主功能码为IRP_MJ_SYSTEM_CONTROL 的i/o请求,实现设备对WMI (WINDOWS management instrumentation)的支持,作用是可以监控设备性能。

详细资料,可以查阅ddk,D_P2003-050_MBCUSB2_TRN_WDMSTRUCT_CN.pptB类驱动接口B类驱动和URB在这个UHCD--USBD--USB CLIENT DRIVER--DLL OR APP结构中, usbd将usb端口芯片驱动uhcd进行了包装,提供更便利的功能,使得其它设备驱动程序可以简单的利用这些功能。

usbd提供的函数就称为usbdi(usbd interface),主要利用 urb(usb request block), 将urb放入irp(可以自己分配irp)中传递给usbd,由usbd完成 usb设备的相关操作。

3.2.URB详细请阅读DDK帮助。

3.3.常用函数UsbBuildVendorRequest,UsbBuildGetDescriptorRequest, UsbBuildSelectConfigurationRequest,USBD_ParseConfigurationDescriptorEx,USBD_CreateConfigurationRequestEx,USBD_ParseDescriptors 4.我们的设备我们的设备有一个控制管道,两个bulk读写管道(自己的命令都通过读写来完成),支持usb2.0, 支持标准usb请求。

5.SYS开发5.1.安装配置开发环境1、确定你已经安装了Visual C++,2、安装2000 DDK,安装2000 DDK成功后,在“开始”->“程序”里应该有“Development Kits”->“Windows 2000 DDK”的项目。

(注意一定要先安装好VC,然后才安装DDK,这个顺序决不能颠倒!!)DDKROOT环境变量设置为Windows 2000 DDK的基目录,如果不是的话,必须进行手工配置。

请在控制面板“系统”属性的“高级”标签环境变量编辑器中设置好这个环境变量。

例:DDK的安装路径为:E: WINDDK3790 则新建用户环境变量变量名为: DDK ROOT 变量值为: E:WINDDK37905.2.制作inf文件系统使用一个扩展名为INF的文本文件来控制与安装驱动程序相关的大部分活动。

INF文件应该由驱动程序开发人员随驱动程序一起提供。

通过INF文件可以告诉操作系统哪一个文件需要复制到用户硬盘上,应该增加或修改哪一个注册表项,如此等等。

INF文件包含一些名字由方括号括起来的段,大部分段都含有一系列keyword = value形式的指令。

例如:[Version]Signature="$CHICAGO$" Class=UUSBDClassGUID=B51CA6BA-E750-4dff-9CDE-6AA963B17052{} provider=%LEADING% DriverVer=08/27/2001,0.1.0.1inf制作详细参看,D_P2003-050_MBCUSB2_TRN_INFSTRUCT_CN.ppt5.3.编写以及编译驱动1 、makefile 文件,2 、Sources文件makefile的内容是:# # DO NOT EDIT THIS FILE!!! Edit .sources. If you want to add a new source # file to this component. This file merely indirects to the real make file # that is shared by all the driver components of the Windows NT DDK # !INCLUDE $(NTMAKEENV)makefile.defSources:TARGETNAME=HelloWDM TARGETTYPE=DRIVER DRIVERTYPE=WDM TARGETPATH=OBJ ? INCLUDES= $(BASEDIR)inc; $(BASEDIR)incddk; TARGETLIBS= $(BASEDIR)lib*freeusbd.lib? SOURCES=HelloWDM.cpp 这个文件指定了生成的驱动程序目标名、存放obj文件的位置、lib文件的位置、被编译的源文件对象值得注意的是,“=”前后不能有空格,否则编译的时候会出错。

编译:从开始菜单里选择编译环境如:Windows 2000 Checked Build Environment.exe 它从配置文件sources中读出待编译的程序的配置,包括源文件、目标文件等,从环境变量include中得到引用文件的地址,然后调用编译链接器进行实际的编译链接工作。

编译所产生的日志文件: Build.log 链接中执行的命令行 Build.wrn 链接中遇到的警告Build.err 链接中遇到的错误5.4.驱动的安装调试Win2000以上都使用*.inf文件来控制与安装驱动程序相关的大部分活动。

Inf文件由驱动开发人员随驱动程序一起提供。

控制面板->添加新硬件,从硬件列表中选择其他设备,并单击从软盘安装,再单击浏览,找到*.inf所在文件夹后,确定。

接下来点下一步就ok了。

相关文档
最新文档