Module: xenomai-abe
Branch: analogy
Commit: ab1559329229069ba7eb2dcf859b76dd16a4d738
URL:    
http://git.xenomai.org/?p=xenomai-abe.git;a=commit;h=ab1559329229069ba7eb2dcf859b76dd16a4d738

Author: Alexis Berlemont <alexis.berlem...@gmail.com>
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
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to