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

lau*_*ote 6 c embedded asynchronous spi linux-device-driver

我正在维护一些通过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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

真的很喜欢在轮询和睡眠的基于事件的解决方案.首先想到的是在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);
}
Run Code Online (Sandbox Code Playgroud)

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

saw*_*ust 2

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

否。
spidev文档指出

At this time there is no async I/O support; everything is purely synchronous.
Run Code Online (Sandbox Code Playgroud)

更重要的是,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 };
Run Code Online (Sandbox Code Playgroud)