作者

QQ群:852283276
微信:arm80x86
微信公众号:青儿创客基地
B站:主页 https://space.bilibili.com/208826118

参考

当ZYNQ遇到Linux Userspace I/O(UIO)
The Userspace I/O HOWTO
Linux 设备驱动之 UIO 机制(测试 UIO 机制)
UIO 示例
Linux UIO

ubuntu 16.04.4 unknown symbol __uio_register_device

开发了一个pcie驱动,加载时,dmesg发现unknown symbol __uio_register_device,定位原因是insmod没有自动加载uio.ko,所以先执行modprobe uio

驱动开发

struct uio_info内容如下,

/**
 * 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);
};

struct uio_mem内容如下,

/**
 * struct uio_mem - description of a UIO memory region
 * @name:		name of the memory region for identification
 * @addr:		address of the device's memory (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)
 * @size:		size of IO
 * @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;
	resource_size_t		size;
	int			memtype;
	void __iomem		*internal_addr;
	struct uio_map		*map;
};

首先构造struct uio_info结构体,uio_irqhandler为中断处理函数,

uioinfo = &pdev_context->info;
uioinfo->name = "pcie_ep";
uioinfo->version = DRIVER_VERSION;
uioinfo->irq = pdev->irq;
uioinfo->irq_flags = IRQF_SHARED;
uioinfo->handler = uio_irqhandler;

struct uio_info填充struct uio_mem,下面将pcie的bar空间依次填入uio结构体,

uiomem = &uioinfo->mem[0];
for (i = 0; i < PCIE_EP_BAR_NUM; i++) {
	if (pci_resource_len(pdev, i) == 0) {
		continue;
	}
	if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
		dev_warn(&pdev->dev, "device has more than "
				__stringify(MAX_UIO_MAPS)
				" I/O memory resources.\n");
		break;
	}
	uiomem->memtype = UIO_MEM_PHYS;
	uiomem->addr = pci_resource_start(pdev, i);
	uiomem->size = pci_resource_len(pdev, i);
	uiomem->name = "pcie bar";
	++uiomem;
}

注册uio设备,

ret = uio_register_device(&pdev->dev, &pdev_context->info);
if (ret)
	goto error;

加载UIO驱动

修改设备树,将compatible节点改成“generic-uio”,有两种方法加载驱动,

  1. bootargs use“uio_pdrv_genirq.of_id=generic-uio”,可以通过DTS定义。
  2. insmod uio_pdrv_genirq.ko of_id=generic-uio
Logo

更多推荐