需要一定的努力才可以学好:
Linux设备驱动是linux内核的一部分,是用来屏蔽硬件细节,为上层提供标准接口的一种技术手段。为了能够编写出质量比较高的驱动程序,要求工程师必须具备以下几个方面的知识:
1、 熟悉处理器的性能
如:处理器的体系结构、汇编语言、工作模式、异常处理等。对于初学者来说,在还不熟悉驱动编写方法的情况下,可以先不把重心放在这一项上,因为可能因为它的枯燥、抽象而影响到你对设备驱动的兴趣。随着你不断地熟悉驱动的编写,你会很自然的意识到此项的重要性。
2、掌握驱动目标的硬件工作原理及通讯协议
如:串口控制器、显卡控制器、硬件编解码、存储卡控制器、I2C通讯、SPI通讯、USB通讯、SDIO通讯、I2S通讯、PCI通讯等。编写设备驱动的前提就是需要了解设备的 *** 作方法,所以这些内容的重要程度不言而喻。但不是说要把所有设备的 *** 作方法都熟悉了以后才可以写驱动,你只需要了解你要驱动的硬件就可以了。
一、掌握硬件的控制方法
如:中断、轮询、DMA 等,通常一个硬件控制器会有多种控制方法,你需要根据系统性能的需要合理的选择 *** 作方法。初学阶段以实现功能为目的,掌握的顺序应该是,轮询->中断->DMA。随着学习的深入,需要综合考虑系统的性能需求,采取合适的方法。
二、良好的GNU C语言编程基础
如:C语言的指针、结构体、内存 *** 作、链表、队列、栈、C和汇编混合编程等。这些编程语法是编写设备驱动的基础,无论对于初学者还是有经验者都非常重要。
三、 良好的linux *** 作系统概念
如:多进程、多线程、进程调度、进程抢占、进程上下文、虚拟内存、原子 *** 作、阻塞、睡眠、同步等概念及它们之间的关系。这些概念及方法在设备驱动里的使用是linux设备驱动区别单片机编程的最大特点,只有理解了它们才会编写出高质量的驱动。
四、掌握linux内核中设备驱动的编写接口
如:字符设备的cdev、块设备的gendisk、网络设备的net_device,以及基于这些基本接口的framebuffer设备的fb_info、mtd设备的mtd_info、tty设备的tty_driver、usb设备的usb_driver、mmc设备的mmc_host等。
linux的驱动一般有两种格式,分别为:tar和rpm格式。rpm安装步骤:
1.将驱动程序文件bcm5700-srcrpm复制到一个临时目录中,并在此目录中运行以下命令:
rpm –ivh bcm5700-srcrpm
2.运行以下命令切换到驱动目录中:
cd /usr/src/redhat/SPECS/
3.此目录中会生成一个名字为bcm5700spec的文件,运行以下命令对驱动程序进行编译:
rpmbuild –bb bcm5700spec (对4xx版本的RPM适用)或 rpm -bb bcm5700spec
4.运行以下命令切换到RPM目录中:
cd /usr/src/redhat/RPMS/i386/
5.运行以下命令安装驱动程序:
rpm –ivh bcm5700-i386rpm (对于Red Hat 72, 73, 21AS和其他包含老版本驱动的系统需要使用--force的参数,强制用新的驱动替换系统自带的老版本驱动)
6.运行以下命令加载驱动模块:
insmod bcm5700
7.运行kudzu命令,系统会自动搜索到硬件,进行配置即可。
或者重新启动系统,启动过程中系统会自动找到硬件,进行相应配置即可。
tar格式安装步骤:
1 将驱动程序压缩文件bcm5700-targz复制到一个临时目录中,并使用以下命令解压缩:
tar xvzf bcm5700-targz
2.构建驱动程序为运行内核可加载模块
cd bcm5700-/src
make
3.加载测试
insmod bcm5700
4.加载驱动程序
make install
5.重新启动系统,启动过程中找到硬件,进行相应配置。
或者直接运行kudzu命令,系统会自动搜索到硬件,进行配置即可。
一、Linux device driver 的概念\x0d\\x0d\系统调用是 *** 作系统内核和应用程序之间的接口,设备驱动程序是 *** 作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象 *** 作普通文件一样对硬件设备进行 *** 作。设备驱动程序是内核的一部分,它完成以下的功能:\x0d\\x0d\1、对设备初始化和释放;\x0d\\x0d\2、把数据从内核传送到硬件和从硬件读取数据;\x0d\\x0d\3、读取应用程序传送给设备文件的数据和回送应用程序请求的数据;\x0d\\x0d\4、检测和处理设备出现的错误。\x0d\\x0d\在Linux *** 作系统下有三类主要的设备文件类型,一是字符设备,二是块设备,三是网络设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O *** 作。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。\x0d\\x0d\已经提到,用户进程是通过设备文件来与实际的硬件打交道。每个设备文件都都有其文件属性(c/b),表示是字符设备还是块设备另外每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们。设备文件的的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序。\x0d\\x0d\最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度。也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他的工作。如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就是漫长的fsck。\x0d\\x0d\二、实例剖析\x0d\\x0d\我们来写一个最简单的字符设备驱动程序。虽然它什么也不做,但是通过它可以了解Linux的设备驱动程序的工作原理。把下面的C代码输入机器,你就会获得一个真正的设备驱动程序。\x0d\\x0d\由于用户进程是通过设备文件同硬件打交道,对设备文件的 *** 作方式不外乎就是一些系统调用,如 open,read,write,close, 注意,不是fopen, fread,但是如何把系统调用和驱动程序关联起来呢这需要了解一个非常关键的数据结构:\x0d\\x0d\STruct file_operatiONs {\x0d\\x0d\int (seek) (struct inode ,struct file , off_t ,int);\x0d\\x0d\int (read) (struct inode ,struct file , char ,int);\x0d\\x0d\int (write) (struct inode ,struct file , off_t ,int);\x0d\\x0d\int (readdir) (struct inode ,struct file , struct dirent ,int);\x0d\\x0d\int (select) (struct inode ,struct file , int ,select_table );\x0d\\x0d\int (ioctl) (struct inode ,struct file , unsined int ,unsigned long);\x0d\\x0d\int (mmap) (struct inode ,struct file , struct vm_area_struct );\x0d\\x0d\int (open) (struct inode ,struct file );\x0d\\x0d\int (release) (struct inode ,struct file );\x0d\\x0d\int (fsync) (struct inode ,struct file );\x0d\\x0d\int (fasync) (struct inode ,struct file ,int);\x0d\\x0d\int (check_media_change) (struct inode ,struct file );\x0d\\x0d\int (revalidate) (dev_t dev);\x0d\\x0d\}\x0d\\x0d\这个结构的每一个成员的名字都对应着一个系统调用。用户进程利用系统调用在对设备文件进行诸如read/write *** 作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数。这是linux的设备驱动程序工作的基本原理。既然是这样,则编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域。\x0d\\x0d\下面就开始写子程序。\x0d\\x0d\#include 基本的类型定义\x0d\\x0d\#include 文件系统使用相关的头文件\x0d\\x0d\#include \x0d\\x0d\#include \x0d\\x0d\#include \x0d\\x0d\unsigned int test_major = 0;\x0d\\x0d\static int read_test(struct inode inode,struct file file,char buf,int count)\x0d\\x0d\{\x0d\\x0d\int left; 用户空间和内核空间\x0d\\x0d\if (verify_area(VERIFY_WRITE,buf,count) == -EFAULT )\x0d\\x0d\return -EFAULT;\x0d\\x0d\for(left = count ; left > 0 ; left--)\x0d\\x0d\{\x0d\\x0d\__put_user(1,buf,1);\x0d\\x0d\buf++;\x0d\\x0d\}\x0d\\x0d\return count;\x0d\\x0d\}\x0d\\x0d\这个函数是为read调用准备的。当调用read时,read_test()被调用,它把用户的缓冲区全部写1。buf 是read调用的一个参数。它是用户进程空间的一个地址。但是在read_test被调用时,系统进入核心态。所以不能使用buf这个地址,必须用__put_user(),这是kernel提供的一个函数,用于向用户传送数据。另外还有很多类似功能的函数。请参考,在向用户空间拷贝数据之前,必须验证buf是否可用。这就用到函数verify_area。为了验证BUF是否可以用。\x0d\\x0d\static int write_test(struct inode inode,struct file file,const char buf,int count)\x0d\\x0d\{\x0d\\x0d\return count;\x0d\\x0d\}\x0d\\x0d\static int open_test(struct inode inode,struct file file )\x0d\\x0d\{\x0d\\x0d\MOD_INC_USE_COUNT; 模块计数加以,表示当前内核有个设备加载内核当中去\x0d\\x0d\return 0;\x0d\\x0d\}\x0d\\x0d\static void release_test(struct inode inode,struct file file )\x0d\\x0d\{\x0d\\x0d\MOD_DEC_USE_COUNT;\x0d\\x0d\}\x0d\\x0d\这几个函数都是空 *** 作。实际调用发生时什么也不做,他们仅仅为下面的结构提供函数指针。\x0d\\x0d\struct file_operations test_fops = {\x0d\\x0d\read_test,\x0d\\x0d\write_test,\x0d\\x0d\open_test,\x0d\\x0d\release_test,\x0d\\x0d\};\x0d\\x0d\设备驱动程序的主体可以说是写好了。现在要把驱动程序嵌入内核。驱动程序可以按照两种方式编译。一种是编译进kernel,另一种是编译成模块(modules),如果编译进内核的话,会增加内核的大小,还要改动内核的源文件,而且不能动态的卸载,不利于调试,所以推荐使用模块方式。\x0d\\x0d\int init_module(void)\x0d\\x0d\{\x0d\\x0d\int result;\x0d\\x0d\result = register_chrdev(0, "test", &test_fops); 对设备 *** 作的整个接口\x0d\\x0d\if (result \x0d\\x0d\#include \x0d\\x0d\#include \x0d\\x0d\#include \x0d\\x0d\main()\x0d\\x0d\{\x0d\\x0d\int testdev;\x0d\\x0d\int i;\x0d\\x0d\char buf[10];\x0d\\x0d\testdev = open("/dev/test",O_RDWR);\x0d\\x0d\if ( testdev == -1 )\x0d\\x0d\{\x0d\\x0d\printf("Cann't open file \n");\x0d\\x0d\exit(0);\x0d\\x0d\}\x0d\\x0d\read(testdev,buf,10);\x0d\\x0d\for (i = 0; i 回答于 2022-11-18
你至少要先学习Linux的应用程序,然后再学习驱动程序才好,不会用驱动也不会写好。
1、不需要去掉所有的驱动,你把你要写的编译成module就可以了,当然必须要让kernel支持module。当然module的写法自己慢慢琢磨吧。
2、Linux工程师是一个庞大队伍通称,就好像计算机工程师做什么一样,不好回答。仅我接触的一个Linux为主的项目就有10万人参与,代码编写几年,这么大的团队,你常见的计算机类的职业都有了。
3、每一个设备,小到中断控制器、计数器、定时器,大到CPU(体系结构)驱动、甚至虚拟文件系统(不是VFS,主要是类似集群文件系统,但是毫无疑问文件系统驱动也都比较庞大)等。
下载 virtualbox 下载一个 linux iso
用virtualbox 建立虚拟系统 配置好 加载iso 启动安装
VMware安装完毕后,利用它可以建立多个虚拟机,每新建一个虚拟机,就会要求你建立一个配置文件。这个配置文件实际上相当于新电脑的“硬件配置”,你可以在配置文件中决定虚拟机的硬盘如何配置,内存多大.准备运行哪种 *** 作系统,是否有网络等。配置Linux虚拟机的步骤如下。
(1)选择File菜单下的“New Virtual Machine”出现新虚拟机向导后单击“下一步”,选择“Typical”典型安装。
(2)再单击“下一步”,在选择 *** 作系统界面的“Guest Operation System”中选择 “Linux”,然后单击Version对应的下拉菜单选择具体的Linux版本, 此处我们选择“Red Hat LinuX”。
(3)单击“下一步”进入安装目录选择界面。该界面上面的文本框是系统的名字,保持默认值即可,下面的文本框需要选择虚拟机 *** 作系统的安装位置。
(4)根据需要选择好后,单击“下一步”按钮,出现设置虚拟机内存大小的界面。Linux9.O对内存的要求是:文本模式至少需要64MB;图形化模式至少需要128MB,推荐使用192MB。此处我们选择192MB:
(5)单击“下一步”按钮进入网络连接方式选择界面。VMware有四种网络设置方式,一般来说,Bridged方式使虚拟机就像网络内一台独立的计算机一样,最为方便好用(四种连网方式的区别大家可参考VMware的有关资料)。在此、我们选择Brided方式。
(6)单击“下一步”按钮进入虚拟磁盘的设置界面。 这里有三种方式(Create a new virtual disk、Use an existing virtual disk、Use a physical disk)可供选择、建议初学者选择“Create a new Virtual disk”,其含义是新建一个虚拟磁盘,该虚拟磁盘只是主机—卜的一个独立文件。
(7)在“下一步”中设置磁盘大小。在此、我们采用默认的4GB。
(8)单击“下一步”进入文件存放路径选择界面。
在此界面可单击Browse按钮进行设置。此处我们使用默认值,单击“完成”按钮。
至此,完成一个虚拟机的配置。
linuxcamera驱动真的需要自己写吗
不一定需要自己写,因为Linux内核已经提供了许多常用摄像头驱动程序。但是,如果使用的相机型号没有现成的驱动程序,或者需要对现有驱动程序进行定制,那么可能需要编写自己的驱动程序。此外,如果要实现一些特定的功能或性能优化,也可能需要自己编写驱动程序。总之,是否需要编写自己的驱动程序取决于具体的情况。
Linux *** 作系统是用C语言、汇编语言编写的。
Linux(lɪnəks/ LIN-əks)是一种自由和开放源码的类UNIX *** 作系统。该 *** 作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布,在加上用户空间的应用程序之后,成为 Linux *** 作系统。Linux 也是自由软件和开放源代码软件发展中最著名的例子。
只要遵循 GNU 通用公共许可证(GPL),任何个人和机构都可以自由地使用 Linux 的所有底层源代码,也可以自由地修改和再发布。
扩展资料
Linux系统架构
基于Linux的系统是一个模块化的类Unix *** 作系统。Linux *** 作系统的大部分设计思想来源于20世纪70年代到80年代的Unix *** 作系统所创建的基本设计思想。
Linux具有设备独立性,它内核具有高度适应能力,从而给系统提供了更高级的功能。GNU用户界面组件是大多数Linux *** 作系统的重要组成部分,提供常用的C函数库,Shell,还有许多常见的Unix实用工具,可以完成许多基本的 *** 作系统任务。
Linux系统使用宏内核,由Linux内核负责处理进程控制、网络,以及外围设备和文件系统的访问。在系统运行的时候,设备驱动程序要么与内核直接集成,要么以加载模块形式添加。
大多数Linux系统使用的图形用户界面创建在X窗口系统之上,由X窗口(XWindow)系统通过软件工具及架构协议来创建 *** 作系统所用的图形用户界面。
参考资料来源:百度百科—linux
在学习之前一直对驱动开发非常的陌生,感觉有点神秘。不知道驱动开发和普通的程序开发究竟有什么不同;它的基本框架又是什么样的;他的开发环境有什么特殊的地方;以及怎么写编写一个简单的字符设备驱动前编译加载,下面我就对这些问题一个一个的介绍。
一、驱动的基本框架
1. 那么究竟什么是驱动程序,它有什么用呢:
l 驱动是硬件设备与应用程序之间的一个中间软件层
l 它使得某个特定硬件能够响应一个定义良好的内部编程接口,同时完全隐蔽了设备的工作细节
l 用户通过一组与具体设备无关的标准化的调用来完成相应的 *** 作
l 驱动程序的任务就是把这些标准化的系统调用映射到具体设备对于实际硬件的特定 *** 作上
l 驱动程序是内核的一部分,可以使用中断、DMA等 *** 作
l 驱动程序在用户态和内核态之间传递数据
2. Linux驱动的基本框架
3. Linux下设备驱动程序的一般可以分为以下三类
1) 字符设备
a) 所有能够象字节流一样访问的设备都通过字符设备来实现
b) 它们被映射为文件系统中的节点,通常在/dev/目录下面
c) 一般要包含open read write close等系统调用的实现
2) 块设备
d) 通常是指诸如磁盘、内存、Flash等可以容纳文件系统的存储设备。
e) 块设备也是通过文件系统来访问,与字符设备的区别是:内核管理数据的方式不同
f) 它允许象字符设备一样以字节流的方式来访问,也可一次传递任意多的字节。
3) 网络接口设备
g) 通常它指的是硬件设备,但有时也可能是一个软件设备(如回环接口loopback),它们由内核中网络子系统驱动,负责发送和接收数据包。
h) 它们的数据传送往往不是面向流的,因此很难将它们映射到一个文件系统的节点上。
二、怎么搭建一个驱动的开发环境
因为驱动是要编译进内核,在启动内核时就会驱动此硬件设备;或者编译生成一个o文件, 当应用程序需要时再动态加载进内核空间运行。因此编译任何一个驱动程序都要链接到内核的源码树。所以搭建环境的第一步当然是建内核源码树
1 怎么建内核源码树
a) 首先看你的系统有没有源码树,在你的/lib/ modules目录下会有内核信息,比如我当前的系统里有两个版本:
#ls /lib/ modules
2615-rc7 2621-13194fc7
查看其源码位置:
## ll /lib/modules/2615-rc7/build
lrwxrwxrwx 1 root root 27 2008-04-28 19:19 /lib/modules/2615-rc7/build -> /root/xkli/linux-2615-rc7
发现build是一个链接文件,其所对应的目录就是源码树的目录。但现在这里目标目录已经是无效的了。所以得自己重新下载
b)下载并编译源码树
有很多网站上可以下载,但官方网址是:
>
下载完后当然就是解压编译了
# tar –xzvf linux-261654targz
#cd linux-261654
## make menuconfig (配置内核各选项,如果没有配置就无法下一步编译,这里可以不要改任何东西)
#make
…
如果编译没有出错。那么恭喜你。你的开发环境已经搭建好了
三、了解驱动的基本知识
1 设备号
1) 什么是设备号呢?我们进系统根据现有的设备来讲解就清楚了:
#ls -l /dev/
crwxrwxrwx 1 root root 1, 3 2009-05-11 16:36 null
crw------- 1 root root 4, 0 2009-05-11 16:35 systty
crw-rw-rw- 1 root tty 5, 0 2009-05-11 16:36 tty
crw-rw---- 1 root tty 4, 0 2009-05-11 16:35 tty0
在日期前面的两个数(如第一列就是1,3)就是表示的设备号,第一个是主设备号,第二个是从设备号
2) 设备号有什么用呢?
l 传统上, 主编号标识设备相连的驱动 例如, /dev/null 和 /dev/zero 都由驱动 1 来管理, 而虚拟控制台和串口终端都由驱动 4 管理
l 次编号被内核用来决定引用哪个设备 依据你的驱动是如何编写的自己区别
3) 设备号结构类型以及申请方式
l 在内核中, dev_t 类型(在 中定义)用来持有设备编号, 对于 260 内核, dev_t 是 32 位的量, 12 位用作主编号, 20 位用作次编号
l 能获得一个 dev_t 的主或者次编号方式:
MAJOR(dev_t dev); //主要
MINOR(dev_t dev);//次要
l 但是如果你有主次编号, 需要将其转换为一个 dev_t, 使用: MKDEV(int major, int minor);
4) 怎么在程序中分配和释放设备号
在建立一个字符驱动时需要做的第一件事是获取一个或多个设备编号来使用 可以达到此功能的函数有两个:
l 一个是你自己事先知道设备号的
register_chrdev_region, 在 中声明:
int register_chrdev_region(dev_t first, unsigned int count, char name);
first 是你要分配的起始设备编号 first 的次编号部分常常是 0,count 是你请求的连续设备编号的总数 name 是应当连接到这个编号范围的设备的名子; 它会出现在 /proc/devices 和 sysfs 中
l 第二个是动态动态分配设备编号
int alloc_chrdev_region(dev_t dev, unsigned int firstminor, unsigned int count, char name);
使用这个函数, dev 是一个只输出的参数, 它在函数成功完成时持有你的分配范围的第一个数 fisetminor 应当是请求的第一个要用的次编号; 它常常是 0 count 和 name 参数如同给 request_chrdev_region 的一样
5) 设备编号的释放使用
不管你是采用哪些方式分配的设备号。使用之后肯定是要释放的,其方式如下:
void unregister_chrdev_region(dev_t first, unsigned int count);
6)
2 驱动程序的二个最重要数据结构
1) file_operation
倒如字符设备scull的一般定义如下:
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,
};
file_operation也称为设备驱动程序接口
定义在 , 是一个函数指针的集合 每个打开文件(内部用一个 file 结构来代表)与它自身的函数集合相关连( 通过包含一个称为 f_op 的成员, 它指向一个 file_operations 结构) 这些 *** 作大部分负责实现系统调用, 因此, 命名为 open, read, 等等
2) File
定义位于include/fsh
struct file结构与驱动相关的成员
l mode_t f_mode 标识文件的读写权限
l loff_t f_pos 当前读写位置
l unsigned int_f_flag 文件标志,主要进行阻塞/非阻塞型 *** 作时检查
l struct file_operation f_op 文件 *** 作的结构指针
l void private_data 驱动程序一般将它指向已经分配的数据
l struct dentry f_dentry 文件对应的目录项结构
3 字符设备注册
1) 内核在内部使用类型 struct cdev 的结构来代表字符设备 在内核调用你的设备 *** 作前, 必须编写分配并注册一个或几个这些结构 有 2 种方法来分配和初始化一个这些结构
l 如果你想在运行时获得一个独立的 cdev 结构,可以这样使用:
struct cdev my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
l 如果想将 cdev 结构嵌入一个你自己的设备特定的结构; 你应当初始化你已经分配的结构, 使用:
void cdev_init(struct cdev cdev, struct file_operations fops);
2) 一旦 cdev 结构建立, 最后的步骤是把它告诉内核, 调用:
int cdev_add(struct cdev dev, dev_t num, unsigned int count);
说明:dev 是 cdev 结构, num 是这个设备响应的第一个设备号, count 是应当关联到设备的设备号的数目 常常 count 是 1, 但是有多个设备号对应于一个特定的设备的情形
3) 为从系统去除一个字符设备, 调用:
void cdev_del(struct cdev dev);
4 open 和 release
以上就是关于linux驱动开发要有哪些基础全部的内容,包括:linux驱动开发要有哪些基础、bcm94352z在Linux下要怎么驱动、linux驱动程序结构框架及工作原理分别是什么等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)