Linux驱动开发之uio驱动
参考当ZYNQ遇到Linux Userspace I/O(UIO)加载UIO驱动bootargs use“uio_pdrv_genirq.of_id=generic-uio”,可以通过DTS定义。insmod uio_pdrv_genirq.ko of_id=generic-uio
·
作者
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”
,有两种方法加载驱动,
- bootargs use“uio_pdrv_genirq.of_id=generic-uio”,可以通过DTS定义。
- insmod uio_pdrv_genirq.ko of_id=generic-uio
更多推荐
已为社区贡献9条内容
所有评论(0)