Sam Protsenk..
8
放弃
嗯,这是一个很好的架构问题,它暗示了一些关于硬件和所需用户空间接口的假设.因此,让我跳出结论进行更改,并尝试猜测哪种解决方案最适合您的情况.
设计
考虑到您未提及write()操作的帐户,我将进一步假设您的硬件始终在生成新数据.如果是这样,你提到的设计可能正是令你困惑的:
该read调用非常简单.它启动DMA写入,然后等待等待队列.
这正是阻止您以常规,常用(以及可能对您而言)方式使用驱动程序的原因.让我们开箱即用,首先想出用户界面(如何从用户空间使用你的驱动程序).下一个案例在这里常用且充足(从我的观点来看):
poll() 您的设备文件等待新数据到达
read() 您的设备文件以获取到达的数据
现在您可以看到请求(到DMA)的数据应该不是通过read()操作来启动的.正确的解决方案将是连续驾驶者读取数据(未经用户空间任何触发),并将其存储在内部,当用户请求你的驱动程序的数据消费(通过read()操作) -为用户提供内部存储的数据.如果驱动程序内部没有存储数据 - 用户可以使用poll()操作等待新数据到达.
正如您所看到的,这是众所周知的生产者 - 消费者问题.您可以使用循环缓冲区将硬件中的数据存储在驱动程序中(因此当缓冲区已满时故意丢失旧数据以防止缓冲区溢出情况).因此,生产者(DMA)写入该RX环形缓冲区的头部,而消费者(用户read()空间执行的用户)从该RX环形缓冲区的尾部读取.
代码参考
这一切情况让我想起了串行控制台 [ 1,2 ]的驱动程序.因此,请考虑在驱动程序实现中使用串行API(如果您的设备实际上是串行控制台).例如,请参阅drivers/tty/serial/atmel_serial.c驱动程序.我对UART API并不是很熟悉,所以我无法准确地告诉你那里发生了什么,但乍一看它看起来并不太难,所以可能你可以从那个代码中找到一两件事你的司机设计.
如果您的驱动程序不应使用Serial API,则可以使用下一个驱动程序进行引用:
补充
在评论中回答你的问题:
如果没有可用的数据并且应该阻止,你建议read打电话吗?pollread
首先,您想决定是否要提供:
阻止I/O.
或两者兼而有之
让我们假设(为了争论)你想在你的驱动程序中提供这两个选项.在这种情况下,open()如果flags参数包含O_NONBLOCK标志,则应检入呼叫.来自man 2 open:
O_NONBLOCK 要么 O_NDELAY
如果可能,文件以非阻塞模式打开.无论是open()也不在其返回将导致调用进程等待的文件描述符的任何后续操作.有关处理FIFO(命名管道)的信息,另请参阅fifo(7).有关O_NONBLOCK与强制文件锁和文件租约一起使用的效果的讨论,请参阅fcntl(2).
现在,当您了解用户选择的模式时,您可以执行下一步(在您的驱动程序中):
如果flagsin open()不包含此类标志,则可以执行阻塞read()(即,如果数据不可用,请等待DMA事务完成然后返回新数据).
但如果O_NONBLOCK在open()标志并没有在循环缓冲区可用数据-你应该返回read()调用与EWOULDBLOCK错误代码.
EAGAIN 要么 EWOULDBLOCK
文件描述符fd引用套接字并且已标记为nonblocking(O_NONBLOCK),并且读取将阻塞.POSIX.1-2001允许在这种情况下返回错误,并且不要求这些常量具有相同的值,因此便携式应用程序应检查这两种可能性.
您还可以阅读下一篇文章,以便更好地掌握相应的界面:
补充2
我需要某种后台任务,不断从设备读取并填充环形缓冲区.poll现在是微不足道的 - 只是检查缓冲区中是否有任何东西,但read更难,因为它可能需要等待将某些内容发布到环形缓冲区.
在poll()函数中:do poll_wait()(等待新数据到达)
在接收数据中断处理程序中:do wake_up_interruptible()(唤醒poll和read操作)
在read()函数中:
如果端口没有数据:
如果O_NONBLOCK设置了标志(在open()操作中):return -EAGAIN= -EWOULDBLOCK立即
否则我们有阻塞读取:wait_event_freezable()等待新数据到达
如果端口有数据:从缓冲区返回数据