Linux下编写zlg7290驱动(3)-键盘驱动编写

在Linux环境下为zlg7290开发键盘驱动程序的第三部分涉及数据处理和中断。
第一个,注册驱动程序后,我们需要处理键盘击键。
zlg7290通过按64个按钮产生中断,驱动程序可以通过轮询或中断来检测它。
本示例将在按下按钮时触发任务队列,以避免Linux内核的i2c_transfer可能导致的睡眠问题。
中断处理函数`zlg7290_interrupt`收到中断信号后;这将启动作业队列。
工作队列“zlg7290_work”负责读取设备密钥值并发送给上层处理“input_report_key”和“input_sync”。
在测试部分,编写一个简单的程序从设备“/dev/input/event1”读取输入事件并打印按键代码和状态。
例如,当用户按下某个键时;终端将发出`user:key_val=code1`,当松开按键时,将输出“user:key_val=code0”,`code`键,其中`code`对应于`code`的键值。
当键值大于56时,它将映射到特定的键值。
至此,zlg7290键盘驱动的编写和测试就完成了。

Linux驱动编程——ch340x驱动移植

ch340x驱动替换的主要概念是将厂商提供的驱动源代码更改为特定的系统版本。
Linux系统通常提供这些驱动程序的源代码。
ch340简介ch340是一款用于USB转串口的芯片,需要编写驱动程序。
测试的目的是更换驱动程序;熟悉ch34x官方驱动的编译和加载方法,熟悉USB转串口功能。
硬件电路开发板和CH340模块。
下载驱动源码ch34x.c(驱动源码);从blog.csdn.net/JAZZSOLDI下载Linux驱动CH341SER_LINUX.ZIP...包括Makefile(编译文件)和readme.txt(版本和命令说明)。
代码更新主要修改了ch34x.c的两段代码,注释掉一些代码并自定义Makefile。
使用make命令编译运行目标文件ch34x.ko,生成目标文件。
使用makeinstall将目标文件复制到NFS目录。
安装CH340模块后,使用insmod命令加载ch34x驱动程序。
测试过程:加载驱动后,系统立即识别出新的串口,证明移植成功。
总结完成驱动移植后,已验证USB转串口功能的实现驱动程序在特定系统环境下的兼容性和可用性已得到验证。

linuxos下编写USB驱动必备知识

Linux操作系统中USB驱动必备知识总结

USB驱动开发包括基础理论和实际应用,主要关注设备类型和接口。

USB基础知识USB版本:USB1.x(包括1.0和1.1,最高12Mbps)、USB2.0(480Mbps,向下兼容旧版本)和USB3x)根据不同的传输率确定。
USB总线:主从结构,服务器(Host)控制数据传输,从机(Device)依赖于服务器。
控制传输和常规传输

控制传输负责设备初始化和配置,而常规传输则传输数据信息,包括Bulk、Interrupt和Isochronous。

驱动框架

Linux驱动分为HCD和DeviceDriver。
需要定义硬件接口并用C语言编写框架,涉及到usb_driver、usb_interface等数据结构。

HCD驱动程序:管理USB主机控制器并处理错误和数据传输。
设备驱动程序和USB核心:USB核心负责枚举和管理,而设备驱动程序处理设备功能和事件。
USB设备

每个USB设备都有一个与一个或多个功能相对应的配置和接口,并且可能需要多个驱动程序支持。

Endpoint:USB通信通道,数据传输识别。
编写示例和程序

驱动程序充当内核模块,连接应用程序和USB子系统。
插入设备后,Linux内核将列出设备,分配地址并下载驱动程序。

代码示例

在LinuxOS中,理解这些概念并练习编写驱动程序代码以实现正常的设备功能和识别非常重要。

怎样编写Linux设备驱动程序?

Linux是Unix操作系统的一个变体。
Linux下编写驱动程序的原理和思路与其他Unix系统完全相似,但dos或window环境下的驱动程序却有很大不同。
在Linux环境下设计驱动程序思路简单、操作方便、功能强大。
但支持的功能很少,只能依赖内核中的功能。
一些常用的操作必须自己写,调试不方便。
这几周,我编写了一个实验室开发的多媒体卡的驱动程序,积累了一些经验。
我想与Linux爱好者分享。
Linux设备驱动程序的概念。
系统调用是操作系统内核和应用程序之间的接口。
设备驱动程序是操作系统内核与机器硬件之间的接口。
设备驱动程序为应用程序屏蔽了硬件的详细信息。
这样,从应用程序的角度来看,硬件设备只是一个设备文件,应用程序可以像普通文件一样操作硬件设备。
设备驱动程序是内核的一部分,执行以下功能:1.初始化和释放设备。
2.将数据从内核传输到硬件并从硬件读取数据。
3.读取应用程序发送到设备文件的数据,并发送回应用程序请求的数据。
4、设备故障的检测和处理。
2、实例分析我们来写一个最简单的字符设备驱动。
虽然它什么也不做,但它可以让你了解Linux设备驱动程序是如何工作的。

如何编写驱动程序?

如何编写Linux设备驱动程序回想起来,我已经慢慢学习Linux操作系统近一年了,现在是时候写点东西了。
也可以看作是保存自己的记忆和记忆!我完全是自学成才,所以以下内容如有不妥之处,请多多指教。
Linux是Unix操作系统,虽然Linux中编写驱动程序的原理和思路与其他Unix系统非常相似,但DOS和Windows环境下的驱动程序却有很大不同。
在Linux环境下设计驱动程序思路简单,操作方便,功能强大,但支持的功能较少,需要自己编写一些常用的操作,调试难度较大。
很不方便。
下面的一些文字主要来自khg、johnsonm的Writelinuxdevicedriver、Brennan的GuidetoInlineAssembly、TheLinuxA-Z和清华BBS的有关设备驱动程序的信息。
1.Linux设备驱动程序概念系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。
设备驱动程序向应用程序隐藏硬件详细信息。
这样,从应用程序的角度来看,硬件设备只是一个设备文件,应用程序可以像普通文件一样操作硬件设备。
设备驱动程序是内核的一部分,执行以下功能:1.初始化并释放设备。
2.将数据从内核传输到硬件并从硬件读取数据。
3.读取应用程序发送到设备文件的数据,并发送回应用程序请求的数据。
4.检测并解决设备错误。
Linux操作系统中的设备文件主要分为三种类型:一是字符设备,二是块设备,三是网络设备。
字符设备和块设备之间的主要区别在于,当向字符设备发出读/写请求时,实际的硬件I/O通常立即发生。
这对于块设备来说是不同的。
如果用户可以满足进程的设备请求,则返回所请求的数据。
否则,调用请求函数来执行实际的I/O操作。
块设备主要是为慢速设备(例如磁盘)设计的,以避免等待过多的CPU时间。
正如前面提到的,用户进程通过设备文件来处理实际的硬件。
每个设备文件都有一个文件属性(c/b),指示它是字符设备还是块设备。
另外,每个文件都有两个设备号,第一个是标识驱动程序的主设备号,第二个是主设备号,用于标识驱动程序。
第一个识别了司机。
这是一个次设备号,用于标识使用相同设备驱动程序的不同硬件设备。
例如,如果您有两张软盘,则可以使用次设备号来区分它们。
设备文件中的主设备号必须与设备驱动程序在注册期间应用的主设备号相匹配。
否则,用户进程将无法访问驱动程序。
最后需要注意的是,当用户进程调用驱动程序时,系统处于核心状态,不再处于抢占式调度状态。
这意味着系统在执行任何其他工作之前必须从驱动程序的子功能返回。
如果您的驱动程序陷入无限循环,不幸的是您所要做的就是重新启动计算机并执行长时间的fsck。
读/写时,首先检查缓冲区的内容,如果缓冲区中的数据尚未处理,则先处理其内容。
如何在Linux操作系统中编写设备驱动程序2.分析示例我们来编写一个最简单的字符设备驱动程序。
这不会做任何事情,但它可以让您了解Linux设备驱动程序的工作原理。
在您的计算机中键入以下C代码以获取实际的设备驱动程序。
#define__NO_VERSION__#includemodules.h>#includeversion.h>charkernel_version[]=UTS_RELEASE;本节定义了不太有用但很重要的版本信息。
Johnsonm指出所有驱动程序必须首先包含config.h>并且通常最好使用它。
用户进程通过设备文件与硬件进行交互,因此设备文件操作只是几个系统调用,如open、read、write、close等。
请注意,它不是fopen或fread。
这需要了解非常重要的数据结构。
int(*read)(structinode*,structfile*,char,int);int(*write)(structinode*,structfile*,off_t,int);int(*readdir)(structinode*,structfile*,structdirent*,int);int(*select)(structinode*,structfile*,int,select_table*);int(*ioctl)(structinode*,structfile*,unsinedint,unsignedlong);int(*mmap)(structinode*,structfile*,structvm_area_struct*);int(*open)(structinode*,int(*f);同步)(结构节点*,结构文件*);int(*fasync)(结构节点*,结构文件*,int);int(*check_media_change)(structinode*,structfile*);}该结构的每个成员的名称对应于一个系统调用。
当用户进程使用系统调用执行读或写设备文件等操作时,系统调用通过设备文件的主设备号找到对应的设备驱动程序,并读取该数据结构中对应的函数指针。
然后将控制权转移到该函数。
这就是Linux设备驱动程序工作的基本原理。
在这种情况下,编写设备驱动程序的主要工作是创建子函数并填充file_operations中的各个字段。
现在我们开始编写子程序。
#includetypes.h>#includedefs.h>#includemm.h>#includeconfig.h>#includeerrno.h>#includesegment.h>unsignedinttest_major=0;staticintread_test(structinode*node,structfile*file,char*buf,intcount){intleft;if(verify_area(VERIFY_WRITE,buf,count)==-EFAULT)return-EFAULT;for(left=count;left>0;left--){__put_user(1,buf,1));buf++;}returncount;}此函数为读取调用做好准备。
当调用read时,会调用read_test()并将全1写入用户缓冲区。
buf是read调用的参数。
用户进程空间的地址。
然而,当调用read_test时,系统进入核心状态。
因此不能使用buf地址,必须使用内核提供的函数__put_user()向用户发送数据。
还有许多具有类似功能的函数。
请参阅Robert的《Linux内核设计与实现》(第2版)。
不过,在将数据复制到用户空间之前,需要确保buf可用。
为此,请使用函数verify_area。
staticintwrite_tibet(structinode*inode,structfile*file,constchar*buf,intcount){returncount;}staticintopen_tibet(structinode*inode,structfile*file){MOD_INC_USE_COUNT;return0;}staticvoidrelease_tibet(structinode*inode,structfile*file){MOD_DEC_USE_COUNT;}所有这些功能都无法操作。
实际调用发生时不执行任何操作,它只是提供指向底层结构的函数指针。
structfile_operationstest_fops={NULL,read_test,write_test,NULL,/*test_readdir*/NULL,NULL,/*test_ioctl*/NULL,/*test_mmap*/open_test,release_test,NULL,/*test_fsync*/NULL,/*test_fasync*//*仅此而已,用NULL填充*/};这样,我们就可以说设备驱动的主体就写好了。
接下来,需要将驱动程序内置到内核中。
驱动程序可以通过两种方式编译。
一种方法是将其编译成内核,另一种方法是将其编译成模块。
编译为内核会增加内核的大小,修改内核的源文件,并且无法动态卸载。
这对于调试没有用,所以我建议使用模块化方法。
intinit_module(void){intresult;result=register_chrdev(0,"test",&test_fops);if(result<0 xss=clean test_major=结果;/*动态*/return0;}insmod当使用该命令将编译后的模块传输到内存时,会调用init_module函数。>这里,init_module只做了一件事:将字符设备注册到系统的字符设备表中。
register_chrdev需要三个参数。
如果第一个参数是要检索的设备号,则系统选择一个空闲的设备号返回。
参数2是设备文件名,参数3用于注册。
指向实际执行操作的函数的指针。
如果注册成功,则返回设备的主设备号;如果注册不成功,则返回负值。
voidcleanup_module(void){unregister_chrdev(test_major,"test");}使用rmmod卸载模块时,cleanup_module调用该函数释放系统字符设备表中字符设备测试占用的表项。
可以说描述了一个非常简单的字符设备。
将文件命名为test.c。
编译:$gcc-O2-DMODULE-D__KERNEL__-ctest.c得到的文件test.o是一个设备驱动程序。
如果您的设备驱动程序有多个文件,请按照上面的命令行编译每个文件,然后ld-rfile1.ofile2.o-omodulename。
现在驱动程序已编译完毕,请将其安装到您的系统上。
$insmod–ftest.o安装成功后,您可以在/proc/devices文件中看到设备测试及其主设备号。
要卸载,请运行$rmmodtest。
下一步是创建设备文件。
mknod/dev/testcmajorminorc指的是字符设备,major是在/proc/devices中找到的主设备号。
使用shell命令$cat/proc/devices获取主设备号。
您可以将上述命令行添加到您的shell脚本中。
Minor是从设备号。
请设置为0。
现在可以通过设备文件访问驱动程序。
编写一个小测试程序。
#include#includetypes.h>#includestat.h>#includemain(){inttestdev;inti;charbuf[10];testdev=open("/dev/test",O_RDWR);if(testdev==-1){printf("无法打开文件\n");exit(0);}read(testdev,buf,10);for(i=0;i<10>以上只是一个快速演示。
真正实用的驱动程序要复杂得多,必须处理中断、DMA和I/O端口等问题。
这些才是真正的困难。
请参阅下一节了解如何处理现实生活中的情况。
如何在Linux操作系统上编写设备驱动程序3.设备驱动程序特定问题1.I/O端口。
硬件处理离不开I/O端口。
Linux允许操作系统轻松地操作I/O端口。
造成混乱。
每个驱动程序必须确保它自己不会滥用端口。
有两个重要的内核函数可确保驱动程序执行此操作。
1)check_region(intio_port,inoff_set)该函数检查系统的I/O表以查看是否有其他驱动程序占用特定的I/O端口。
参数1:I/O端口基址,参数2:I/O端口占用范围。
返回值:0,未占用;非0,已占用。
2)request_region(intio_port,intff_set,char*devname)如果该I/O端口没有被占用,则可以被驱动程序使用。
使用前必须在系统中注册,以免被其他程序占用。
注册完成后,可以在/proc/ioports文件中查看注册的I/O端口。
参数1:IO口基址。
参数2:IO口占用范围。
参数3:该IO在地址中使用设备名称。
注册I/O端口允许使用inb()、outb()和其他函数安全地访问它。
某些PCI设备将I/O端口映射到内存部分,访问这些端口相当于访问内存部分。
很多时候需要获取内存的物理地址。
2.内存操作:要在设备驱动程序中动态分配内存,请使用kmalloc而不是malloc,或者使用get_free_pages将其直接应用于页面。
Kfree或free_pages用于释放内存。
请注意,kmalloc等函数返回物理地址。
注意kmalloc最多只能开辟128k-16,其中16个字节被页面描述符结构占用。
用于内存映射I/O端口、寄存器或硬件设备(例如视频内存)的RAM通常占用F0000000以上的地址空间。
无法在驱动程序中直接访问它。
重映射的位置必须通过内核函数vremap来获取。
地点。
此外,许多硬件需要相对大量的连续内存用于DMA传输。
该程序必须始终存在于内存中并且不能交换到文件。
但是kmalloc最多只能开辟128k的内存。
这可以通过牺牲一些系统内存来解决。
3.中断处理:与I/O端口处理类似,要使用中断,必须首先向系统注册它们。
intrequest_irq(unsignedintirq,void(*handle)(int,void*,structpt_regs*),unsignedintlongflags,constchar*device);irq:是要应用的中断。
Handle:中断处理函数指针。
flags:SA_INTERRUPT请求快速中断,0请求普通中断。
设备:设备名称。
如果注册成功,则返回0。
此时,可以在/proc/interrupts文件中看到请求的中断。
4、常见问题解答。
时序在硬件操作中非常重要(对于具体时序问题,请参阅特定设备芯片的文档;例如网卡芯片RTL8139)。
然而,当您用C编写低级硬件操作时,gcc经常会优化您的程序,从而导致时序错误。
当以汇编语言编写时,gcc还会优化​​汇编代码,除非您使用volatile关键字进行更改。
最安全的方法是禁用优化。
当然,这只适用于您自己编写的部分代码。
如果您不优化所有代码,您会发现您的驱动程序根本无法加载。
这是因为编译驱动时使用了gcc的一些扩展,而这些扩展只有在你添加优化选项后才会体现出来。
背面写着:学习Linux当然不是一件容易的事。
因为它需要大量的努力和良好的C语言基础。
然而,Linux学习也很有趣,蕴含着很多高手、专家的智慧。
“幽默”,这都要自己去体会O(∩_∩)O~哈哈哈!