ubuntu下编译字符设备驱动遇到各种坑

一、这里博主用的是Ubuntu12.04版本、内核是2.6.35.
我简单写了个驱动程序,命名为charDev.c
这个代码是错误的,更改后的在最下面。

#include <linux/module.h>
#include <linux/moduleparam.h>
#indclude <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#define BUFFER_MAX (10)
#define OK (0)
#define ERROR (-1)

struct cdev *gDev;
struct file_operations *gFile;
dev_t devNum;
unsigned int subDevNum = 1;
int reg_major=232;
int reg_minor = 0;
char *buffer;
int flag = 0;
int testOpen(struct inode *p, struct file *f)
{
printk(KERN_EMERG" testOpen\r\n");
return 0;
 }
 25 ssize_t testWrite(struct file *f, const char __user *u,size_t s,loff_t *l)
 26 {
 27         printk(KERN_EMERG"testWrite\r\n");
 28         return 0;
 29 }
 30 ssize_t testRead(struct file *f, char __user *u, size_t s, loff_t *l)
 31 {
 32 printk(KERN_EMERG"testRead\r\n");
 33 return 0;
 34 }
 35 
 36 int charDrvInit(void)
 37 {
 38 devNum=MKDEV(reg_major,reg_minor);
 39 printk(KERN_EMERG"devNum is %d\r\n", devNum);
 40 if(OK == register_chrdev_region(devNum,subDevNum,"testchar"))
 41 {
 42 printk(KERN_EMERG"register_chrdev_region ok\r\n");
 43 }
 44 else
 45 {
 printk(KERN_EMERG"register_chrdev_region error\r\n");
 47 return ERROR;
 48 }
 49 
 50 printk(KERN_EMERG"devNum is %d\r\n", devNum);
 51 gDev = kzalloc(sizeof(struct cdev),GFP_KERNEL);
 52 gFile =kzalloc(sizeof(struct file_operations),GFP_KERNEL);
 53 
 54 gFile->open=testOpen;
 55 gFile->read=testRead;
 56 gFile->write=testWrite;
 57 gFile->owner=THIS_MODULE;
 58 cdev_init(gDev,gFile);
 59 cdev_add(gDev,devNum,3);
 60 return 0;
 61 }
 62 
 63 void __exit charDrvExit(void)
 64 {
 65         cdev_del(gDev);
 66         unregister_chrdev_region(devNum,subDevNum);
 67         return ;
}
 69 module_init(charDrvInit);
 70 module_exit(charDrvExit);
 71 MODULE_LICENSE("GPL");

二、编写Makefile文件(也是错误的,正确的在下面)

ifneq ($(KERNELRELEASE),)
obj-m := charDev.o
else
 PWD := $(shell pwd)
 KDIR := /lib/modules/‘uname -r’/build
 all:
        make -C $(KDIR) M=$(PWD)
 clean:
        rm -rf .*.cmd *.o *.ko *.mod.c *.symvers .tmp_versions *.c~ *~
 endif

三、这里就开始make了,也是各种报错的开始。
在这里插入图片描述从图片看出/lib/modules/uname -r/build这一行是出错的,在Makefile文件中,去修改:vi Makefile。
发现KDIR := /lib/modules/‘uname -r’/build这一句中需要根据自己内核的目录来更改‘uname -r’。
两种解决方案:
①命令行模式下uname -r 查看内核号,把查到的内核号替换掉‘uname -r’。
②$(shell uname –r)替换掉‘uname -r’。
再make。
在这里插入图片描述发现make结束虽然没有error,但是!这个make过程中并没有生成.ko和.mod.o等文件。
于是百度得知要么我的charDev.c有问题,要么就是我的Makefile有问题。总之一句话,代码没写对。找代码的错。
改过几次书写的错误后make后还是出错。
在这里插入图片描述发现原来kzalloc需要依赖#include <linux/slab.h>头文件。加上。

出错的地方细微,所以在写代码的时候一定要仔细认真。直接正确代码

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#define BUFFER_MAX (10)
#define OK (0)
#define ERROR (-1)

struct cdev *gDev;
struct file_operations *gFile;
dev_t devNum;
unsigned int subDevNum = 1;
int reg_major=232;
int reg_minor = 0;
char *buffer;
int flag = 0;
int testOpen(struct inode *p, struct file *f)
{
printk(KERN_EMERG" testOpen\r\n");
return 0;
}
ssize_t testWrite(struct file *f, const char __user *u,size_t s,loff_t *l)
{
        printk(KERN_EMERG"testWrite\r\n");
        return 0;
}
ssize_t testRead(struct file *f, char __user *u, size_t s,loff_t *l)
{
printk(KERN_EMERG"testRead\r\n");
return 0;
}

int charDrvInit(void)
{
devNum=MKDEV(reg_major,reg_minor);
printk(KERN_EMERG"devNum is %d\r\n", devNum);
if(OK == register_chrdev_region(devNum,subDevNum,"testchar"))
{
printk(KERN_EMERG"register_chrdev_region ok\r\n");
}
else
{
printk(KERN_EMERG"register_chrdev_region error\r\n");
return ERROR;
}

printk(KERN_EMERG"devNum is %d\r\n", devNum);
gDev = kzalloc(sizeof(struct cdev),GFP_KERNEL);
gFile =kzalloc(sizeof(struct file_operations),GFP_KERNEL);

gFile->open=testOpen;
gFile->read=testRead;
gFile->write=testWrite;
gFile->owner=THIS_MODULE;
cdev_init(gDev,gFile);
cdev_add(gDev,devNum,3);
return 0;
}

void __exit charDrvExit(void)
{
        cdev_del(gDev);
        unregister_chrdev_region(devNum,subDevNum);
        return ;
}
module_init(charDrvInit);
module_exit(charDrvExit);
MODULE_LICENSE("GPL");

make 还是同样的错误,改Makefile去掉错误的书写格式。
Makefile的书写格式是:依赖命令行的需要按下tab键,才能开始写,不依赖的可以tab也可以不tab,这也是Makefile规则是为了区分。比如:我的Makefile里的
all:
make -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD)
第二行就是需要先按tab键,不能是空格键!在Makefile里,要么按tab键要么别按,不能按空格。

ifneq ($(KERNELRELEASE),)
obj-m := charDev.o
else
PWD := $(shell pwd)
KDIR := /lib/modules/2.6.35/build
all:
        make -C $(KDIR) M=$(PWD)
clean:
        rm -rf .*.cmd *.o *.ko *.mod.c *.symvers .tmp_versions *.c~ *~
endif

这是修改正确后的Makefile文件。
四、这下再make就ok了。
在这里插入图片描述在这里插入图片描述五、清除dmesg信息:dmesg -c
insmod charDev.ko在这里插入图片描述打印出的三条信息是charDrvInit(初始化)函数里的。
也就验证了驱动初始化成功,也说明insmod 就会初始化程序。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
***于Linux操作系统的发行版,它支持各种硬件设备和驱动程序。字符设备驱动Linux内核中的一种设备驱动程序,用于管理字符设备,例如串口、打印机等。 要编写一个字符设备驱动程序,你需要了解Linux内核模块编程和字符设备接口。以下是一个简单的示例来演示如何编写一个基本的字符设备驱动程序: 1. 包含必要的头文件: ```c #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/cdev.h> ``` 2. 定义设备号: ```c dev_t dev = 0; static struct cdev c_dev; ``` 3. 实现文件操作函数: ```c static int device_open(struct inode *i, struct file *f) { printk(KERN_INFO "Device opened\n"); return 0; } static int device_release(struct inode *i, struct file *f) { printk(KERN_INFO "Device closed\n"); return 0; } static ssize_t device_read(struct file *f, char __user *buf, size_t len, loff_t *off) { printk(KERN_INFO "Reading from device\n"); // 在这里实现读取设备数据的逻辑 return 0; } static ssize_t device_write(struct file *f, const char __user *buf, size_t len, loff_t *off) { printk(KERN_INFO "Writing to device\n"); // 在这里实现写入设备数据的逻辑 return len; } static struct file_operations fops = { .owner = THIS_MODULE, .open = device_open, .release = device_release, .read = device_read, .write = device_write }; ``` 4. 初始化并注册字符设备驱动: ```c static int __init char_device_init(void) { if (alloc_chrdev_region(&dev, 0, 1, "char_device") < 0) { return -1; } if ((cl = class_create(THIS_MODULE, "char_device_class")) == NULL) { unregister_chrdev_region(dev, 1); return -1; } if (device_create(cl, NULL, dev, NULL, "char_device") == NULL) { class_destroy(cl); unregister_chrdev_region(dev, 1); return -1; } cdev_init(&c_dev, &fops); if (cdev_add(&c_dev, dev, 1) == -1) { device_destroy(cl, dev); class_destroy(cl); unregister_chrdev_region(dev, 1); return -1; } return 0; } ``` 5. 卸载字符设备驱动: ```c static void __exit char_device_exit(void) { cdev_del(&c_dev); device_destroy(cl, dev); class_destroy(cl); unregister_chrdev_region(dev, 1); } ``` 6. 注册初始化和卸载函数: ```c module_init(char_device_init); module_exit(char_device_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); ``` 这只是一个简单的示例,真实的字符设备驱动可能更加复杂。你可以根据自己的需求进行扩展和修改。编写完成后,使用gcc编译并将其插入内核即可使用。 请注意,字符设备驱动程序的编写需要一定的Linux内核编程知识和对设备驱动的理解。在实际编写和使用过程中,请仔细阅读相关文档和学习资料,并进行必要的测试和验证。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值