微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

mmap IO 端口地址为串口

如何解决mmap IO 端口地址为串口

我正在检查串口 (uart) 0x2f8 的 io 端口地址是否可以映射到用户空间。 我想在驱动程序中自己做这件事,而不是使用任何库来知道需要哪些 api 来实现这一点。但是,我不确定它是否真的可以完成,因为这是 x86 和端口 IO 特定的。无论如何,我已经在用户空间中编写了一个 mmap 函数调用者。

Setting up the mapping is as below:
res = request_region(base_addr,8,"custom_serial_device");
void __iomem * mem_base_addr = ioport_map(base_addr,8);
iowrite8(0x01,(u8 *)my_dev->mem_base_addr + 3); /*Few more configs and works fine */
/* After this I am able to make the uart function in software loopback mode */

现在我决定在这个地址上尝试 mmap:

static int my_dev_mmap(struct file *filep,struct vm_area_struct *vma) {
    SERIAL_DEV *my_dev = (SERIAL_DEV*)filep->private_data;
    unsigned long pfn;
    size_t sz = vma->vm_end - vma->vm_start;
    unsigned long phys_addr;

    if (vma->vm_end - vma->vm_start != PAGE_SIZE) {
            return -EINVAL;
    }
    if (PAGE_SIZE > (1 << 16))
            return -ENOSYS;

    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    vma->vm_flags |= VM_IO;
    /*ioport_map gives virtual address so I am using below to get physical addr */
    phys_addr = virt_to_phys(my_dev->mem_base_addr);
    pfn = phys_addr >> PAGE_SHIFT;
    printk("GNA: mmap called: vm-start: 0x%lx vm-end: 0x%lx mem_base: 0x%lx phys: 0x%lx pfn: %lu\n",vma->vm_start,vma->vm_end,(unsigned long)my_dev->mem_base_addr,phys_addr,pfn);

    if (remap_pfn_range(vma,pfn,sz,vma->vm_page_prot)) {
            printk("GNA: mmap Failed\n");
            return -EAGAIN;
    }
        return 0;
}

我得到的打印如下:

Dec 19 11:05:00 realtek-dpdk kernel: [ 4624.894086] GNA: mmap called: 
vm-start: 0x7fa150f4d000  --> Kernel allocates this range which is in user space 
vm-end: 0x7fa150f4e000 
mem_base: 0x102f8 
phys: 0x6587800102f8    --> Virt_to_phys gave this which seems wrong
pfn: 27254063120

当我打印 mmap'd 内存时,我期望在 0x2f8(uart 的基数)偏移 0x7(便笺本)处有 0x5A。但是我没有看到预期的输出

我试过的另一种方法是ioport_map给出的地址是0x102f8,好像没有 像虚拟地址,但更多的是物理地址(BASE + 0x2f8) 所以,我直接用这个地址来获取pfn。但结果还是一样。

我的用户空间程序如下:

address = mmap(NULL,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,configfd,0);

在此之后,我试图找到写入暂存器内存偏移量 0x7 处的值。

for (int i = 0 ; i < 10; i++) {
    printf("Value: 0x%x 0x%x\n",address[i],address[0x2f8 + i]);
}

那么,是否可以 mmap() 一个 ioport。如果是,请您说出正确的步骤。

PS:虽然这是 x86,但我添加了嵌入式 linux 标签,以便从平台方面获得一些帮助,以防万一有人知道其中的区别。

解决方法

注意:这个答案是特定于 x86 的。

通过 IN 和 OUT 指令访问 I/O 端口。

应该可以映射驱动程序管理的反弹缓冲区,并使用这些指令将其写入串行。您可能需要编写一个用于同步的接口(例如刷新 ioctl)。

与您可以使用基于 MMIO 的设备所做的不同,您将无法粗略地将接触设备的内存直接映射到用户空间,因为该内存不存在。

您可以尝试设置 I/O 端口权限,以便用户空间可以访问 I/O 端口本身。 ioperm 系统调用(也可能是其他系统调用)管理这个。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。