驱动程序 insmod无效问题解决

在使用Ubuntu系统时遇到内核版本更新导致无法正确安装驱动程序的问题,通过检查并修改Makefile文件中的内核版本定义,成功解决了insmod命令提示的Invalid module format错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

奇了怪的,不知道怎么更新ubuntu  内核版本竟然变了,然后今天将驱动程序插入内核是提示错误:insmod: error inserting 'test.ko': -1 Invalid module format

  最后还是网上资源丰富,感谢那些无私奉献的前辈们。

 原因是这样的,Makefile中编译的内核版本是:KERNELDIR := /usr/src/linux-headers-2.6.38-8-generic,而在/usr/src目录下竟然变成了:

然后:uname  -r:

 

这样就不能怪insmod -f 时出错了,只好将Makefile 中的版本由8 改成16 即可

<think>我们之前讨论了底层驱动的基本概念和作用,现在用户希望编写一个底层驱动程序的实例。根据用户提供的引用,特别是引用[1]中树莓派底层驱动开发的示例,我们可以设计一个简单的树莓派GPIO驱动示例。同时,用户要求参考之前的回答,因此我们将结合嵌入式系统中常见的GPIO控制来展示。 注意:编写底层驱动需要针对特定硬件平台和操作系统。这里以树莓派(Linux系统)为例,编写一个简单的字符设备驱动,用于控制一个GPIO引脚(例如GPIO4)的高低电平。 ### 步骤1:理解驱动框架 在Linux中,字符设备驱动通常包括以下部分: - **初始化函数**:注册设备,初始化硬件(如配置GPIO方向)。 - **文件操作结构体**:实现open、read、write、release等系统调用的回调函数。 - **注销函数**:卸载驱动时释放资源。 ### 步骤2:编写驱动代码 以下是一个简化的树莓派GPIO驱动示例(以GPIO4为例): ```c #include <linux/module.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/gpio.h> #define DEVICE_NAME "pin4_module" #define GPIO_PIN 4 static int major; static struct class *pin4_class; static struct device *pin4_device; // 文件操作函数:写操作(设置电平) static ssize_t pin4_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { char val; if (copy_from_user(&val, buf, 1)) // 从用户空间复制数据 return -EFAULT; if (val == '0') { gpio_set_value(GPIO_PIN, 0); // 设置低电平 } else if (val == '1') { gpio_set_value(GPIO_PIN, 1); // 设置高电平 } else { return -EINVAL; } return 1; } // 文件操作结构体 static struct file_operations pin4_fops = { .owner = THIS_MODULE, .write = pin4_write, }; // 驱动初始化 static int __init pin4_init(void) { // 注册字符设备 major = register_chrdev(0, DEVICE_NAME, &pin4_fops); if (major < 0) { printk(KERN_ALERT "Register char device failed!\n"); return major; } // 创建设备节点(在/dev目录下) pin4_class = class_create(THIS_MODULE, "pin4_class"); if (IS_ERR(pin4_class)) { unregister_chrdev(major, DEVICE_NAME); return PTR_ERR(pin4_class); } pin4_device = device_create(pin4_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); if (IS_ERR(pin4_device)) { class_destroy(pin4_class); unregister_chrdev(major, DEVICE_NAME); return PTR_ERR(pin4_device); } // 初始化GPIO if (gpio_request(GPIO_PIN, "pin4_module")) { printk(KERN_ALERT "GPIO request failed!\n"); device_destroy(pin4_class, MKDEV(major, 0)); class_destroy(pin4_class); unregister_chrdev(major, DEVICE_NAME); return -1; } gpio_direction_output(GPIO_PIN, 0); // 设置为输出模式,初始低电平 printk(KERN_INFO "Pin4 module initialized\n"); return 0; } // 驱动退出 static void __exit pin4_exit(void) { gpio_set_value(GPIO_PIN, 0); gpio_free(GPIO_PIN); device_destroy(pin4_class, MKDEV(major, 0)); class_destroy(pin4_class); unregister_chrdev(major, DEVICE_NAME); printk(KERN_INFO "Pin4 module unloaded\n"); } module_init(pin4_init); module_exit(pin4_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); ``` ### 步骤3:编写测试程序(用户空间) 用户空间的测试程序(如引用[1]所示)通过操作设备文件`/dev/pin4_module`来控制GPIO: ```c #include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { int fd = open("/dev/pin4_module", O_RDWR); if (fd < 0) { perror("open"); return -1; } while (1) { char cmd; printf("高电平输入1,低电平输入0\n"); scanf(" %c", &cmd); // 注意空格跳过空白字符 if (write(fd, &cmd, 1) < 0) { perror("write"); break; } } close(fd); return 0; } ``` ### 步骤4:编译与加载驱动 1. **编译驱动**:编写Makefile,使用内核头文件编译驱动模块(生成.ko文件)。 2. **加载驱动**: ```bash sudo insmod pin4_module.ko ``` 加载后,使用`dmesg`查看内核日志,确认驱动初始化成功,并检查`/dev/pin4_module`设备文件是否存在。 3. **运行测试程序**:编译并运行上述测试程序,输入1或0控制GPIO4的电平。 ### 注意事项 1. **权限问题**:确保测试程序有权限访问设备文件(通常需要root权限或修改设备文件权限)。 2. **硬件连接**:将树莓派的GPIO4引脚连接到LED等外设进行测试。 3. **错误处理**:实际驱动中应增加更完善的错误处理机制。 ### 总结 这个示例展示了如何编写一个简单的树莓派GPIO底层驱动。它实现了字符设备的基本框架,通过用户空间的write系统调用控制硬件状态。驱动开发需要深入理解硬件特性和操作系统内核机制,是嵌入式系统开发中的核心技能[^1]。 如果您需要更复杂的驱动功能(如中断处理、DMA传输等),可以进一步扩展此框架。 §§相关问题§§ 1. 如何为树莓派GPIO驱动添加中断处理功能? 2. Linux设备驱动中字符设备和块设备有什么区别? 3. 在编写底层驱动时,如何确保硬件的并发访问安全? 4. 如何调试Linux内核模块(如驱动程序)?</think>### 树莓派GPIO底层驱动开发示例 下面以树莓派GPIO控制为例,展示一个完整的底层驱动开发流程。该驱动实现了对GPIO4引脚的读写控制,包含内核模块代码和用户空间测试程序。 --- #### 1. **驱动模块代码(内核空间)** ```c #include <linux/module.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/gpio.h> #define DEVICE_NAME "pin4_module" #define GPIO_PIN 4 // 使用GPIO4引脚 static int major; static struct class *pin4_class; static struct device *pin4_device; static int gpio_status = 0; // 当前GPIO状态 // 文件操作:写函数(设置GPIO电平) static ssize_t pin4_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { char val; if (copy_from_user(&val, buf, 1)) return -EFAULT; if (val == '0') { gpio_set_value(GPIO_PIN, 0); // 设置低电平 gpio_status = 0; } else if (val == '1') { gpio_set_value(GPIO_PIN, 1); // 设置高电平 gpio_status = 1; } else { return -EINVAL; // 无效输入 } return 1; } // 文件操作:读函数(获取GPIO状态) static ssize_t pin4_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { char status_str[2]; snprintf(status_str, sizeof(status_str), "%d", gpio_status); if (copy_to_user(buf, status_str, 1)) return -EFAULT; return 1; } // 文件操作结构体 static struct file_operations pin4_fops = { .owner = THIS_MODULE, .write = pin4_write, .read = pin4_read, }; // 模块初始化 static int __init pin4_init(void) { // 1. 注册字符设备 major = register_chrdev(0, DEVICE_NAME, &pin4_fops); if (major < 0) { printk(KERN_ALERT "Register char device failed!\n"); return major; } // 2. 创建设备节点 pin4_class = class_create(THIS_MODULE, "pin4_class"); pin4_device = device_create(pin4_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); // 3. 初始化GPIO if (gpio_request(GPIO_PIN, "pin4_module")) { printk(KERN_ALERT "GPIO request failed!\n"); return -1; } gpio_direction_output(GPIO_PIN, 0); // 设置为输出模式 printk(KERN_INFO "Pin4 module initialized\n"); return 0; } // 模块退出 static void __exit pin4_exit(void) { gpio_set_value(GPIO_PIN, 0); // 复位GPIO gpio_free(GPIO_PIN); // 释放GPIO资源 device_destroy(pin4_class, MKDEV(major, 0)); class_destroy(pin4_class); unregister_chrdev(major, DEVICE_NAME); printk(KERN_INFO "Pin4 module unloaded\n"); } module_init(pin4_init); module_exit(pin4_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("YourName"); ``` --- #### 2. **用户空间测试程序** ```c #include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { int fd = open("/dev/pin4_module", O_RDWR); if (fd < 0) { perror("Device open failed"); return -1; } char cmd; char status; while(1) { printf("输入命令: 1(高电平), 0(低电平), r(读取状态), q(退出)\n"); scanf(" %c", &cmd); // 注意空格跳过空白符 if (cmd == 'q') break; if (cmd == 'r') { read(fd, &status, 1); printf("当前GPIO状态: %c\n", status); } else { write(fd, &cmd, 1); } } close(fd); return 0; } ``` --- #### 3. **编译与使用步骤** 1. **编译驱动模块**(需内核头文件): ```makefile obj-m := pin4_driver.o KDIR := /lib/modules/$(shell uname -r)/build all: make -C $(KDIR) M=$(PWD) modules ``` 执行 `make` 生成 `.ko` 内核模块 2. **加载驱动**: ```bash sudo insmod pin4_driver.ko # 加载模块 sudo mknod /dev/pin4_module c 250 0 # 创建设备节点 sudo chmod 666 /dev/pin4_module # 设置权限 ``` 3. **编译测试程序**: ```bash gcc test_pin4.c -o pin4_test ``` 4. **运行测试**: ```bash sudo ./pin4_test ``` --- #### 4. **关键机制说明** 1. **硬件交互**:通过`gpio_set_value()`直接操作硬件寄存器[^1] 2. **用户-内核通信**: - `copy_from_user()` 安全传递用户数据 - `copy_to_user()` 返回结果到用户空间 3. **设备抽象**: - 通过 `/dev/pin4_module` 文件接口提供控制 - 统一封装硬件操作细节[^1][^2] 4. **资源管理**: - `gpio_request()` 申请硬件资源 - `gpio_free()` 释放资源防止泄漏[^3] > **注意**:实际开发需考虑并发控制(如自旋锁)、错误处理等增强稳定性[^3]。 --- ### 其他底层驱动示例场景 1. **中断处理驱动**(参考引用[3]): ```c // 注册中断处理函数 request_irq(IRQ_NUM, irq_handler, IRQF_SHARED, "example", dev); ``` 2. **CUDA底层驱动**(参考引用[2]): ```cpp cuModuleLoad(&module, "kernel.ptx"); // 直接加载PTX汇编 cuLaunchKernel(module, ...); // 底层内核启动 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值