当前位置: 首页 > news >正文

北京大兴专业网站建设公司交换链接

北京大兴专业网站建设公司,交换链接,济南网站建设外包公司,建设外贸购物网站概述 本文介绍了platform框架下的设备驱动开发流程和方法,主要包括设备树、驱动程序和应用程序的开发。以随机数驱动为例,实现了应用程序调用库函数,通过系统调用陷入内核,最后执行硬件驱动,获取真随机数的过程。 添…

概述

本文介绍了platform框架下的设备驱动开发流程和方法,主要包括设备树、驱动程序和应用程序的开发。以随机数驱动为例,实现了应用程序调用库函数,通过系统调用陷入内核,最后执行硬件驱动,获取真随机数的过程。

添加设备树节点

soc节点下添加名为trng子节点,内容如下:

trng: trng@0x53030000 {compatible = "acme,trng";reg = <0x00 0x53030000 0x00 0x1000>;interrupts = <0x34 IRQ_TYPE_LEVEL_HIGH>;interrupt-parent = <&plic>;
};

编译设备树dts,生成相应的dtb文件:

make dtbs

使用新的dtb启动Linux内核。Linux启动成功之后查看是否有trng这个节点:

ls /proc/device-tree/soc
# trng@0x53030000

进入trng目录,查看属性相关的文件:

/proc/device-tree/soc/trng@0x53030000# ls
compatible        interrupts        phandle
interrupt-parent  name              reg

编写设备驱动

Makefile

新建trng/driver目录,并创建Makefile,内如如下:

# 内核架构
ARCH := riscv
# 交叉工具链
CROSS_COMPILE := /path/to/riscv32-linux-
# 内核目录
KERNELDIR := /path/to/linux/linux-6.1
# 当前目录
PWD := $(shell pwd)
# 目标文件
obj-m := trng.o# 目标
build: kernel_modules# 编译模块
kernel_modules:$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules# 清理
clean:$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) clean

驱动

trng/driver下新建trng.c文件,内容如下:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/platform_device.h>/* TRNG寄存器 */
#define TRNG_CTRL           (0x0)#define TRNG_CTRL_CMD_MASK      (0x07)#define TRNG_CTRL_CMD_RNG       (0x01)#define TRNG_CTRL_CMD_SEED      (0x02)
#define TRNG_STAT           (0x4)#define TRNG_STAT_SEEDED        BIT(9)
#define TRNG_MODE           (0x8)#define TRNG_MODE_R256          BIT(3)
#define TRNG_ISTAT          (0x14)#define TRNG_ISTAT_RAND_RDY     BIT(0)#define TRNG_ISTAT_SEED_DONE    BIT(1)
#define TRNG_RAND0          (0x20)#define TRNG_TIMEOUT        (50000)#define DRIVER_NAME         "trng"struct trng_dev {dev_t devid;            /* 设备号 */struct cdev cdev;       /* cdev */struct class *class;    /* 类 */struct device *dev;     /* 设备 */int major;              /* 主设备号 */int minor;              /* 次设备号 */int irq;                /* 中断号 */void __iomem *base;     /* 基地址 */
};static int trng_init(void *base)
{int ret;unsigned int value;/* 模式 */value = readl(base + TRNG_MODE);value |= TRNG_MODE_R256;writel(value, base + TRNG_MODE);    /* 播种 */value = readl(base + TRNG_CTRL);value &= ~TRNG_CTRL_CMD_MASK;value |= TRNG_CTRL_CMD_SEED;writel(value, base + TRNG_CTRL);/* 等待播种完成 */ret = readl_relaxed_poll_timeout_atomic(base + TRNG_ISTAT,value, (value & TRNG_ISTAT_SEED_DONE),10, TRNG_TIMEOUT);if (ret == 0) {value |= TRNG_ISTAT_SEED_DONE;writel(value, base + TRNG_ISTAT);}return ret;
}static int trng_generate_random(void *base, unsigned char *buf)
{int ret;unsigned int value;/* 启动生成随机数 */value = readl(base + TRNG_CTRL);value &= ~TRNG_CTRL_CMD_MASK;value |= TRNG_CTRL_CMD_RNG;writel(value, base + TRNG_CTRL);/* 等待随机数准备好 */ret = readl_relaxed_poll_timeout_atomic(base + TRNG_ISTAT,value, (value & TRNG_ISTAT_RAND_RDY),10, TRNG_TIMEOUT);    if (ret) {return ret;}/* 清除准备好标志 */value = readl(base + TRNG_ISTAT);value &= ~TRNG_ISTAT_RAND_RDY;writel(value, base + TRNG_ISTAT);/* 读取随机数 */for (int i = 0; i < 8; i++) {*(unsigned int*)buf = readl(base + TRNG_RAND0 + i*4);buf += 4;}return 0;
}static irqreturn_t trng_irq_handler(int irq, void *dev_id)
{struct trng_dev *trng;trng = (struct trng_dev*)dev_id;dev_dbg(trng->dev, "TRNG interrupt received\n");return IRQ_HANDLED;
}static int trng_open(struct inode *inode, struct file *filp) 
{int ret;struct trng_dev *trng;trng = container_of(inode->i_cdev, struct trng_dev, cdev);filp->private_data = trng;dev_dbg(trng->dev, "Open trng\n");ret = trng_init(trng->base);if (ret) {dev_err(trng->dev, "Failed to init trng, ret=%d\n", ret);return ret;}return 0;
}static int trng_release(struct inode *inode, struct file *filp) 
{struct trng_dev *trng;trng = filp->private_data;dev_dbg(trng->dev, "Release trng\n");return 0;
}static ssize_t trng_read(struct file *filp, char __user *buffer, size_t len, loff_t *offset)
{  int ret;unsigned char random[32];size_t copyed_len, len_to_copy;struct trng_dev *trng;trng = filp->private_data;dev_info(trng->dev, "Read trng\n");copyed_len = 0;while (len) {ret = trng_generate_random(trng->base, random);if (ret) {dev_err(trng->dev, "Failed to generate random, ret=%d\n", ret);return ret;}// print_hex_dump(KERN_INFO, "random: ", DUMP_PREFIX_NONE, 16, 1, random, sizeof(random), false);len_to_copy = (len < sizeof(random)) ? len : sizeof(random);ret = copy_to_user(buffer, random, len_to_copy);if (ret) {dev_err(trng->dev, "Failed to copy to user\n");return -EFAULT;}copyed_len += len_to_copy;buffer += len_to_copy;len -= len_to_copy;}return copyed_len;  
}  static ssize_t trng_write(struct file *filp, const char __user *buffer, size_t len, loff_t *offset) 
{struct trng_dev *trng;trng = filp->private_data;dev_dbg(trng->dev, "Write trng\n");return len;
}static long trng_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{struct trng_dev *trng;trng = filp->private_data;dev_dbg(trng->dev, "Ioctl trng\n");switch (cmd) {default:dev_err(trng->dev, "Unknown ioctl = 0x%x\n", cmd);break;}return -ENOTTY;
}static int trng_mmap(struct file *filp, struct vm_area_struct *vma) 
{struct trng_dev *trng;trng = filp->private_data;dev_dbg(trng->dev, "Mmap trng\n");return 0;
}static const struct file_operations trng_fops = {.owner = THIS_MODULE,.open = trng_open,.release = trng_release,.read = trng_read,.write = trng_write,.unlocked_ioctl = trng_ioctl,.mmap = trng_mmap,
};static int trng_probe(struct platform_device *pdev) 
{struct device *dev = &pdev->dev;struct trng_dev *trng;int ret;/* 分配内存 */trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL);if (!trng) {dev_err(dev, "Failed to allocate memory\n");return -ENOMEM;}/* 将设备的资源映射到内存空间 */trng->base = devm_platform_ioremap_resource(pdev, 0);if (IS_ERR(trng->base)) {dev_err(dev, "Failed to map device registers\n");return PTR_ERR(trng->base);}/* 获取设备的中断号 */trng->irq = platform_get_irq(pdev, 0);if (trng->irq <= 0) {dev_err(dev, "Failed to get irq %d\n", trng->irq);return trng->irq;        }/* 请求中断 */ret = devm_request_irq(dev, trng->irq, trng_irq_handler, 0,DRIVER_NAME, trng);if (ret) {dev_err(dev, "Failed to request IRQ\n");return ret;}/* 申请设备号 */ret = alloc_chrdev_region(&trng->devid, 0, 1, DRIVER_NAME);  if (ret < 0) {  dev_err(dev, "Failed to allocate device number\n");  return ret;  }trng->major = MAJOR(trng->devid); trng->minor = MINOR(trng->devid); /* 初始化cdev */trng->cdev.owner = THIS_MODULE;cdev_init(&trng->cdev, &trng_fops);/* 添加一个cdev */ret = cdev_add(&trng->cdev, trng->devid, 1);if (ret < 0) {dev_err(dev, "Failed to add cdev\n");unregister_chrdev_region(trng->devid, 1);return ret;} /* 创建类 */trng->class = class_create(THIS_MODULE, DRIVER_NAME);if (IS_ERR(trng->class)) {cdev_del(&trng->cdev);unregister_chrdev_region(trng->devid, 1);dev_err(dev, "Failed to create class\n");return PTR_ERR(trng->class);}/* 创建设备 */trng->dev = device_create(trng->class, NULL, trng->devid, NULL, DRIVER_NAME);if (IS_ERR(trng->dev)) {cdev_del(&trng->cdev);unregister_chrdev_region(trng->devid, 1);class_destroy(trng->class);dev_err(dev, "Failed to create device\n");return PTR_ERR(trng->dev);}/* 保存设备私有结构体 */platform_set_drvdata(pdev, trng);dev_info(dev, "TRNG platform driver probed\n");return 0;
}static int trng_remove(struct platform_device *pdev) 
{struct trng_dev *trng;/* 获取设备私有结构体 */trng = platform_get_drvdata(pdev);/* 删除cdev */cdev_del(&trng->cdev);/* 释放设备号 */unregister_chrdev_region(trng->devid, 1);/* 删除设备 */device_destroy(trng->class, trng->devid);/* 删除类 */class_destroy(trng->class);/* 释放设备内存 */// devm_kfree(&pdev->dev, trng);    // devm_kzalloc为设备分配的内存,在设备移除时会自动释放dev_info(&pdev->dev, "TRNG platform driver removed\n");return 0;
}static const struct of_device_id trng_of_match[] = {{ .compatible = "acme,trng" },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, trng_of_match);static struct platform_driver trng_driver = {.driver = {.name = DRIVER_NAME,.of_match_table = trng_of_match,},.probe = trng_probe,.remove = trng_remove,
};module_platform_driver(trng_driver);MODULE_AUTHOR("Author");
MODULE_DESCRIPTION("Trng driver");
MODULE_LICENSE("GPL");

使用platform平台驱动设备模型编写trng的驱动程序。

  • 当设备树中的节点与驱动匹配成功会执行trng_probe函数,完成驱动的加载。

  • 当应用需要获取随机数时,读取这个trng设备,陷入内核调用函数trng_read,进而调用函数trng_generate_random完成从硬件获取随机数。

  • 如果需要释放设备,会调用trng_remove函数卸载设备驱动。

执行make编译驱动程序,编译成功生成trng.ko

Linux启动成功之后,可以挂载nfs,将trng.ko拷贝到trng目录:

mkdir trng
mount -t nfs -o nolock xx.xx.xx.xx:/nfs/trng /root/trng

执行如下命令,加载设备驱动:

insmod trng.ko
# [  177.821055] trng 53030000.trng: TRNG platform driver probed

如果设备驱动加载成功,可以在/dev下找到设备:

ls /dev/trng

另外可以查看trng的设备号:

cat /proc/devices
# 249 trng

如果需要卸载设备驱动,执行:

rmmod trng.ko
# [ 2947.495906] trng 53030000.trng: TRNG platform driver removed

应用App

Makefile

新建trng/app目录,并创建Makefile,内如如下:

# 交叉工具链
CROSS_COMPILE ?= /opt/andestech/nds32le-linux-glibc-v5d/bin/riscv32-linux-# 指定C编译器
CC := $(CROSS_COMPILE)gcc# 目标文件名
TARGET := trng# 源文件名
SRC := trng.c# 默认目标
all: $(TARGET)# 编译并链接
$(TARGET): $(SRC)$(CC) $(SRC) -o $(TARGET)# 清理
clean:rm -f $(TARGET)

应用

trng/app下新建trng.c文件,内容如下:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h> #define TRNG_DEVICE                       "/dev/trng"static void hexdump(const char *name, const unsigned char *buffer, unsigned int len)
{printf("****************%s****************\n", name);for (unsigned int i = 0; i < len; i++) {printf("%02x ", buffer[i]);if ((i + 1) % 16 == 0) {printf("\n");}}if (len % 16 ) {printf("\n");}
}int main(int argc, char *argv[])
{uint8_t *buf = NULL;size_t num;int ret, fd;if (argc < 2) {printf("Usage: trng <num>\n");return -1;}num = atoi(argv[1]);buf = malloc(num);if (buf == NULL) {printf("Failed to malloc\n");return -1;}/* 打开设备 */fd = open(TRNG_DEVICE, O_RDONLY);if (fd < 0) {printf("Failed to open trng device\n");goto exit;}/* 读取随机数 */ret = read(fd, buf, num);if (ret < 0) {printf("Failed to read random, ret=%d\n", ret);goto exit;}hexdump("random", buf, num);
exit:close(fd);free(buf);return ret;
}

执行make编译应用程序,编译成功生成trng

同理,将trng应用拷贝到trng目录,并执行:

./trng 16
# ****************random****************
# 6c 95 ea 3c a0 1f e8 c2 03 db 66 f6 19 4b 07 e3 
# c0 96 a3 93 20 a9 68 c5 9f 1f a1 55 c0 9c 24 c9 
# 5f 06 47 45 be 2c 21 b5 11 23 23 e6 36 94 3f d6 
# 9a 30 68 91 da c4 6d ff af 46 26 c9 ab f8 79 7c 

如果随机数获取成功,说明驱动和应用程序运行正常。

编译进内核

在开发前期阶段,一般将驱动编译成模块,方便调试。当驱动开发完成后,可以将其编译进内核。

驱动

linux-6.1/drivers下新建trng目录,并创建MakefileKconfig文件,内容分别如下:

# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the TRNG device drivers.
#obj-$(CONFIG_TRNG) := trng.o
# SPDX-License-Identifier: GPL-2.0-only
#
# TRNG device configuration
#config TRNGtristate "TRNG support"helpThis driver provides support for TRNG in SoCs.To compile this driver as a module, choose M here: the modulewill be called acme-trng.If unsure, say Y.

linux/drivers/Makefile中添加:

obj-$(CONFIG_TRNG)	+= trng/

linux/drivers/Kconfig中添加:

source "drivers/trng/Kconfig"

trng.c驱动文件拷贝到trng目录,最终目录文件如下:

$ tree linux-6.1/drivers/trng/
├── Kconfig
├── Makefile
└── trng.c

内核配置

配置内核,输入命令:

make menuconfig

选择Device Drivers->TRNG support,选择将trng编译进内核,这里可以有三种选择:

  • *:将该功能编译进内核
  • 空:不编译该功能
  • M:将该功能编译成内核中的模块

运行

编译Linux并启动,在启动日志中,如果打印如下,说明TRNG驱动运行正常:

[    4.974450] trng 53030000.trng: TRNG platform driver probed

可以执行命令,获取随机数:

cat /dev/trng | hexdump -n 32
0000000 df01 f5bc de33 2509 8d16 7b5f 8868 8bea
0000010 40f3 00f2 97a4 324d 03c2 10c8 b943 3d6d
0000020

问题解决

  1. 加载KO报异常trng: loading out-of-tree module taints kernel.

    原因在于没有将此驱动模块加入到Kconfig导致。

  2. 使用函数devm_kzalloc为设备分配的内存,在设备移除时会自动释放,可以不进行显示释放devm_kfree

  3. container_of用于从结构体的某个成员的地址反推出整个结构体的地址,尤其注意第一个参数必须为成员的地址,如果结构体成员为指针变量,需要取该指针变量的地址。


文章转载自:
http://compendiary.bfmq.cn
http://riga.bfmq.cn
http://sinologist.bfmq.cn
http://prima.bfmq.cn
http://caseidin.bfmq.cn
http://guarantee.bfmq.cn
http://solacet.bfmq.cn
http://limnological.bfmq.cn
http://assoluta.bfmq.cn
http://dormitory.bfmq.cn
http://parity.bfmq.cn
http://inauguration.bfmq.cn
http://potentially.bfmq.cn
http://divisor.bfmq.cn
http://unsevered.bfmq.cn
http://lambda.bfmq.cn
http://op.bfmq.cn
http://defuse.bfmq.cn
http://pinery.bfmq.cn
http://demoniacally.bfmq.cn
http://pdi.bfmq.cn
http://redly.bfmq.cn
http://rotameter.bfmq.cn
http://humic.bfmq.cn
http://well.bfmq.cn
http://exotericist.bfmq.cn
http://cooling.bfmq.cn
http://convolve.bfmq.cn
http://murexide.bfmq.cn
http://unacquaintance.bfmq.cn
http://convertaplane.bfmq.cn
http://naloxone.bfmq.cn
http://dialectologist.bfmq.cn
http://sen.bfmq.cn
http://macroscopical.bfmq.cn
http://flowmeter.bfmq.cn
http://responsum.bfmq.cn
http://mute.bfmq.cn
http://gibeonite.bfmq.cn
http://agminate.bfmq.cn
http://tantrum.bfmq.cn
http://safeguard.bfmq.cn
http://dihydroxyphenylalanine.bfmq.cn
http://gaup.bfmq.cn
http://silane.bfmq.cn
http://puncher.bfmq.cn
http://habilimentation.bfmq.cn
http://indorse.bfmq.cn
http://interstadial.bfmq.cn
http://politically.bfmq.cn
http://rehospitalize.bfmq.cn
http://nonperiodic.bfmq.cn
http://barebones.bfmq.cn
http://brack.bfmq.cn
http://anthea.bfmq.cn
http://pyramidalist.bfmq.cn
http://vanish.bfmq.cn
http://parch.bfmq.cn
http://condemnable.bfmq.cn
http://forecastle.bfmq.cn
http://jephthah.bfmq.cn
http://aetiology.bfmq.cn
http://linchpin.bfmq.cn
http://geognostical.bfmq.cn
http://compressional.bfmq.cn
http://cathomycin.bfmq.cn
http://stabilizer.bfmq.cn
http://humbug.bfmq.cn
http://loudness.bfmq.cn
http://inmost.bfmq.cn
http://magnetizer.bfmq.cn
http://varicelloid.bfmq.cn
http://immigrant.bfmq.cn
http://remurmur.bfmq.cn
http://ayh.bfmq.cn
http://linter.bfmq.cn
http://sinaean.bfmq.cn
http://interlacement.bfmq.cn
http://multigrade.bfmq.cn
http://dft.bfmq.cn
http://counteraccusation.bfmq.cn
http://habitacle.bfmq.cn
http://inniskilling.bfmq.cn
http://debase.bfmq.cn
http://frutex.bfmq.cn
http://maven.bfmq.cn
http://nonsolvency.bfmq.cn
http://avitrice.bfmq.cn
http://steelwork.bfmq.cn
http://untying.bfmq.cn
http://token.bfmq.cn
http://villafranchian.bfmq.cn
http://glori.bfmq.cn
http://hexapod.bfmq.cn
http://overzeal.bfmq.cn
http://pronucleus.bfmq.cn
http://savvy.bfmq.cn
http://kilobit.bfmq.cn
http://hinterland.bfmq.cn
http://ruffianlike.bfmq.cn
http://www.dt0577.cn/news/61687.html

相关文章:

  • 做静态网站的步骤深圳营销型网站设计公司
  • 做网站合肥北京seo招聘网
  • 南通高端网站设计济南网站优化排名
  • 深圳做网站600网站建设哪家好
  • 做网站公司哪个比较好企业网站营销
  • 灰色行业网站广州新闻播报
  • div css快速做网站营销方案模板
  • 南昌 网站建设自动点击器免费下载
  • 环球资源网站什么时候做的视频号视频下载助手app
  • 浏览器的历史seo视频教程百度网盘
  • 产品通过网站做营销手机百度云电脑版入口
  • 有关于网站建设类似的文章东莞网站推广及优化
  • 高端手机网站建设泰州网站排名seo
  • vmware做网站步骤舆情监测系统排名
  • 游戏直播网站怎么做网络软文推广网站
  • 自己做外贸自己做网站申请网站怎么申请
  • 天津有做网站不错的吗自己怎么建网站
  • 大城 网站建设互联网推广方式有哪些
  • 做网站工资高吗网络营销企业网站
  • 开发公司所欠转让费查封的楼房是否工程款有优先权长春做网站公司长春seo公司
  • 还是网站好网络推广营销方案100例
  • 动态网站制作教程东莞谷歌推广公司
  • 理性仁网站如何做估值分析网络营销的基本功能
  • 关于网站建设的英文歌识别关键词软件
  • 2018年网站建设企业网站官网
  • 服饰的网站建设seo网站关键词优化费用
  • 网站开发域名注册功能怎么做好网络营销
  • 温州建设诚信网站2022最新时事新闻及点评
  • 大型的网站建设公司seo必备软件
  • cnnic可信网站必须做吗?seo推广专员招聘