驱动 自动创建设备节点 2024.1.3

驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
 
#define CNAME "myled"
unsigned int major = 0; //分配的主设备号
char kbuf[128] = "";
struct class *cls = NULL;
struct device *dev = NULL;
 
int myled_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); //打印一句话
    return 0;
}
 
ssize_t myled_read(struct file *file, char __user *ubuf, size_t size, loff_t *loffs)
{
    int ret;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);//打印一句话
   //如果用户空间想读的大小,大于内核空间的大小,更正写大小
    if(size > sizeof(kbuf))  size = sizeof(kbuf);
    ret = copy_to_user(ubuf,kbuf,size); //将内核空间的数据拷贝到用户空间
    if(ret){
        printk("copy to user is error\n");
        return -EIO;
    }
    return size; //!!!!!!!!!!
}
 
ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loffs)
{
    int ret;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);//打印一句话
    //如果用户空间写的大小,大于内核空间的大小,更正写大小
    if(size > sizeof(kbuf))  size = sizeof(kbuf);
    ret = copy_from_user(kbuf,ubuf,size); //将用户空间的数据拷贝到内核空间
    if(ret){ //判断错误
        printk("copy from user is error\n");
        return -EIO;
    }
    //打印kbuf中的内容,kbuf中存储的内容,就是用户空间拷贝过来的内容
    printk("kernel kbuf = %s\n",kbuf);
    return size; //!!!!!!!!!!
}
 
int myled_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);//打印一句话
    return 0;  
}
 
//操作方法结构体
const struct file_operations fops = {
        .open = myled_open,
        .read = myled_read,
        .write = myled_write,
        .release = myled_close,
};
 
//入口
static int __init mycdev_init(void)
{
    //1.注册字符设备驱动
    major = register_chrdev(0,CNAME,&fops);
    if(major <= 0){
        printk("register chrdev is error\n");
        return  -EIO;
    }
    //2.打印分配成功主设备号
    printk("major = %d\n",major);
 
    //3.提交目录信息 class_create
    cls = class_create(THIS_MODULE,CNAME);    
    if(IS_ERR(cls)) //判断错误码转换为地址是否在4K空间内
    {
        printk("class create is error\n");
        return PTR_ERR(cls);//将地址转换为错误码    
    }
    //4.提交设备节点信息 device_create 节点名字myled
    dev = device_create(cls,NULL,MKDEV(major,0),NULL,CNAME);
    if(IS_ERR(dev)) //判断错误码转换为地址是否在4K空间内
    {
        printk("device create is error\n");
        return PTR_ERR(dev);//将地址转换为错误码    
    }   
    return 0;
}
 
//出口
static void __exit mycdev_exit(void)
{
    device_destroy(cls,MKDEV(major,0));//取消向上层提交设备节点信息
    class_destroy(cls);//取消向上层提交目录信息
    //注销字符设备驱动
    unregister_chrdev(major,CNAME);
}
 
module_init(mycdev_init);//指定入口地址
module_exit(mycdev_exit);//指定出口地址
MODULE_LICENSE("GPL");//遵循GPL协议

应用层代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char const *argv[])
{
    int fd = -1;
    char buf[128] = "";
    fd = open("/dev/myled",O_RDWR); //打开
    if(fd == -1){
        perror("open is error\n");
        exit(1);
    }
    fgets(buf,sizeof(buf),stdin);
    buf[strlen(buf)-1] = '\0';
    write(fd,buf,sizeof(buf)); //将buf内容拷贝到内核空间
    memset(buf,0,sizeof(buf)); //将buf内容清空
    read(fd,buf,sizeof(buf)); //将内核空间的数据读到buf中
    printf("user buf = %s\n",buf);
    close(fd);//关闭
    return 0;
}

Makefile

ARCH ?= arm
MODNAME ?= mycdev

#编译ARM架构
ifeq (arm,$(ARCH))
	KERNEDIR := /home/ubuntu/linux-5.10.61/
else
#编译X86架构
	KERNEDIR := /lib/modules/$(shell uname -r)/build
endif

#打开终端,在当前终端执行pwd命令,赋值给PWD
PWD := $(shell pwd)

all:
	@#采用模块化编译
	@#-C : 跳转到内核源码顶层目录,读取该目录下的Makefile
	@#M 跳转到当前编写驱动的目录,读取该目录下的Makefile
	make -C $(KERNEDIR) M=$(PWD) modules

clean:
	make -C $(KERNEDIR) M=$(PWD) clean

#制定编译文件
obj-m := $(MODNAME).o

测试

1.编译驱动代码:linux@ubuntu:~/DC23081/02_chrdev$ make ARCH=x86 MODNAME=mycdev

2.清除打印信息:linux@ubuntu:~/DC23081/02_chrdev$ sudo dmesg -C

3.安装驱动:linux@ubuntu:~/DC23081/02_chrdev$ sudo insmod mycdev.ko

4.查看分配到主设备号信息:linux@ubuntu:~/DC23081/02_chrdev$ dmesg ===>[ 9885.250251] major = 236

5.编译应用层程序

6.编译应用层程序 ===> linux@ubuntu:~/DC23081/02_chrdev$ gcc test.c

7.运行应用层程序 ===> linux@ubuntu:~/DC23081/02_chrdev$ sudo ./a.out

8.查看内核层打印信息 ===> dmesg

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值