Module: xenomai-2.5 Branch: master Commit: ab1559329229069ba7eb2dcf859b76dd16a4d738 URL: http://git.xenomai.org/?p=xenomai-2.5.git;a=commit;h=ab1559329229069ba7eb2dcf859b76dd16a4d738
Author: Alexis Berlemont <[email protected]> Date: Wed Jul 21 00:22:46 2010 +0200 analogy: add comments in the buffer management code --- include/analogy/buffer.h | 52 ++++++++++++++++++++++++++++++++++++---- ksrc/drivers/analogy/buffer.c | 23 +++++++++++++++++- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/include/analogy/buffer.h b/include/analogy/buffer.h index 9e5ae8a..b5be3f0 100644 --- a/include/analogy/buffer.h +++ b/include/analogy/buffer.h @@ -90,9 +90,12 @@ struct a4l_buffer { }; typedef struct a4l_buffer a4l_buf_t; -/* Static inline Buffer related functions */ +/* --- Static inline functions related with + user<->kernel data transfers --- */ -/* Produce memcpy function */ +/* The function __produce is an inline function which copies data into + the asynchronous buffer and takes care of the non-contiguous issue + when looping. This function is used in read and write operations */ static inline int __produce(a4l_cxt_t *cxt, a4l_buf_t *buf, void *pin, unsigned long count) { @@ -122,7 +125,9 @@ static inline int __produce(a4l_cxt_t *cxt, return ret; } -/* Consume memcpy function */ +/* The function __consume is an inline function which copies data from + the asynchronous buffer and takes care of the non-contiguous issue + when looping. This function is used in read and write operations */ static inline int __consume(a4l_cxt_t *cxt, a4l_buf_t *buf, void *pout, unsigned long count) { @@ -153,7 +158,9 @@ static inline int __consume(a4l_cxt_t *cxt, return ret; } -/* Munge procedure */ +/* The function __munge is an inline function which calls the + subdevice specific munge callback on contiguous windows within the + whole buffer. This function is used in read and write operations */ static inline void __munge(struct a4l_subdevice * subd, void (*munge) (struct a4l_subdevice *, void *, unsigned long), @@ -176,7 +183,9 @@ static inline void __munge(struct a4l_subdevice * subd, } } -/* Event consumption function */ +/* The function __handle_event can only be called from process context + (not interrupt service routine). It allows the client process to + retrieve the buffer status which has been updated by the driver */ static inline int __handle_event(a4l_buf_t * buf) { int ret = 0; @@ -194,7 +203,38 @@ static inline int __handle_event(a4l_buf_t * buf) return ret; } -/* Counters management functions */ +/* --- Counters management functions --- */ + +/* Here, we may wonder why we need more than two counters / pointers. + + Theoretically, we only need two counters (or two pointers): + - one which tells where the reader should be within the buffer + - one which tells where the writer should be within the buffer + + With these two counters (or pointers), we just have to check that + the writer does not overtake the reader inside the ring buffer + BEFORE any read / write operations. + + However, if one element is a DMA controller, we have to be more + careful. Generally a DMA transfer occurs like this: + DMA shot + |-> then DMA interrupt + |-> then DMA soft handler which checks the counter + + So, the checkings occur AFTER the write operations. + + Let's take an example: the reader is a software task and the writer + is a DMA controller. At the end of the DMA shot, the write counter + is higher than the read counter. Unfortunately, a read operation + occurs between the DMA shot and the DMA interrupt, so the handler + will not notice that an overflow occured. + + That is why tmp_count comes into play: tmp_count records the + read/consumer current counter before the next DMA shot and once the + next DMA shot is done, we check that the updated writer/producer + counter is not higher than tmp_count. Thus we are sure that the DMA + writer has not overtaken the reader because it was not able to + overtake the n-1 value. */ static inline int __pre_abs_put(a4l_buf_t * buf, unsigned long count) { diff --git a/ksrc/drivers/analogy/buffer.c b/ksrc/drivers/analogy/buffer.c index f9bcad7..8bd7d38 100644 --- a/ksrc/drivers/analogy/buffer.c +++ b/ksrc/drivers/analogy/buffer.c @@ -35,7 +35,11 @@ /* --- Initialization functions (init, alloc, free) --- */ -void a4l_free_buffer(a4l_buf_t *buf_desc) +/* The buffer charactistic is very close to the Comedi one: it is + allocated with vmalloc() and all physical addresses of the pages which + compose the virtual buffer are hold in a table */ + +void a4l_free_buffer(a4l_buf_t * buf_desc) { if (buf_desc->pg_list != NULL) { rtdm_free(buf_desc->pg_list); @@ -249,6 +253,9 @@ int a4l_get_chan(a4l_subd_t *subd) /* --- Transfer / copy functions --- */ +/* The following functions are explained in the Doxygen section + "Buffer management services" in driver_facilities.c */ + int a4l_buf_prepare_absput(a4l_subd_t *subd, unsigned long count) { a4l_buf_t *buf = subd->buf; @@ -563,6 +570,10 @@ int a4l_ioctl_cancel(a4l_cxt_t * cxt, void *arg) return a4l_cancel_buffer(cxt); } +/* The ioctl BUFCFG is only useful for changing the size of the + asynchronous buffer. + (BUFCFG = free of the current buffer + allocation of a new one) */ + int a4l_ioctl_bufcfg(a4l_cxt_t * cxt, void *arg) { a4l_dev_t *dev = a4l_get_dev(cxt); @@ -610,6 +621,10 @@ int a4l_ioctl_bufcfg(a4l_cxt_t * cxt, void *arg) return a4l_alloc_buffer(buf, buf_cfg.buf_size); } +/* The BUFINFO ioctl provides two basic roles: + - tell the user app the size of the asynchronous buffer + - display the read/write counters (how many bytes to read/write) */ + int a4l_ioctl_bufinfo(a4l_cxt_t * cxt, void *arg) { a4l_dev_t *dev = a4l_get_dev(cxt); @@ -715,6 +730,9 @@ a4l_ioctl_bufinfo_out: return 0; } +/* The function a4l_read_buffer can be considered as the kernel entry + point of the RTDM syscall read. This syscall is supposed to be used + only during asynchronous acquisitions */ ssize_t a4l_read_buffer(a4l_cxt_t * cxt, void *bufdata, size_t nbytes) { a4l_dev_t *dev = a4l_get_dev(cxt); @@ -814,6 +832,9 @@ out_a4l_read: return count; } +/* The function a4l_write_buffer can be considered as the kernel entry + point of the RTDM syscall write. This syscall is supposed to be + used only during asynchronous acquisitions */ ssize_t a4l_write_buffer(a4l_cxt_t *cxt, const void *bufdata, size_t nbytes) { a4l_dev_t *dev = a4l_get_dev(cxt); _______________________________________________ Xenomai-git mailing list [email protected] https://mail.gna.org/listinfo/xenomai-git
