繁体   English   中英

我可以在/ dev / spidev文件描述符上选择()吗?

[英]Can I select() on a /dev/spidev file descriptor?

我正在维护一些通过SPI与FPGA通信的用户空间代码。 现在正在轮询,看看是否有数据可以采取行动,我并不感到兴奋。 comm线程的(大大简化)结构如下所示:

int spi_fd;

void do_transfer(char *buf, int len)
{
    struct spi_ioc_transfer xfer;
    memset(xfer, 0, sizeof(xfer));

    ioctl_tell_some_fpga_register_heads_up();

    xfer[0].len = len;
    xfer[0].tx_buf = NULL;
    xfer[0].rx_buf = buf;
    ioctl(spi_fd, SPI_IOC_MESSAGE(1), xfer);

    ioctl_tell_some_fpga_register_were_done();
}

void *comm_thread(void arg)
{
    uint8_t config = SPI_MODE_3;
    __u32 speed = 4000000;
    char buffer[5120];

    spi_fd = open("/dev/spidev1.0", O_RDWR);
    ioctl(spi_fd, SPI_IOC_WR_MODE, &config);
    ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

    while(1) {
        sleep(2); //ugh
        if(ioctl_read_some_fpga_register_that_says_if_theres_data())
        {
            do_transfer(buffer, some_small_number_of_bytes());
            do_stuff(buffer); //you get the picture
        }
    }
}

真的很喜欢在轮询和睡眠的基于事件的解决方案。 首先想到的是在spidev文件描述符上执行select()而不是每X秒检查一次寄存器,类似于

fd_set myset;

while(1) {
    FD_ZERO(&myset);
    FD_SET(spi_fd, &myset);
    select(spi_fd + 1, &myset, NULL, NULL, NULL);
    do_transfer(buffer, some_small_number_of_bytes());
    do_stuff(buffer);
}

事情是我找不到像这样处理SPI的人的任何例子,我想知道是否有一个很好的理由。 可以这样使用/ dev / spidev吗? 它会像往常一样愚蠢/永远不会“准备好阅读”吗? 是否可以做出的行为就是我想要的? 它是硬件依赖的吗? 如果有必要的话,我不反对一个小内核驱动程序黑客,但我不确定我是否需要在哪里寻找。

我可以在/ dev / spidev文件描述符上选择()吗?

没有。
spidev文档说明

At this time there is no async I/O support; everything is purely synchronous.

更重要的是, spidev驱动程序不支持轮询文件操作。 select()系统调用要求设备驱动程序支持poll fops。

670 static const struct file_operations spidev_fops = {
671         .owner =        THIS_MODULE,
672         /* REVISIT switch to aio primitives, so that userspace
673          * gets more complete API coverage.  It'll simplify things
674          * too, except for the locking.
675          */
676         .write =        spidev_write,
677         .read =         spidev_read,
678         .unlocked_ioctl = spidev_ioctl,
679         .compat_ioctl = spidev_compat_ioctl,
680         .open =         spidev_open,
681         .release =      spidev_release,
682         .llseek =       no_llseek,
683 };

即使在此之前,这可能是Linux SPI驱动程序的问题,您还必须了解如何从FPGA获取状态信息。

除非FPGA正在执行诸如驱动中断或关注线之类的操作,否则SPI主控制器(可能连接到CPU)将不得不执行SPI操作来轮询FPGA。 因此,除非或者直到你在内核空间中有代码周期性地进行轮询,否则驱动程序中没有可用的信息可供用户空间有意义地选择()。

如果你从FPGA获得一个注意信号回到处理器(这取决于是否有其他任何东西共享它,可能就像驱动MISO一样简单)那么你可能会把它监视为内核中的一个中断SPI驱动程序,或单独使用用户空间中断接口,您可以在其上选择()。

如果没有,您将不得不评估通过SPI将状态轮询移动到自定义内核驱动程序中的权衡,而不是将其留在用户空间中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM