首页 > 其他分享 >泰山派学习11--字符设备驱动

泰山派学习11--字符设备驱动

时间:2024-06-15 21:44:08浏览次数:21  
标签:11 字符 file struct -- zbl dev chardev 设备

1、字符设备定义

  应用程序按字节/字符来读写数据的设备,不支持随机存取数据,系统直接从设备读取/写入每一个字符。

2、字符设备抽象

  Linux内核中将字符设备抽象成一个具体的数据结构(struct cdev),理解为字符设备对象。 字符设备的打开、读写、关闭等操作接口(file_operations)。 创建一个文件(设备节点)绑定对象的cdev

3、字符设备相关概念

3.1、设备号

主设备号区分设备类别,次设备号标识具体的设备。cdev结构体被内核用来记录设备号,而在使用设备时,我们通常会打开设备节点,通过设备节点的inode结构体、 file结构体最终找到file_operations结构体,并从file_operations结构体中得到操作设备的具体方法。 dev_t用来表示设备编号,dev_t是一个32位的数,其中,高12位表示主设备号,低20位表示次设备号。

3.2、设备节点

Linux中设备节点是通过“mknod”命令来创建的。一个设备节点其实就是一个文件, Linux中称为设备文件。设备节点被创建在/dev下,是连接内核与用户层的枢纽。

sudo mknod /dev/chardev c 236 0

4、数据结构

这三个数据结构体都是存在(内核源码/include/linux/fs.h)

4.1、文件操作结构体file_operations

系统调用和驱动程序关联起来的关键数据结构

struct file_operations {

struct module *owner;

ssize_t (*read)(struct file *, char __user *, size_t loff_t *);

ssize_t (*write)(struct file const char __user *, size_t, loff_t *);

int (*open)(struct inode *, struct file *);

int (* release)(struct inode *, struct file *);

......

};

4.2 文件描述结构体

内核中用file结构体来表示每个打开的文件,每打开一个文件,内核会创建一个结构体

struct file {

{......};

const struct file_operations *f_op;

void *private_data;

{......};

};

4.3、节点inode结构体

内核使用inode结构体在内核内部表示一个文件,它是Linux 管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁.

struct inode{

dev_t i_rdev;

{......};

union{

struct pipe_inode_info *i_pipe;

struct block_device *i_bdev;

struct cdev *i_cdev;

char *i_link;

unsigned i_dir_seq;

};

{......};

};

5、设备号的注册申请及注销归还

5.1、宏定义常量进行申请

int register_chrdev_region(dev_t from, unsigned count, const char *name)

5.2、内核自动分配,成功会返回一个指针

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

5.3、注销删除设备

void unregister_chrdev_region(dev_t from, unsigned count)

6、字符设备驱动模块(chrdevbase.c)

//头文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define MY_NAME "chardev"

int major = 0;
char kbuf[128] = {0};

int my_open(struct inode *inode, struct file *file)
{
  printk("chardev open!\n");
  return 0;
}
ssize_t my_read(struct file *file, char __user *ubuf, size_t size, loff_t *offset)
{
  if(size > sizeof(kbuf)){
  size = sizeof(kbuf);
}
  if(copy_to_user(ubuf, kbuf, size)){
    printk("copy data to user failed.\n");
    return -EIO;
  }
  printk("user read data ok!\n");
  return size;
}
ssize_t my_write(struct file *file, const char __user *ubuf, size_t size, loff_t *offset)
{
  if(size > sizeof(kbuf)){
  size = sizeof(kbuf);
  }
  if(copy_from_user(kbuf, ubuf, size)){
    printk("copy data to kernel failed.\n");
    return -EIO;
  }
  printk("user write data ok!\n");
  return size;
}
int my_close(struct inode *inode, struct file *file)
{
  printk("chardev close!\n");
  return 0;
}

struct file_operations fops = {
  .owner = THIS_MODULE,
  .open = my_open,
  .read = my_read,
  .write = my_write,
  .release = my_close
};

static int __init mycdev_init(void)
{
  major = register_chrdev(0, MY_NAME, &fops);
  if(major < 0)
  {
    printk("chardev reg failed!\n");
    return -1;
  }
  printk("chardev reg successed\n");
  return 0;
}

static void __exit mycdev_exit(void)
{
  printk("hello linux %s\n"," chardev exit");
  unregister_chrdev(major, MY_NAME);
}

module_init(mycdev_init);

module_exit(mycdev_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("zbl");

7、用户应用程序(chrdevbaseapp.c)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>


int main()
{

char buf[32] = "zbl tspi.";
char ubuf[64] = {0};
int fd = open("/dev/chardev",O_RDWR);
if(fd == -1)
{
  printf("open failed.\n");
  return -1;
}

memcpy(ubuf,buf,sizeof(buf));
printf("write ubuf = %s\n", ubuf);
write(fd,ubuf,sizeof(ubuf));

memset(ubuf, 0, sizeof(ubuf));
read(fd,ubuf,1024);
printf("read ubuf = %s\n",ubuf);

close(fd);
return 0;

}

**8、交叉编译makefile**

PWD ?= $(shell pwd)

KERNELDIR := /home/zbl/tspi-rk3566/sdk/linux/kernel

CROSS_COMPILE ?= /home/zbl/tspi-rk3566/sdk/linux/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-

CC := $(CROSS_COMPILE)gcc

obj-m += chrdevbase.o

module:

make -C $(KERNELDIR) M=$(PWD) ARCH=arm64 modules

@# -C 表示从当前目录切换到内核源码目录下,借助内核源码makefile进行make编译

@# M=$(PWD) 表示只编译当前目录下的驱动

@# ARCH=arm64 指定编译架构

$(CC) chrdevbaseapp.c -o app

@# 交叉编译应用程序

.PHONE:clean

clean:

make -C $(KERNELDIR) M=$(PWD) ARCH=arm64 clean

rm app

**9、修改终端printk显示等级**

////终端消息在串口才可以查看,ssh无法打印终端消息,并且需要修改printk的等级为8////

root@localhost:/home/lckfb/zbl-kernel-modules# ./app

root@localhost:/home/lckfb/zbl-kernel-modules# cat /proc/sys/kernel/printk

4       4       1       7

root@localhost:/home/lckfb/zbl-kernel-modules# echo 8 > /proc/sys/kernel/printk

root@localhost:/home/lckfb/zbl-kernel-modules# cat /proc/sys/kernel/printk

8       4       1       7

       

10、执行流程

1、编写内核驱动chrdevbase.c

2、编写应用程序chrdevbaseapp.c

3、编写makefile,添加交叉编译工具及编译应用执行文件

4、.ko及app应用执行文件导入开发板 cmd 使用adb命令或者局域网内登录ssh 传输 : adb push  xxx xxx

       

5、修改执行权限 chmod 777 app chrdevbase.ko

6、加载内核启动 sudo insmod chrdevbase.ko

lckfb@linux:~/zbl-kernel-modules$ sudo insmod chrdevbase.ko
[ 4343.651750] reg successed

       

7、查看驱动lsmod

lckfb@linux:~/zbl-kernel-modules$ lsmod
Module Size Used by
chrdevbase 16384 0
bcmdhd 1048576 0

       

8、查看驱动主设备号

cat /proc/devices

226 drm

236 chardev

237 hidraw

238 rpmb

239 ttyGS

      

9、创建设备节点文件 sudo mknod /dev/chardev c(字符设备) 236(主设备号) 0(从设备号)

lckfb@linux:~/zbl-kernel-modules$ sudo mknod /dev/chardev c 236 0

       

10、查看节点是否加载成功 ls -l /dev/chardev

lckfb@linux:~/zbl-kernel-modules$ ll /dev/chardev
crw-r--r-- 1 root root 236, 0 Jun 4 13:59 /dev/chardev

11、修改节点权限 sudo chmod 777 /dev/chardev

lckfb@linux:~/zbl-kernel-modules$ ll /dev/chardev
crwxrwxrwx 1 root root 236, 0 Jun 4 13:59 /dev/chardev

12、执行应用程序 ./app

root@localhost:/home/lckfb/zbl-kernel-modules# ./app
[ 4208.722682] open!
[ 4208.722768] read!
[ 4208.722785] write!
[ 4208.722801] close!
root@localhost:/home/lckfb/zbl-kernel-modules/04# ./app
[ 1090.308736] chardev open!
write ubuf = zbl tspi.
read ubuf = zbl tspi.
[ 1090.309171] user write data ok!
[ 1090.309209] user read data ok!
[ 1090.309500] chardev close!

      

13、卸载内核驱动 sudo rmmod chrdevbase.ko

root@localhost:/home/lckfb/zbl-kernel-modules# sudo rmmod chrdevbase.ko

[ 4236.212310] hello world mydev exit

       

14、删除设备节点文件 sudo rm /dev/chardev

root@localhost:/home/lckfb/zbl-kernel-modules# sudo rm /dev/chardev

       

标签:11,字符,file,struct,--,zbl,dev,chardev,设备
From: https://www.cnblogs.com/zblblog/p/18232342

相关文章

  • 5月31日
    今天上午完成了计网的实验二实验二 路由器动态路由的配置方法  一、实验目的: 1.理解动态路由的工作原理;2.学习并掌握动态路由协议RIP的配置;3.学习并掌握动态路由协议OSPF的配置;4.进一步学习路由器的配置命令。二、实验原理:RIP(RoutingInformationProtocols,路由信息......
  • 代码随想录算法训练营第十天
    python语法:一、通常使用列表(list)来实现栈。append(),pop()点击查看代码stack=[]#压栈(push)stack.append(1)#弹栈(pop)top_element=stack.pop()#查看栈顶元素(peek)top_element=stack[-1]#检查栈是否为空is_empty=len(stack)==0二、可以使用列表(list)或col......
  • 最低50元的京东云轻量服务器体验
    ‍最低50元的京东云轻量服务器体验:最低的价格,最差的体验。​​体验​​看路人评论​​‍处处是bug‍从自己的机器上ssh到服务器,刚连接的时候正常​​用了一会,终端没反应了(非禁止画面)这是不是断连?​​‍然后是网页的控制台​​vim搜索alias,开始乱码​​鼠......
  • 【译文】利用RNN从神经数据中重建计算系统动力学
    【译文】利用RNN从神经数据中重建计算系统动力学文章:ReconstructingcomputationalsystemdynamicsfromneuraldatawithrecurrentneuralnetworksDOI:https://doi.org/10.1038/s41583-023-00740-7FromNatureReviewsNeuroscience|Volume24|November2023|693–71......
  • WPF Path Data PathGeometry PathFigure Segments BezierSegment,LineSegment,ArcSeg
     BezierSegment//BezierCurveusingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows;usingSystem.Windows.Controls;usingSystem.Windows.Data;usingSystem.Windows.Documen......
  • 5月24日
    今天上午完成了数据库的实验二实验二SQL语言的使用一、实验目的:掌握使用SQL语言进行各种查询的操作和视图的操纵方法。二、实验要求:在现有的数据库上进行各种查询操作,对视图的创建、使用等操作。三、实验步骤:1、开始→程序→MicrosoftSQLServer→SQLServerManagem......
  • 数据库连接池、flask定制命令、flask-cache缓存、信号
    flask操作mysql1fromflaskimportFlask,jsonify2importpymysql34app=Flask(__name__)5app.debug=True67#拿到mysql链接对象8conn=pymysql.connect(host='127.0.0.1',user='root',password='199721',database=&......
  • ensp实验
    需求:1.除R5的环回地址固定以外,整个其他所有网段基于192.168.1.0/24进行合理的ip地址划分2.R1-R4每个路由器存在两个环回接口,用于模拟连接PC网段;地址也在192.168.1.0/24这个网络范围内,R3下面PC通过DHCP获取一个合法的地址3.R1-R4上不能直接编写到达5.5.5.0/24的静态路由,但依......
  • 英语复习之英语反义词总结(七)
    接下来总结一些英语反义词。单词(英式发音/美式发音)释义(词性)例句(中文翻译)Absent(/'æbsənt//ˈæbsənt/)缺席的(adj)Shewasabsentfromschoolyesterday.(她昨天缺席了学校。)Hisabsencewasnotedbyeveryone.(每个人都注意到了他的缺席。......
  • 5月29日
    今天上午python完成了实验三Python可视化训练【实验编号】【实验专责】刘立嘉;【实验目的】使学生综合运用图形用户界面设计的概念;使学生熟悉使用中间面板,组成层次复杂的GUI界面;使学生掌握Python图形绘制和图像处理步骤与方法;使学生掌握Python可视化处理的步骤......