【讯为Linux驱动开发】2.注册一个字符设备

【问】如何描述一个字符设备?

dev结构体

其中需要关心三个成员变量:

所属模块 :struct module *owner;

文件操作结构体: const struct file_operations *ops

设备号 : dev_t

当应用层使用指令open("/dev/hello", HELLO),系统就会进入驱动程序中执行cdev_open函数

【问】 如何连接系统调用open和驱动程序dev_open函数

file_operations结构体中就将这两个函数进行连接:

cs 复制代码
static struct file_operations cdev_ops = {
     .owner = THIS_MODULE;
     .open = cdev_open;
}
【问】应用程序和驱动程序的桥梁是什么?

设备节点,设备节点创建在/dev目录下。

比如 open("/dev/hello" ,HELLO);

【问】如何创建设备节点?

使用udev机制,在注册设备的时候自动创建,在注销设备的时候自动销毁。

1.创建类:

class_creat(struct module *owner ,const char *name)

THIS_MODULE 和 类的名字

对应删除:class_destroy(struct class *cls) 类

2.在类下创建设备:

device_creat(struct class *cls ,struct device *parent, dev_t devt , NULL ,const char *fmt )

1.哪个类 2.父设备是谁? NULL一般 3.设备号 4.NULL 5.设备节点的名字

3.删除类:

device_destroy(struct class *cls, dev_t devt)

类 设备号

【注册字符设备模版 】

cs 复制代码
static int major = 0;
static int minor = 0;
module_param(major ,int ,S_IRUGO);
module_param(minor ,int ,S_IRUGO);

dev_t dev_num;

static int cdev_open(struct inode *inode, struct file *filp)
{
    printk("cdev_open success\n");
    return 0;
}

static ssize_t cdev_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    printk("cdev_read success\n");
    return 0;
}

static ssize_t cdev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    printk("cdev_write success\n");
    return 0;            
}

static int cdev_release(struct inode *inode, struct file *filp)
{
    printk("cdev_release success\n");
    return 0;       
}

struct file_operations cdev_file_operations = {
    .owner = THIS_MODULE;
    .open = cdev_open;
    .read = cdev_read;
    .write = cdev_write;
    .release = cdev_release;
}


struct cdev cdev_test;


static int moduleparam_init()
{
        int ret;
        /* 动态申请 */
        ret = alloc_chrdev_region(&dev_num,0,1);  
        if(ret<0)
        {
           printk("alloc_chrdev_region error\n");
        }
          //动态注册设备号成功,则打印
           printk("alloc_chrdev_region ok\n");  
           major_num =MAJOR(dev_num); //将主设备号取出来
           minor_num = MINOR(dev_num);//将次设备号取出来
           printk("major_num = %d\n",major_num);//打印传入进来的主设备号
           printk("minor_num = %d\n",minor_num);//打印传入进来的次设备号
           
           cdev_test.owner = THIS_MODULE;
           cdev_init(cdev_test, cdev_file_operations);
           cdev_add(&cdev_test, dev_num, 1);
           
           class = class_creat(THIS_MODULE, "test");
           device = device_creat(class,NULL,dev_num,,NULL,"/dev/test")
          
           return 0;
}

static void hello_exit(void)
{
  unregister_chrdev_region(MKDEV(major_num,minor_num),DEVICE_NUMBER);//注销设备号
  cdev_del(&cdev_test);  //销毁字符设备

  device_destroy(class,dev_num);
  class_destroy(class);

  printk("gooodbye! \n");
}

module_init(moduleparam_init);
module_init(moduleparam_exit);

【应用程序验证】

cs 复制代码
int main(int argc, char *argv[])
{
 int fd;
 char buf[64] = 0;
 fd = open("/dev/test", HELLO);  /* 打开设备节点 */   
 close(fd);
 return 0;  
}
【问】app.c如何编译?

使用3568开发板对应的交叉编译器

linux源码 / prebuilts /gcc /linux-x86 / aarch64 / gcc ..............................

然后进入bin文件夹找到 gnu - gcc

编译命令:

进入app.c目录:

交叉编译器的绝对路径 加 / 交叉编译器的名字 加 app.c

生成a.out文件

拷贝 a.outfile .ko 文件进开发板

加载:insmod file.ko

手动创建设备节点 : mknod /dev/test c 2350 (设备名字和驱动中一致)

(在dev/test中可以看到设备节点)

执行 a.out 应用程序: ./a.out

成功调用,打印出驱动中的这两句话:

实验效果:

加载:insmod file.ko

因为是自动创建设备节点,所以ls /dev/test直接看

执行:./a.out

---------------------------------------------

-----------------------打印出打开设备和卸载设备信息

相关推荐
赟赟、嵌入式15 小时前
linux RTC时钟时间出现了明显的偏移
linux·驱动开发·嵌入式硬件·实时音视频
sukalot16 小时前
windows USB 设备驱动开发- USB管道的通讯(一)
驱动开发
拉达曼迪斯II2 天前
14-28 剑和诗人2 - 高性能编程Bend和Mojo
人工智能·驱动开发·语言模型·创业创新·mojo
Spcarrydoinb3 天前
嵌入式学习——硬件(Linux内核驱动编程LED、蜂鸣器、按键)——day59
linux·驱动开发·学习
cooldream20093 天前
测试驱动开发(TDD)方法详解
驱动开发·tdd
Geektec3 天前
AI在软件开发:助力开发者还是取而代之?
人工智能·驱动开发·计算机·chatgpt·变革
阳爱铭3 天前
GitHub:现代软件开发的协作平台
驱动开发·后端·中间件·面试·架构·github·学习方法
cooldream20093 天前
用户体验驱动开发:打造卓越数字产品的关键
驱动开发·ux
北京迅为4 天前
RK3568驱动指南|第十六篇 SPI-第190章 配置模式下寄存器的配置
linux·驱动开发·嵌入式硬件·rk3568
宁静致远20214 天前
【正点原子MP157连载】第十九章 Buildroot根文件系统构建-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7
linux·驱动开发·stm32