Linux驱动开发(2)——驱动编程

1.内核输出接口

Linux 内核日志划分1~7 优先级等级,只有日志自身优先级数值低于console_loglevel(控制台日志等级阈值)时,内核打印信息才会输出到串口终端。

printk: 内核最基础的打印接口,默认使用 4 级日志优先级。

**pr 函数族:**带日志等级分类的标准化打印接口,不同函数绑定固定优先级。

  • **pr_info():**固定为6 级普通提示日志,多用于打印设备初始化、驱动加载、状态提示等常规非关键信息。

2.设备驱动

驱动方式:字符设备驱动、块设备驱动、网络设备驱动

2.1设备号:主设备号+次设备号

  • 主设备号:表示设备类型
  • 次设备号:该类型的第几个设备

2.2 自定义设备:cdev结构设备

cdev结构:设备号+对设备操作的方法

cs 复制代码
struct cdev{
    struct module *owner;//引用计数,计数使用cdev的设备个数
    const struct file_operations *ops;//对设备操作的方法
    dev_t dev;//该类型中第一个设备号
}
1).自定义设备

函数 :struct cdev *cdev_alloc(void);

  • 功能:申请cdev结构
  • 返回值:cdev结构体

函数 :int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);

  • 功能:申请设备号(内核自动分配主设备号)
  • 参数:@dev --- 自动分配的主设备号,@baseminor --- 次设备号始编号0,@count --- 申请个数,@name --- 设备类型名称

函数 :int cdev_add(struct cdev *p, dev_t dev, unsigned count);

  • 功能:加入到cdev链表中
  • 参数:@p --- cdev结构体,@dev --- 主设备号,@count --- 次设备个数

函数class_create(owner, name);

  • 功能:创建设备类型对应的文件系统目录
  • 参数:@owner --- 引入计数,@name --- 设备类型名

函数 :struct device *device_create(struct class *class,struct device *parent,dev_t devt,void *drvdata,const char *fmt,...);

  • 功能:创建类型对应的设备
  • 参数:@class --- 设备所属的类,@parent --- 父设备,@devt --- 设备号,@@fmt --- 带格式的设备名
函数 功能
cdev_del(struct cdev *p) 释放cdev结构体
unregister_chrdev_region(dev_t from, unsigned count); 释放设备号
class_destroy(struct class *cls); 销毁设备类
device_destroy(struct class *class, dev_t devt); 销毁设备
2).自定义设备类型的操作方法
cs 复制代码
static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = open,
    .release = close,
    .read = read,
    .write = write,
};
//内核层对应接口
int (*open)(struct inode*,struct file*);
int (*close)(struct inode*,struct file*);
ssize_t (*read)(struct file*,char __user*, size_t, loft_t*);
ssize_t (*write)(struct file*,char __user*, size_t, loft_t*);

函数 :unsigner long copy_from_user(void *to,const void __user *from,unsigned long n);

  • 功能:内核层从用户层拷贝数据(write)
  • 参数:@to --- 内核层数据的缓存区,from --- 用户层,@n --- 数据长度

函数 :unsigner long copy_to_user(void *to,const void __user *from,unsigned long n);

  • 功能:用户层从内核层拷贝数据(read)
  • 参数:@to --- 用户层,from --- 内核层数据,@n --- 数据长度

2.3 MMU内存映射

函数 :void __iomem *ioremap(phys_addr_t offset, size_t size);

  • 功能:虚拟地址和实际物理地址的映射
  • 参数:@offset --- 实际的寄存器地址,@size --- 地址大小(4byte)

函数 : void writel(u32 b, volatile void __iomem *addr)

  • 功能:Linux 内核读取寄存器
  • 参数:@b --- 要写入的值,@addr --- 虚拟地址

函数 :u32 readl(const volatile void __iomem *addr)

  • 功能:Linux 内核写入寄存器,readl用于32位寄存器

函数 :void iounmap(const void __iomem *addr)

  • 功能:解除映射
相关推荐
风度前端几秒前
阿里云宝塔面板部署https证书
linux·后端·https
Yeats_Liao2 分钟前
物联网接入层技术剖析(二):epoll到底是怎么工作的
java·linux·网络·物联网·信息与通信
Donk_6710 分钟前
什么是虚拟化
linux·运维
Shadow(⊙o⊙)11 分钟前
Shell进程替换,自定义Shell解释器——字符串库函数灵活操作!
linux·运维·服务器·开发语言·c++·学习
IT大白鼠12 分钟前
2019年Cloudflare全球宕机事件技术分析:正则表达式回溯失控与互联网基础设施脆弱性研究
运维·正则表达式·去中心化
funnycoffee12312 分钟前
华为S5736交换机3层ECMP负载方式
linux·服务器·数据库
SparkleN.26 分钟前
/tmp/cargo/env:No such file or directory
运维·服务器
rockmelodies33 分钟前
CentOS Stream 源码编译安装 Nginx 1.31.0(静态依赖版)
运维·chrome·nginx
2401_853087881 小时前
打破文档孤岛:将知识库深度融入DevOps流水线
运维·人工智能·devops
叶半欲缺1 小时前
Linux初始化数据盘
java·linux·服务器