Linux - 驱动 之 字符设备

一.Linux设备驱动分类

1.1按管理的设备硬件来分
字符设备
按字节流访问,能够顺序访问,也能够指定位置访问。
 按键 串口 终端 触摸屏 LCD等 …

块设备
在Unix系统下,块设备按一定的数据块进行访问,数据块为512bytes 1K等。
 在Linux下,块设备既可以按数据块的方式访问,也可以安字节流访问。
 块设备和字符设备的区别在于linux系统中描述块设备和字符设备的数据结构和操作方法是不一样的 。

网络设备
网卡,网络设备一般要结合tcp/ip协议栈来实现。

二、字符设备驱动

1.驱动程序的作用:
1.管理对应的硬件。
2.给用户提供访问硬件的操作的方法(接口)。

2.应用程序如何访问硬件?
硬件设备在linux系统下,会以设备文件的形式存在,设备文件(字符和块)在/dev/
,那么应用程序要访问硬件其实就是访问对应的设备文件。

3.应用程序如何访问设备文件?
通过调用系统调用来实现对其的访问,访问设备文件和访问普通文件的方式是一样的
open read write ioctl mmap close…

4.应用程序如何通过设备文件在非常多的驱动中找到对应的硬件驱动?
设备文件本身包含一些属性:
 设备文件是字符设备文件©还是块设备文件(b)。
 设备文件还包括主设备号和次设备号这两个重要的属性。
 应用程序就是通过主设备号找到对应的驱动程序。
 一个驱动程序只有一个主设备号。

5.次设备号的作用?
次设备号用于找到具体要访问的设备个体。
 例如一台电脑有4个串口,4个串口共用一个主设备好,而次设备号就是区分4个串口之中的哪一个。

6.设备号:同时包含了主设备号和次设备号,它的数据类型为:dev_t(unsigned int)

typedef __kernel_dev_t  dev_t;
typedef __u32 __ kernel_dev_t;
typedef unsigned int __u32;

而设备号的: 高12位保存着主设备的值;
      低20位保存着次设备号的值。
在这里插入图片描述

7.设备号操作宏:

设备号 = MKDEV(已知的主设备号,已知的次设备号)
主设备号 = MAJOR(已知的设备号)
次设备号 = MINOR(已知的设备号)

#define MINORBITS	20
#define MINORMASK	((1U << MINORBITS) - 1)

#define MAJOR(dev)	((unsigned int) ((dev) >> MINORBITS))  //主设备号 
#define MINOR(dev)	((unsigned int) ((dev) & MINORMASK))   //次设备号
#define MKDEV(ma,mi)	(((ma) << MINORBITS) | (mi))      //主设备号 + 次设备号

8.如何向内核申请设备号?

 设备号是属于系统资源,如果要实现驱动和设备号的绑定,首先必须向内核申请设备号资源,只有完成申请之后,才能和驱动程序绑定。

静态分配和动态分配(一般使用动态比较方便)

静态指定分配设备号:
 1>在开发板查看哪些主设备号已经被使用:命令 cat /proc/devices

 2>然后根据你的设备个数分配次设备号,一般次设备号都从0开始
  dev_t dev = MKDEV(主设备号,次设备号);

 3>调用register_chrdev_region;向内核申请

 注:主设备号不能为0

静态申请函数:
int register_chrdev_region(dev_t from, unsigned count, const char *name);
from:待申请的设备号
count:待申请的设备号数目
name:设备名称(出现在/proc/devices)
返回:成功返回0,失败返回负值。

例子:向内核申请从from开始的count个设备号(数设备号不变,次设备号增加):

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>

MODULE_LICENSE("GPL");
#define  CDD_MAJOR	200//cat /proc/devices  找一个尚未使用的
#define  CDD_MINOR	0
#define  CDD_COUNT	1
dev_t dev = 0;        //保存申请到的设备号

int __init cdd_init(void)
{
   
	int ret = 0;
	//dev = CDD_MAJOR<<20 + CDD_MINOR;
	dev = MKDEV(CDD_MAJOR, CDD_MINOR);//生成设备号
	//注册设备号;1、要注册的起始设备号  2、连续注册的设备号个数  3、名字
	ret = register_chrdev_region(dev, CDD_COUNT, "cdd_demo");
	if(ret < 0){
   
		printk("register_chrdev_region failed!\n");
		goto failure_register_chrdev;  //goto在内核中一般用来做错误处理
	}
	printk("register_chrdev_region successed! #cat /proc/devices\n");
	return 0;
failure_register_chrdev:
	return ret;
}

void __exit cdd_exit(void)
{
   
	//注销设备号
	unregister_chrdev_region(dev, CDD_COUNT);
}	

module_init(cdd_init);
module_exit(cdd_exit);

动态分配设备号
1>调用alloc_chrdev_region 直接向内核申请
2>释放设备号 unregister_chrdev_region

动态申请函数:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
baseminor: 次设备号的起始
count:     申请次设备号的个数
name :     执行 cat /proc/devices显示的名称
返回值:   小于0,则错误,自动分配设备号错误。否则分配得到的设备号就被第一个参数带出来。

释放设备号

void unregister_chrdev_region(dev_t from, unsigned count);
/* 参数:
    dev_t from - 要释放的第一个设备号(起始)
    unsigned count - 要释放的次设备号数量 */

三、Linux字符设备中的两个重要结构体(file、inode)

转载:https://www.cnblogs.com/chen-farsight/p/6177870.html

对于Linux系统中,一般字符设备和驱动之间的函数调用关系如下图所示
在这里插入图片描述

 上图描述了用户空间应用程序通过系统调用来调用程序的过程。一般而言在驱动程序的设计中,会关系 struct file 和 struct inode 这两个结构体。

 用户空间使用open()系统调用函数打开一个字符设备时( int fd = open(“dev/demo”, O_RDWR) )大致有以下过程:
1.在虚拟文件系统VFS中的查找对应与字符设备对应 struct inode节点。
2.遍历字符设备列表(chardevs数组),根据inod节点中的 cdev_t设备号找到cdev对象。
3.创建struct file对象(系统采用一个数组来管理一个进程中的多个被打开的设备,每个文件秒速符作为数组下标标识了一个设备对象)。
4.初始化struct file对象,将 struct file对象中的 file_operations成员指向 struct cdev对象中的 file_operations成员(file->fops = cdev->fops)。
5.回调file->fops->open函数。

3.1inode结构体
 VFS inode 包含文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间等信息。它是Linux 管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁。

 内核使用inode结构体在内核内部表示一个文件。因此,它与表示一个已经打开的文件描述符的结构体(即file 文件结构)是不同的,我们可以使用多个file 文件结构表示同一个文件的多个文件描述符,但此时,所有的这些file文件结构全部都必须只能指向一个inode结构体。

  inode结构体包含了一大堆文件相关的信息,但是就针对驱动代码来说,我们只要关心其中的两个域即可:
dev_t i_rdev: 表示设备文件的结点,这个域实际上包含了设备号。
 struct cdev *i_cdev: struct cdev是内核的一个内部结构,它是用来表示字符设备的,当inode结点指向一个字符设备文件时,此域为一个指向inode结构的指针。

下面是源代码:

struct inode 
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值