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)

  • 功能:解除映射
相关推荐
YaBingSec1 小时前
玄机网络安全靶场:Jackson-databind 反序列化漏洞(CVE-2017-7525)
linux·网络·笔记·安全·web安全
计算机安禾1 小时前
【Linux从入门到精通】第30篇:综合案例:编写一个Linux系统体检脚本
linux·运维·服务器
海的预约1 小时前
Bootloader应用分析
linux·运维·服务器
时空未宇1 小时前
海鸥派顺利运行YOLO11S
linux·运维·服务器
ElevenS_it1881 小时前
日志在哪里找?分布式环境下日志采集断裂的5个排查路径
运维·网络·分布式
半壶清水1 小时前
ubuntu中部署开源交换机模拟器bmv2详细步骤
linux·运维·网络·网络协议·tcp/ip·ubuntu
j_xxx404_2 小时前
Linux:深入解析ELF文件结构
linux·运维·服务器
2601_949695592 小时前
开源AI智能体OpenClaw接入DeepSeek V4全流程:从配置到成本
人工智能·驱动开发·ai·电脑
互联网推荐官2 小时前
上海软件定制开发与数字化建设:D-coding 全平台应用架构及实施指南
大数据·运维