[Xenomai-git] Alexis Berlemont : analogy: add comments in the buffer management code
Module: xenomai-head Branch: master Commit: ab1559329229069ba7eb2dcf859b76dd16a4d738 URL: http://git.xenomai.org/?p=xenomai-head.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
[Xenomai-git] Alexis Berlemont : analogy: add comments in the buffer management code
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 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
[Xenomai-git] Alexis Berlemont : analogy: add comments in the buffer management code
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
[Xenomai-git] Alexis Berlemont : analogy: add comments in the buffer management code
Module: xenomai-abe Branch: analogy Commit: 9da7e5d12f9725a477b23ce4bfcec93346e0bfb2 URL: http://git.xenomai.org/?p=xenomai-abe.git;a=commit;h=9da7e5d12f9725a477b23ce4bfcec93346e0bfb2 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
[Xenomai-git] Alexis Berlemont : analogy: add comments in the buffer management code
Module: xenomai-head Branch: master Commit: 14bdb1d1e4334f0e6b0e9c3e8ba1ccb8669ef092 URL: http://git.xenomai.org/?p=xenomai-head.git;a=commit;h=14bdb1d1e4334f0e6b0e9c3e8ba1ccb8669ef092 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