Linux Device Driver Buffering Strategy

Suppose I have an external device that constantly pushes data into a small buffer in my driver. I use the wait queue, where the interrupt handler wakes up the waiting user process (similar to LDD (3rd edition) - the implementation of the handler).

irq_handler_t irq_handler(int irq, void *dev_id, struct pt_regs *regs) { flag = 1; wake_up_interruptible(&wq); return IRQ_HANDLED; } ssize_t my_read(struct file *dev, char __user *buf, size_t count, loff_t *f_pos) { wait_event_interruptible(wq, flag != 0); flag = 0; copy_to_user(usr_buf, drv_buf, count); } /***********************User program***********************/ while(1) { read(fid, buffer, size); //do stuff with data } 

The user program calls read and waits until the interrupt receives new data from the external device. Since an external device can push data faster than it can execute code, what mechanisms can I use to ensure that the data is not overwritten before the user program copies it? Will a ring buffer such as a structure work here? It is unclear how to implement it.

thanks

+5
source share
1 answer

Yes, the buffer buffer will work.

You just need to fill the buffer from the interrupt handler, and you will read it from the my_read .

A truly naive and really really ineffective implementation can be (untested):

 static irqreturn_t irq_handler(int irq, void *dev_id) { struct my_dev *dev = dev_id; buf[buf_wr] = read_device(dev); buf_wr++; if (buf_wr >= BUFSIZE) buf_wr = 0; wake_up(&wq); return IRQ_HANDLED; } static ssize_t my_read(struct file *file, char __user *ubuf, size_t sz, loff_t *ppos) { int n, ret; ret = wait_event_interruptible(wq, buf_wr != buf_rd); if (ret) return ret; n = buf_wr - buf_rd; if (n < 0) n += BUFSIZE; n = min(count, n); ret = copy_to_user(ubuf, buf, n); buf_rd += n; if (buf_rd >= BUFSIZE) buf_rd -= BUFSIZE; if (ret) return ret; *ppos += n; return 1; } 

You can also use DMA or mmap or both to get something more efficient.

+2
source

Source: https://habr.com/ru/post/1263523/


All Articles