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)

  • 功能:解除映射
相关推荐
U-Mail邮件系统4 小时前
自建邮箱服务器有哪些软件?三款主流邮件服务器软件推荐
运维·服务器
倒头就睡的小比特6 小时前
Linux基础指令3
linux·服务器
天远数科6 小时前
零信任架构实战:基于天远贷前风险报告构建自动化消金信贷风控与多头共债排查网关
运维·人工智能·架构·自动化
梦帮科技6 小时前
Kali Linux Scapy 畸形报文构造学——深度解剖非法 TCP Flags 与反常序列号
linux·爬虫·神经网络·算法·数学建模·系统架构·模拟退火算法
盛世宏博智慧档案6 小时前
智慧档案平台驱动开发实战:恒湿消毒净化一体机 Modbus-RTU 协议解析
驱动开发·恒湿机
半杯咖啡半行码7 小时前
Linux 驱动开发入门:内核模块编程基础
linux·服务器·网络
Herbert_hwt7 小时前
OpenSpec 实战演练:从“猜数字”到“暗黑模式”的规范驱动开发之旅
驱动开发
别动我齐刘海7 小时前
Linux 系统调试学习2
linux·运维·c++·人工智能·学习·机器学习·机器人
龙虾电话7 小时前
语音机器人打断不进去:VAD 双阈值迟滞里一个共用的 bool,和它引发的连锁误判
linux
honsor7 小时前
机房IP化改造首选:以太网温湿度传感器,PoE供电+Modbus TCP一网搞定
linux·运维·服务器