linux UIO驱动实践 您所在的位置:网站首页 tableview滚动到指定位置cell一点就偏差 linux UIO驱动实践

linux UIO驱动实践

2023-03-14 01:54| 来源: 网络整理| 查看: 265

linux UIO驱动实践 环境搭建platform 设备驱动UIO驱动

环境搭建

Ubuntu20地址 虚拟机安装与配置见博客开头:驱动虚拟环境搭建记录

一直以为用镜像直接安装的Ubuntu没有内核源码,不能用来编译驱动,只能由源码编译内核后切换内核才能进行驱动的编译,没想到一安装完就可以编译了,错误的印象。 用hello world测试环境是否搭建成功

#include #include MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Hcamal"); int hello_init(void) { printk(KERN_INFO "Hello World\n"); return 0; } void hello_exit(void) { printk(KERN_INFO "Goodbye World\n"); } module_init(hello_init); module_exit(hello_exit); obj-m+=hello.o all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean platform 设备驱动

本来想直接编译运行Linux UIO驱动实例介绍的代码看一下效果,但遇到了一些问题: Skipping BTF generation for /root/driver/test/hello.ko due to unavailability of vmlinux

移动/sys/kernel/btf/vmlinux至/lib/modules/$(shell uname -r)/build/目录 Skipping BTF generation xxx. due to unavailability of vmlinux on Ubuntu 21.04

[ 6657.847233] hello: Unknown symbol __uio_register_device (err -2) [ 6657.847260] hello: Unknown symbol uio_unregister_device (err -2)

运行modprobe uio 安装驱动错误 Unknown symbol __uio_register_device (err -2)

Driver ‘test’ needs updating - please use bus_type methods 在这里插入图片描述 linux设备驱动(3)devive_driver 详解

想了想,还是自己写一个简单的demo,加深一下印象。由于没有实际的物理设备,为了触发驱动的探测函数,就需要借助platform设备与platform驱动。推荐博客: Linux 设备驱动开发 —— platform 设备驱动 Linux platform device driver and design platform_driver——dm9000.c platform_device——board-dm355-evm.c

hello world demo如下:

#include #include #define DRV_NAME "test" static int drv_probe(struct platform_device *pdev) { printk("call probe function dev name is:%s\n", pdev->name); return 0; } static int drv_remove(struct platform_device *pdev) { printk("call remove function dev name is:%s\n", pdev->name); return 0; } static struct platform_device *test_device; static struct platform_driver test_driver = { .driver = { .name = DRV_NAME, }, .probe = drv_probe, .remove = drv_remove, }; static int __init test_init(void) { test_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); return platform_driver_register(&test_driver); } static void __exit test_exit(void) { platform_device_unregister(test_device); platform_driver_unregister(&test_driver); } MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("test driver"); module_init(test_init); module_exit(test_exit);

在这里插入图片描述 相关函数与结构体

struct platform_device { const char *name; int id; bool id_auto; struct device dev; u64 platform_dma_mask; struct device_dma_parameters dma_parms; u32 num_resources; struct resource *resource; const struct platform_device_id *id_entry; /* * Driver name to force a match. Do not set directly, because core * frees it. Use driver_set_override() to set or clear it. */ const char *driver_override; /* MFD cell pointer */ struct mfd_cell *mfd_cell; /* arch specific additions */ struct pdev_archdata archdata; }; struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; bool prevent_deferred_probe; /* * For most device drivers, no need to care about this flag as long as * all DMAs are handled through the kernel DMA API. For some special * ones, for example VFIO drivers, they know how to manage the DMA * themselves and set this flag so that the IOMMU layer will allow them * to setup and manage their own I/O address space. */ bool driver_managed_dma; }; /** * platform_device_register_simple - add a platform-level device and its resources * @name: base name of the device we're adding * @id: instance id * @res: set of resources that needs to be allocated for the device * @num: number of resources * * This function creates a simple platform device that requires minimal * resource and memory management. Canned release function freeing memory * allocated for the device allows drivers using such devices to be * unloaded without waiting for the last reference to the device to be * dropped. * * This interface is primarily intended for use with legacy drivers which * probe hardware directly. Because such drivers create sysfs device nodes * themselves, rather than letting system infrastructure handle such device * enumeration tasks, they don't fully conform to the Linux driver model. * In particular, when such drivers are built as modules, they can't be * "hotplugged". * * Returns &struct platform_device pointer on success, or ERR_PTR() on error. */ static inline struct platform_device *platform_device_register_simple( const char *name, int id, const struct resource *res, unsigned int num) { return platform_device_register_resndata(NULL, name, id, res, num, NULL, 0); } UIO驱动

代码主体仍然来自于Linux UIO驱动实例介绍,只不过为了简洁,忽略错误处理代码 驱动代码

#include #include #include #include #define DRV_NAME "test" #define MEMORY_SIZE (1 printk("call probe function dev name is:%s\n", pdev->name); struct device *dev = &pdev->dev; void *p = kmalloc(MEMORY_SIZE, GFP_KERNEL); // 申请内存空间 strcpy(p, "123456"); // 写入一些数据 test_info.mem[0].name = "area1"; test_info.mem[0].addr = (unsigned long)p; test_info.mem[0].memtype = UIO_MEM_LOGICAL; test_info.mem[0].size = MEMORY_SIZE; uio_register_device(dev, &test_info); return 0; } static int drv_remove(struct platform_device *pdev) { printk("call remove function dev name is:%s\n", pdev->name); printk("memory data:%s\n", test_info.mem[0].addr); // 输出内存数据 uio_unregister_device(&test_info); return 0; } static struct platform_device *test_device; static struct platform_driver test_driver = { .driver = { .name = DRV_NAME, }, .probe = drv_probe, .remove = drv_remove, }; static int __init test_init(void) { test_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); return platform_driver_register(&test_driver); } static void __exit test_exit(void) { platform_device_unregister(test_device); platform_driver_unregister(&test_driver); } MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("test driver"); module_init(test_init); module_exit(test_exit);

相较于platform的demo,只是加入了一些uio_info相关的代码,函数构成一致。 用户程序

#include #include #include #include #include #include #include #define UIO_DEV "/dev/uio0" #define UIO_ADDR "/sys/class/uio/uio0/maps/map0/addr" #define UIO_SIZE "/sys/class/uio/uio0/maps/map0/size" int main(void) { int uio_fd, addr_fd, size_fd; char uio_addr_buf[16], uio_size_buf[16]; int uio_size; void *uio_addr, *access_address; uio_fd = open(UIO_DEV, O_RDWR); addr_fd = open(UIO_ADDR, O_RDONLY); // 起始地址 size_fd = open(UIO_SIZE, O_RDONLY); // 内存大小 read(addr_fd, uio_addr_buf, sizeof(uio_addr_buf)); read(size_fd, uio_size_buf, sizeof(uio_size_buf)); uio_addr = (void *)strtoul(uio_addr_buf, NULL, 0); uio_size = (int)strtol(uio_size_buf, NULL, 0); access_address = mmap(NULL, uio_size, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, 0); // 进行mmap映射 printf("memory data:%s\n", access_address); // 读取内存数据 strcpy(access_address, "00000000"); // 写入内存数据 printf("memory data:%s\n", access_address); // 再次读取内存数据 return 0; }

用户代码首先读取内存数据,而后写入一些数据,驱动在设备移除函数中读取内存数据,验证用户程序是否成功写入

驱动在drv_probe中写入123456 用户程序读取内存,得到123456 用户程序写入00000000 驱动在drv_remove中读到00000000

在这里插入图片描述

root@driver-virtual-machine ~/d/test# tree /sys/class/uio/uio0/ /sys/class/uio/uio0/ ├── dev ├── device -> ../../../test ├── event ├── maps │ └── map0 │ ├── addr │ ├── name │ ├── offset │ └── size ├── name ├── power │ ├── async │ ├── autosuspend_delay_ms │ ├── control │ ├── runtime_active_kids │ ├── runtime_active_time │ ├── runtime_enabled │ ├── runtime_status │ ├── runtime_suspended_time │ └── runtime_usage ├── subsystem -> ../../../../../class/uio ├── uevent └── version 5 directories, 18 files root@driver-virtual-machine ~/d/test# cat /sys/class/uio/uio0/name test_uio root@driver-virtual-machine ~/d/test# cat /sys/class/uio/uio0/version 1.0 root@driver-virtual-machine ~/d/test# cat /sys/class/uio/uio0/maps/map0/addr 0xffff9c2f5380c000 root@driver-virtual-machine ~/d/test# cat /sys/class/uio/uio0/maps/map0/name area1 root@driver-virtual-machine ~/d/test# cat /sys/class/uio/uio0/maps/map0/size 0x0000000000001000

相关函数与结构体

/* defines for uio_info->irq */ #define UIO_IRQ_CUSTOM -1 #define UIO_IRQ_NONE 0 /* defines for uio_mem->memtype */ #define UIO_MEM_NONE 0 #define UIO_MEM_PHYS 1 #define UIO_MEM_LOGICAL 2 #define UIO_MEM_VIRTUAL 3 #define UIO_MEM_IOVA 4 /* defines for uio_port->porttype */ #define UIO_PORT_NONE 0 #define UIO_PORT_X86 1 #define UIO_PORT_GPIO 2 #define UIO_PORT_OTHER 3 /** * struct uio_mem - description of a UIO memory region * @name: name of the memory region for identification * @addr: address of the device's memory rounded to page * size (phys_addr is used since addr can be * logical, virtual, or physical & phys_addr_t * should always be large enough to handle any of * the address types) * @offs: offset of device memory within the page * @size: size of IO (multiple of page size) * @memtype: type of memory addr points to * @internal_addr: ioremap-ped version of addr, for driver internal use * @map: for use by the UIO core only. */ struct uio_mem { const char *name; phys_addr_t addr; unsigned long offs; resource_size_t size; int memtype; void __iomem *internal_addr; struct uio_map *map; }; /** * struct uio_info - UIO device capabilities * @uio_dev: the UIO device this info belongs to * @name: device name * @version: device driver version * @mem: list of mappable memory regions, size==0 for end of list * @port: list of port regions, size==0 for end of list * @irq: interrupt number or UIO_IRQ_CUSTOM * @irq_flags: flags for request_irq() * @priv: optional private data * @handler: the device's irq handler * @mmap: mmap operation for this uio device * @open: open operation for this uio device * @release: release operation for this uio device * @irqcontrol: disable/enable irqs when 0/1 is written to /dev/uioX */ struct uio_info { struct uio_device *uio_dev; const char *name; const char *version; struct uio_mem mem[MAX_UIO_MAPS]; struct uio_port port[MAX_UIO_PORT_REGIONS]; long irq; unsigned long irq_flags; void *priv; irqreturn_t (*handler)(int irq, struct uio_info *dev_info); int (*mmap)(struct uio_info *info, struct vm_area_struct *vma); int (*open)(struct uio_info *info, struct inode *inode); int (*release)(struct uio_info *info, struct inode *inode); int (*irqcontrol)(struct uio_info *info, s32 irq_on); };

drivers-session3-uio-4public.pdf



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有