linuxlinux usb驱动编写写可以用库函数吗

linux驱动开发常用函数及函数 .
我的图书馆
linux驱动开发常用函数及函数 .
Region的操作函数__XXX_region(),Linux在头文件include/linux/ioport.h中定义了三个对I/O内存资源进行操作的宏:
  ①request_mem_region()宏,请求分配指定的I/O内存资源。
  ②check_ mem_region()宏,检查指定的I/O内存资源是否已被占用。
  ③release_ mem_region()宏,释放指定的I/O内存资源。
  这三个宏的定义如下:
  #define request_mem_region(start,n,name)     __request_region(&iomem_resource, (start), (n), (name))   #define check_mem_region(start,n)    __check_region(&iomem_resource, (start), (n))   #define release_mem_region(start,n)    __release_region(&iomem_resource, (start), (n))
  其中,参数start是I/O内存资源的起始物理地址(是CPU的RAM物理地址空间中的物理地址),参数n指定I/O内存资源的大小。
Linux内核中所有已分配的字符设备编号都记录在一个名为 chrdevs 散列表里。该散列表中的每一个元素是一个 char_device_struct 结构,它的定义如下
static struct char_device_struct {
&&&&&&&struct char_device_struct *next; // 指向散列冲突链表中的下一个元素的指针
&&&&&&&unsigned int major; // 主设备号
&&&&&&&unsigned int baseminor; // 起始次设备号
&&&&&&&int minorct; // 设备编号的范围大小
&&&&&&&char name[64]; // 处理该设备编号范围内的设备驱动的名称
&&&&&&&struct file_operations *fops; // 没有使用
&&&&&&&struct cdev *cdev; // 指向字符设备驱动程序描述符的指针
注意,内核并不是为每一个字符设备编号定义一个 char_device_struct 结构,而是为一组对应同一个字符设备驱动的设备编号范围定义一个 char_device_struct 结构。chrdevs 散列表的大小是 255,散列算法是把每组字符设备编号范围的主设备号以 255 取模插入相应的散列桶中。同一个散列桶中的字符设备编号范围是按起始次设备号递增排序的。
注册内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()。这三个函数都会调用一个共用的 __register_chrdev_region() 函数来注册一组设备编号范围(即一个 char_device_struct 结构)。
内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()。其中,register_chrdev_region()是为提前知道 设备的主次设备号的设备分配设备编号。alloc_chrdev_region() 是动态分配主次设备号。register_chrdev()。是老版本的设备号注册方式,他只分配主设备号。从设备号在mknod的时候指定 ioremap_nocache 把内存映射到CPU空间 void __iomem * ioremap_nocache (unsigned long phys_addr, unsigned long size); phys_addr 要映射的物理地址 size 要映射资源的大小 ioremap_nocache进行一系列平台相关的操作使得CPU可以通过readb/readw/readl/writeb/writew/writel等IO函数进行访问。在译者的使用过程种并没有出现不能作为虚拟地址直接访问的情况,可能是某些平台下的不可以吧。译者的使用平台是x86和ixp425] 这个版本的ioremap确保这些内存在CPU是不可缓冲的,如同PCI总线上现存的缓冲规则一样。注:此时在很多总线上仍有其他的缓冲和缓存。在某些特殊的驱动中,作者应当在PCI写的时候进行读取。这对于一些控制寄存器在这种不希望复合写或者缓冲读的区域内时是非常有用的返回的映射地址必须使用iounmap来释放。
TA的最新馆藏[转]&linux驱动程序开发详细介绍
作者:佚名
字体:[ ] 来源:互联网 时间:11-13 08:49:54
前提,一般来说内核代码的错误可能会引起一个用户进程的死亡,或者整个系统的瘫痪,更严重的后果,可能导致磁盘损伤~因此建议最好有一台实验机进行系统的测试
前提,一般来说内核代码的错误可能会引起一个用户进程的死亡,或者整个系统的瘫痪,更严重的后果,可能导致磁盘损伤~因此建议最好有一台实验机进行系统的测试。 第一个内核模块(Hello World模块) 代码如下: View Code #include&linux/init.h& #include&linux/module.h& MODULE_LICENSE("Dual BSD/GPL"); static __init int hello_init(void) { //printk函数在内核中定义对模块可用,内核需要自已的打印涵数 //因为它靠自已运行,而没有相应的库函数。 //模块能够调用printk是因为insmod加载了之后,模块被链接到内核 //因些可调用内核的公用符号,KERN_ALERT是消息的优先级 printk(KERN_ALERT"HELLO WORLD\n"); return 0; } static __exit void hello_exit(void) { printk(KERN_ALERT"GoodBye\n"); } module_init(hello_init); module_exit(hello_exit); 在这个模块中定义了两个函数,一个在模块加载到内核时调用(hello_init),另一个在从内核将模块移出时调用(hello_exit);在上面的代码中,module_init与module_exit是两个内核宏定义,用于告诉内核从哪里启动,从哪里退出,MODULE_LICENSE宏用于声明模块是遵守某个自由许可证的,否则内核加载时会出现警告。 好了,现在可以对上面这个程序进行相应的测试,在测试之前必须要编写相应的Makefile文件,模块的编译与普通程序的编译是不同的 Makefile文件 代码如下: View Code #makefile for hello world # KERNELRELEASE是在内核源码中定义的第一个变量 ifneq ($(KERNELRELEASE),) #判断变量是否为空(第一次执行时没有定义) #没定义时执行else语句 obj-m := HelloWorld.o#表明有一个模块要从目录文件HelloWorld.o建立,建立之后将其 #命名为HelloWorld.ko #如果有一个模块名为module.ko,来自于两个源文件,假设为file1.c与file2.c #则应该这样 obj-m := module.o # module-objs:=file1.o file2.o else KDIR:=/lib/modules/$(shell uname -r)/build all: #当make的目标为all时,-C $(KDIR)跳到内核源码目录下读取Makefile #M=$(PWD)表示返回当前目录继续读取,执行当前的Makefile,当再次执行时 #$(KERNELRELEASE)已经定义,make将读取else之前的内容 make -C $(KDIR) M=$(PWD) modules clean: rm -rf *.ko *.o *.mod.o *.mod.c *.symvers endif 相应的解释如上 开如编译内核:必须要是超级用户 在当前路径下输入make 编译完成后,输入insmd HelloWorld.ko进行内核的加载,使用dmesg |tail可以查看内核的输出信息。 移除内核采用rmmod HelloWorld 相应的使用dmesg|tail可以看到打印出GoodBye Printk可能没有输出到屏幕上,这与KERN_ALERT的优先级有关,说明还不够高,内核输出的内容实际在/var/log/kern.log中,可以vim /var/log/kern.log查看。 内核模块与应用程序的不同: 1:应用程序运行后就会处理相应的任务,而内核模块注册后是用来服务于将来请求,并且初始化函数加了__init之后,调用完后,内存空间立即释放。 2:应用程序终止时可以不用负责回收资源,由操作系统来维护,但内核模块在除时必须释放资源。 3:应用程序可以调用相应的库函数,而内核模块能够调用的则只要内核中输入的那些函数。在内核模块的编程中,源文件不应当包括通常的头文件,但也有例外,如&stdarg.h&等少部分头文件是仅有的例外。 4:错误的处理方式不同,在应用程序中段错误,可以由相应的调试程序进行检查更改,但内核模块中,段错误,如果不终止整个系统的话,就会终止当前进程。 用户空间与内核空间: 应用程序在用户空间运行,而内核模块是在内核空间内运行的。每种模式都有它自已的内存映射,它自已的地址空间。 内核与当前进程的关系: 内核模块做的大部份动作是代表一个特定进程的,内核代码可以引用当前进程,通过存取全局项current,它在&asm/cuurent.h&定义: #define current get_current()//通过这个宏定义可以获取指向task_struct的任务指针 内核代码可以通过current来使用进程特定的信息。 内核符号表: 内核模块在加载时通过查找内核符号表来解决未定义的符号,内核符号表包涵了全局内核项的地址,当加载一个模块时,模块中输出的符号也将成为内核符号表的一部分。 模块的输入符号通常采用以下两种形式: EXPORT_SYMBOL(name) EXPORT_SYMBOL_GPL(name) 上面的宏定义中的任何一个使得给定的符号在模块外使用,_GPL版本的宏定义只能使符号对_GPL许可的模块可用。 版本依赖: 模块代码一定要为每个它要连接的内核版本重新编译,在模块编译的过程中,其中一步是到当前的内核对读取Makefile文件,在编译的过程中会采用内核树中的文件(vermagic.o)连接你的模块,在这个文件里面有许多有关内核的信息,包括版本... 模块参数: 模块参数由insmod与modprobe在加载时指定。 对前面的HelloWorld.c进行修改如下: 在终端上输入 代码如下: Make Insmod HelloWorld.ko who=&test& num=10 Dmesg|tail -3 即可以看到。 声明数组参数时采用module_param_array(name,type,num,perm) Name是数组的名字,type是数组元素的类型,num是数组无数的个数,perm是权限 附:insmod Insmod将内核模块加载到内存中,它依赖一个在kernel/module.c中定义的系统调用,函数sys_init_module分配内核内存来存放模块,它接着copy模块的代码段到这块内存区,借助内核符号表来解决模块中的内核引用,并且调用模块的初始经函数来启动所有的东西。 Modprobe工具也用来加载一个内核模块到内存,与insmod不同的是,它会查看要加载的模块,看看是否引用了当前内核没有定义的符号。如要有,它会在当前搜索路径下寻找其他模块,看是否这个符号的定义,如果有,则将这个模块也加载进内核。 Rmmod用来去除内核模块,如果内核认为模块还在使用,或者内核配置了不允许去除模块,则模块的卸载会失败。 Lsmod例举出当前系统中加载的所有模块列表。 内核模块编程中函数通常声明为静态的,是因为它们不会在文件之外可见。
大家感兴趣的内容
12345678910
最近更新的内容Linux驱动基础开发 - Linux 设备驱动概述_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Linux驱动基础开发
Linux 设备驱动概述
来源:Linux社区&
作者:xdw1985829
目前,Linux软件工程师大致可分为两个层次:
 (1)Linux应用软件工程师(Application Software Engineer):
&& & &主要利用C库函数和Linux API进行应用软件的编写;
&& & &从事这方面的开发工作,主要需要学习:符合linux posix标准的API函数及系统调用,linux的多任务编程技巧:多进程、多线程、进程间通信、多任务之间的同步互斥等,嵌入式数据库的学习,UI编程:QT、miniGUI等。
 (2)Linux固件工程师(Firmware Engineer):
&& & &主要进行Bootloader、Linux的移植及Linux设备驱动程序的设计工作。
一般而言,固件工程师的要求要高于应用软件工程师的层次,而其中的Linux设备驱动编程又是Linux程序设计中比较复杂的部分,究其原因,主要包括如下几个方面:
&& &1)设备驱动属于Linux内核的部分,编写Linux设备驱动需要有一定的Linux操作系统内核基础;需要了解部分linux内核的工作机制与系统组成
&& &2)编写Linux设备驱动需要对硬件的原理有相当的了解,大多数情况下我们是针对一个特定的嵌入式硬件平台编写驱动的,例如:针对特定的主机平台:可能是三星的,也可能是atmel的,或者飞思卡尔的等等
&& &3)Linux设备驱动中广泛涉及到多进程并发的同步、互斥等控制,容易出现bug;因为linux本身是一个多任务的工作环境,不可避免的会出现在同一时刻对同一设备发生并发操作
&& &4)由于属于内核的一部分,Linux设备驱动的调试也相当复杂。linux设备驱动没有一个很好的IDE环境进行单步、变量查看等调试辅助工具;linux驱动跟linux内核工作在同一层次,一旦发生问题,很容易造成内核的整体崩溃。
&& &本系列文章我们将一步步、深入浅出的介绍linux设备驱动编程中设计的一些问题及学习方法,希望对大家学习linux设备驱动有所帮助。
&& &在任何一个计算机系统中,大至服务器、PC机、小至手机、mp3/mp4播放器,无论是复杂的大型服务器系统还是一个简单的流水灯单片机系统,都离不开驱动程序的身影,没有硬件的软件是空中楼阁,没有软件的硬件只是一堆废铁,硬件是底层的基础,是所有软件得以运行的平台,代码最终会落实到硬件上的逻辑组合。
&& &但是硬件与软件之间存在一个驳论:为了快速、优质的完成软件功能设计,应用程序工程师不想也不愿关心硬件,而硬件工程师也很难有功夫去处理软件开发中的一些应用。例如软件工程师在调用printf的时候,不许也不用关心信息到底是通过什么样的处理,走过哪些通路显示在该显示的地方,硬件工程师在写完了一个4*4键盘驱动后,无需也不必管应用程序在获得键值后做哪些处理及操作。
&& &也就是说软件工程师需要看到一个没有硬件的纯软件世界,硬件必须透明的提供给他,谁来实现这一任务?答案是驱动程序,驱动程序从字面解释就是:“驱使硬件设备行动”。驱动程序直接与硬件打交道,按照硬件设备的具体形式,驱动设备的寄存器,完成设备的轮询、中断处理、DMA通信,最终让通信设备可以收发数据,让显示设备能够显示文字和画面,让音频设备可以完成声音的存储和播放。
&& &可见,设备驱动程序充当了硬件和软件之间的枢纽,因此驱动程序的表现形式可能就是一些标准的、事先协定好的API函数,驱动工程师只需要去完成相应函数的填充,应用工程师只需要调用相应的接口完成相应的功能。无论有没有操作系统,驱动程序都有其存在价值,只是在裸机情况下,工作环境比较简单、完成的工作较单一,驱动程序完成的功能也就比较简单,同时接口只要在小范围内符合统一的标准即可。但是在有操作系统的情况下,此问题就会被放大:硬件来自不同的公司、千变万化,全世界每天都会有大量的新芯片被生产,大量的电路板被设计出来,如果没有一个很好的统一标准去规范这一程序,操作系统就会被设计的非常冗余,效率会非常低。
&& &所以无论任何操作系统都会制定一套标准的架构去管理这些驱动程序:linux作为嵌入式操作系统的典范,其驱动架构具有很高的规范性与聚合性,不但把不同的硬件设备分门别类、综合管理,并且针对不同硬件的共性进行了统一抽象,将其硬件相关性降到最低,大大简化了驱动程序的编写,形成了具有其特色的驱动组织架构。
下图反映了应用程序、linux内核、驱动程序、硬件的关系。
linux内核分为5大部分:多任务管理、内存管理、文件系统管理、设备管理、网络管理;
每一部分都有承上下的作用,对上提供API接口,提供给应用开发工程师使用;
对下通过驱动程序屏蔽不同的硬件构成,完成硬件的具体操作。
【内容导航】
相关资讯 & & &
& (07/21/:14)
& (01/04/:27)
& (07/23/:38)
& (05/23/:33)
& (10/09/:05)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款
匿名 发表于 linxu ,内核提供的服务以及设定/article/734.html}

我要回帖

更多关于 linux 网卡驱动编写 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信