我正在维护一些通过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
}
}
}
与轮询和 sleep 相比,我真的更喜欢基于事件的解决方案。首先想到的是在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吗? 它会像永远/永远不会“准备阅读” 那样愚蠢吗?可以使其表现为我想要的方式吗?是否依赖于硬件?如果必要的话,我不反对小小的内核驱动程序黑客攻击,但我不确定是否需要查找。
最佳答案
At this time there is no async I/O support; everything is purely synchronous.
更重要的是,spidev driver不支持轮询文件操作。 select()系统调用要求设备驱动程序支持民意调查。
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 };