• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

include/analogy/buffer.h

Go to the documentation of this file.
00001 
00023 #ifndef __ANALOGY_BUFFER_H__
00024 #define __ANALOGY_BUFFER_H__
00025 
00026 #ifndef DOXYGEN_CPP
00027 
00028 #ifdef __KERNEL__
00029 
00030 #include <linux/version.h>
00031 #include <linux/mm.h>
00032 
00033 #include <rtdm/rtdm_driver.h>
00034 
00035 #include <analogy/os_facilities.h>
00036 #include <analogy/context.h>
00037 
00038 /* --- Events bits / flags --- */
00039 
00040 #define A4L_BUF_EOBUF_NR 0
00041 #define A4L_BUF_EOBUF (1 << A4L_BUF_EOBUF_NR)
00042 
00043 #define A4L_BUF_ERROR_NR 1
00044 #define A4L_BUF_ERROR (1 << A4L_BUF_ERROR_NR)
00045 
00046 #define A4L_BUF_EOA_NR 2
00047 #define A4L_BUF_EOA (1 << A4L_BUF_EOA_NR)
00048 
00049 /* --- Status bits / flags --- */
00050 
00051 #define A4L_BUF_BULK_NR 8
00052 #define A4L_BUF_BULK (1 << A4L_BUF_BULK_NR)
00053 
00054 #define A4L_BUF_MAP_NR 9
00055 #define A4L_BUF_MAP (1 << A4L_BUF_MAP_NR)
00056 
00057 struct a4l_subdevice;
00058 
00059 /* Buffer descriptor structure */
00060 struct a4l_buffer {
00061 
00062         /* Added by the structure update */
00063         struct a4l_subdevice *subd;
00064 
00065         /* Buffer's first virtual page pointer */
00066         void *buf;
00067 
00068         /* Buffer's global size */
00069         unsigned long size;
00070         /* Tab containing buffer's pages pointers */
00071         unsigned long *pg_list;
00072 
00073         /* RT/NRT synchronization element */
00074         a4l_sync_t sync;
00075 
00076         /* Counters needed for transfer */
00077         unsigned long end_count;
00078         unsigned long prd_count;
00079         unsigned long cns_count;
00080         unsigned long tmp_count;
00081 
00082         /* Status + events occuring during transfer */
00083         unsigned long flags;
00084 
00085         /* Command on progress */
00086         a4l_cmd_t *cur_cmd;
00087 
00088         /* Munge counter */
00089         unsigned long mng_count;
00090 
00091         /* Theshold below which the user process should not be
00092            awakened */
00093         unsigned long wake_count;
00094 };
00095 typedef struct a4l_buffer a4l_buf_t;
00096 
00097 /* --- Static inline functions related with
00098    user<->kernel data transfers --- */
00099 
00100 /* The function __produce is an inline function which copies data into
00101    the asynchronous buffer and takes care of the non-contiguous issue
00102    when looping. This function is used in read and write operations */
00103 static inline int __produce(a4l_cxt_t *cxt,
00104                             a4l_buf_t *buf, void *pin, unsigned long count)
00105 {
00106         unsigned long start_ptr = (buf->prd_count % buf->size);
00107         unsigned long tmp_cnt = count;
00108         int ret = 0;
00109 
00110         while (ret == 0 && tmp_cnt != 0) {
00111                 /* Check the data copy can be performed contiguously */
00112                 unsigned long blk_size = (start_ptr + tmp_cnt > buf->size) ?
00113                         buf->size - start_ptr : tmp_cnt;
00114 
00115                 /* Perform the copy */
00116                 if (cxt == NULL)
00117                         memcpy(buf->buf + start_ptr, pin, blk_size);
00118                 else
00119                         ret = rtdm_safe_copy_from_user(cxt->user_info,
00120                                                        buf->buf + start_ptr,
00121                                                        pin, blk_size);
00122 
00123                 /* Update pointers/counts */
00124                 pin += blk_size;
00125                 tmp_cnt -= blk_size;
00126                 start_ptr = 0;
00127         }
00128 
00129         return ret;
00130 }
00131 
00132 /* The function __consume is an inline function which copies data from
00133    the asynchronous buffer and takes care of the non-contiguous issue
00134    when looping. This function is used in read and write operations */
00135 static inline int __consume(a4l_cxt_t *cxt,
00136                             a4l_buf_t *buf, void *pout, unsigned long count)
00137 {
00138         unsigned long start_ptr = (buf->cns_count % buf->size);
00139         unsigned long tmp_cnt = count;
00140         int ret = 0;
00141 
00142         while (ret == 0 && tmp_cnt != 0) {
00143                 /* Check the data copy can be performed contiguously */
00144                 unsigned long blk_size = (start_ptr + tmp_cnt > buf->size) ?
00145                         buf->size - start_ptr : tmp_cnt;
00146 
00147                 /* Perform the copy */
00148                 if (cxt == NULL)
00149                         memcpy(pout, buf->buf + start_ptr, blk_size);
00150                 else
00151                         ret = rtdm_safe_copy_to_user(cxt->user_info,
00152                                                      pout,
00153                                                      buf->buf + start_ptr,
00154                                                      blk_size);
00155 
00156                 /* Update pointers/counts */
00157                 pout += blk_size;
00158                 tmp_cnt -= blk_size;
00159                 start_ptr = 0;
00160         }
00161 
00162         return ret;
00163 }
00164 
00165 /* The function __munge is an inline function which calls the
00166    subdevice specific munge callback on contiguous windows within the
00167    whole buffer. This function is used in read and write operations */
00168 static inline void __munge(struct a4l_subdevice * subd,
00169                            void (*munge) (struct a4l_subdevice *,
00170                                           void *, unsigned long),
00171                            a4l_buf_t * buf, unsigned long count)
00172 {
00173         unsigned long start_ptr = (buf->mng_count % buf->size);
00174         unsigned long tmp_cnt = count;
00175 
00176         while (tmp_cnt != 0) {
00177                 /* Check the data copy can be performed contiguously */
00178                 unsigned long blk_size = (start_ptr + tmp_cnt > buf->size) ?
00179                         buf->size - start_ptr : tmp_cnt;
00180 
00181                 /* Perform the munge operation */
00182                 munge(subd, buf->buf + start_ptr, blk_size);
00183 
00184                 /* Update the start pointer and the count */
00185                 tmp_cnt -= blk_size;
00186                 start_ptr = 0;
00187         }
00188 }
00189 
00190 /* The function __handle_event can only be called from process context
00191    (not interrupt service routine). It allows the client process to
00192    retrieve the buffer status which has been updated by the driver */
00193 static inline int __handle_event(a4l_buf_t * buf)
00194 {
00195         int ret = 0;
00196 
00197         /* The event "End of acquisition" must not be cleaned
00198            before the complete flush of the buffer */
00199         if (test_bit(A4L_BUF_EOA_NR, &buf->flags)) {
00200                 ret = -ENOENT;
00201         }
00202 
00203         if (test_bit(A4L_BUF_ERROR_NR, &buf->flags)) {
00204                 ret = -EPIPE;
00205         }
00206 
00207         return ret;
00208 }
00209 
00210 /* --- Counters management functions --- */
00211 
00212 /* Here, we may wonder why we need more than two counters / pointers.
00213 
00214    Theoretically, we only need two counters (or two pointers):
00215    - one which tells where the reader should be within the buffer
00216    - one which tells where the writer should be within the buffer
00217 
00218    With these two counters (or pointers), we just have to check that
00219    the writer does not overtake the reader inside the ring buffer
00220    BEFORE any read / write operations.
00221 
00222    However, if one element is a DMA controller, we have to be more
00223    careful. Generally a DMA transfer occurs like this:
00224    DMA shot
00225       |-> then DMA interrupt
00226          |-> then DMA soft handler which checks the counter
00227 
00228    So, the checkings occur AFTER the write operations.
00229 
00230    Let's take an example: the reader is a software task and the writer
00231    is a DMA controller. At the end of the DMA shot, the write counter
00232    is higher than the read counter. Unfortunately, a read operation
00233    occurs between the DMA shot and the DMA interrupt, so the handler
00234    will not notice that an overflow occured.
00235 
00236    That is why tmp_count comes into play: tmp_count records the
00237    read/consumer current counter before the next DMA shot and once the
00238    next DMA shot is done, we check that the updated writer/producer
00239    counter is not higher than tmp_count. Thus we are sure that the DMA
00240    writer has not overtaken the reader because it was not able to
00241    overtake the n-1 value. */
00242 
00243 static inline int __pre_abs_put(a4l_buf_t * buf, unsigned long count)
00244 {
00245         if (count - buf->tmp_count > buf->size) {
00246                 set_bit(A4L_BUF_ERROR_NR, &buf->flags);
00247                 return -EPIPE;
00248         }
00249 
00250         buf->tmp_count = buf->cns_count;
00251 
00252         return 0;
00253 }
00254 
00255 static inline int __pre_put(a4l_buf_t * buf, unsigned long count)
00256 {
00257         return __pre_abs_put(buf, buf->tmp_count + count);
00258 }
00259 
00260 static inline int __pre_abs_get(a4l_buf_t * buf, unsigned long count)
00261 {
00262         /* The first time, we expect the buffer to be properly filled
00263         before the trigger occurence; by the way, we need tmp_count to
00264         have been initialized and tmp_count is updated right here */
00265         if (buf->tmp_count == 0 || buf->cns_count == 0)
00266                 goto out;
00267 
00268         /* At the end of the acquisition, the user application has
00269         written the defined amount of data into the buffer; so the
00270         last time, the DMA channel can easily overtake the tmp
00271         frontier because no more data were sent from user space;
00272         therefore no useless alarm should be sent */
00273         if (buf->end_count != 0 && (long)(count - buf->end_count) > 0)
00274                 goto out;
00275 
00276         /* Once the exception are passed, we check that the DMA
00277         transfer has not overtaken the last record of the production
00278         count (tmp_count was updated with prd_count the last time
00279         __pre_abs_get was called). We must understand that we cannot
00280         compare the current DMA count with the current production
00281         count because even if, right now, the production count is
00282         higher than the DMA count, it does not mean that the DMA count
00283         was not greater a few cycles before; in such case, the DMA
00284         channel would have retrieved the wrong data */
00285         if ((long)(count - buf->tmp_count) > 0) {
00286                 set_bit(A4L_BUF_ERROR_NR, &buf->flags);
00287                 return -EPIPE;
00288         }
00289 
00290 out:
00291         buf->tmp_count = buf->prd_count;
00292 
00293         return 0;
00294 }
00295 
00296 static inline int __pre_get(a4l_buf_t * buf, unsigned long count)
00297 {
00298         return __pre_abs_get(buf, buf->tmp_count + count);
00299 }
00300 
00301 static inline int __abs_put(a4l_buf_t * buf, unsigned long count)
00302 {
00303         unsigned long old = buf->prd_count;
00304 
00305         if ((long)(buf->prd_count - count) >= 0)
00306                 return -EINVAL;
00307 
00308         buf->prd_count = count;
00309 
00310         if ((old / buf->size) != (count / buf->size))
00311                 set_bit(A4L_BUF_EOBUF_NR, &buf->flags);
00312 
00313         if (buf->end_count != 0 && (long)(count - buf->end_count) >= 0)
00314                 set_bit(A4L_BUF_EOA_NR, &buf->flags);
00315 
00316         return 0;
00317 }
00318 
00319 static inline int __put(a4l_buf_t * buf, unsigned long count)
00320 {
00321         return __abs_put(buf, buf->prd_count + count);
00322 }
00323 
00324 static inline int __abs_get(a4l_buf_t * buf, unsigned long count)
00325 {
00326         unsigned long old = buf->cns_count;
00327 
00328         if ((long)(buf->cns_count - count) >= 0)
00329                 return -EINVAL;
00330 
00331         buf->cns_count = count;
00332 
00333         if ((old / buf->size) != count / buf->size)
00334                 set_bit(A4L_BUF_EOBUF_NR, &buf->flags);
00335 
00336         if (buf->end_count != 0 && (long)(count - buf->end_count) >= 0)
00337                 set_bit(A4L_BUF_EOA_NR, &buf->flags);
00338 
00339         return 0;
00340 }
00341 
00342 static inline int __get(a4l_buf_t * buf, unsigned long count)
00343 {
00344         return __abs_get(buf, buf->cns_count + count);
00345 }
00346 
00347 static inline unsigned long __count_to_put(a4l_buf_t * buf)
00348 {
00349         unsigned long ret;
00350 
00351         if ((long) (buf->size + buf->cns_count - buf->prd_count) > 0)
00352                 ret = buf->size + buf->cns_count - buf->prd_count;
00353         else
00354                 ret = 0;
00355 
00356         return ret;
00357 }
00358 
00359 static inline unsigned long __count_to_get(a4l_buf_t * buf)
00360 {
00361         unsigned long ret;
00362 
00363         /* If the acquisition is unlimited (end_count == 0), we must
00364            not take into account end_count */
00365         if (buf->end_count == 0 || (long)(buf->end_count - buf->prd_count) > 0)
00366                 ret = buf->prd_count;
00367         else
00368                 ret = buf->end_count;
00369 
00370         if ((long)(ret - buf->cns_count) > 0)
00371                 ret -= buf->cns_count;
00372         else
00373                 ret = 0;
00374 
00375         return ret;
00376 }
00377 
00378 static inline unsigned long __count_to_end(a4l_buf_t * buf)
00379 {
00380         unsigned long ret = buf->end_count - buf->cns_count;
00381 
00382         if (buf->end_count == 0)
00383                 return ULONG_MAX;
00384 
00385         return ((long)ret) < 0 ? 0 : ret;
00386 }
00387 
00388 /* --- Buffer internal functions --- */
00389 
00390 int a4l_alloc_buffer(a4l_buf_t *buf_desc, int buf_size);
00391 
00392 void a4l_free_buffer(a4l_buf_t *buf_desc);
00393 
00394 void a4l_init_buffer(a4l_buf_t * buf_desc);
00395 
00396 void a4l_cleanup_buffer(a4l_buf_t * buf_desc);
00397 
00398 int a4l_setup_buffer(a4l_cxt_t *cxt, a4l_cmd_t *cmd);
00399 
00400 int a4l_cancel_buffer(a4l_cxt_t *cxt);
00401 
00402 int a4l_buf_prepare_absput(struct a4l_subdevice *subd,
00403                            unsigned long count);
00404 
00405 int a4l_buf_commit_absput(struct a4l_subdevice *subd,
00406                           unsigned long count);
00407 
00408 int a4l_buf_prepare_put(struct a4l_subdevice *subd,
00409                         unsigned long count);
00410 
00411 int a4l_buf_commit_put(struct a4l_subdevice *subd,
00412                        unsigned long count);
00413 
00414 int a4l_buf_put(struct a4l_subdevice *subd,
00415                 void *bufdata, unsigned long count);
00416 
00417 int a4l_buf_prepare_absget(struct a4l_subdevice *subd,
00418                            unsigned long count);
00419 
00420 int a4l_buf_commit_absget(struct a4l_subdevice *subd,
00421                           unsigned long count);
00422 
00423 int a4l_buf_prepare_get(struct a4l_subdevice *subd,
00424                         unsigned long count);
00425 
00426 int a4l_buf_commit_get(struct a4l_subdevice *subd,
00427                        unsigned long count);
00428 
00429 int a4l_buf_get(struct a4l_subdevice *subd,
00430                 void *bufdata, unsigned long count);
00431 
00432 int a4l_buf_evt(struct a4l_subdevice *subd, unsigned long evts);
00433 
00434 unsigned long a4l_buf_count(struct a4l_subdevice *subd);
00435 
00436 /* --- Current Command management function --- */
00437 
00438 static inline a4l_cmd_t *a4l_get_cmd(a4l_subd_t *subd)
00439 {
00440         return (subd->buf) ? subd->buf->cur_cmd : NULL;
00441 }
00442 
00443 /* --- Munge related function --- */
00444 
00445 int a4l_get_chan(struct a4l_subdevice *subd);
00446 
00447 /* --- IOCTL / FOPS functions --- */
00448 
00449 int a4l_ioctl_mmap(a4l_cxt_t * cxt, void *arg);
00450 int a4l_ioctl_bufcfg(a4l_cxt_t * cxt, void *arg);
00451 int a4l_ioctl_bufcfg2(a4l_cxt_t * cxt, void *arg);
00452 int a4l_ioctl_bufinfo(a4l_cxt_t * cxt, void *arg);
00453 int a4l_ioctl_bufinfo2(a4l_cxt_t * cxt, void *arg);
00454 int a4l_ioctl_poll(a4l_cxt_t * cxt, void *arg);
00455 ssize_t a4l_read_buffer(a4l_cxt_t * cxt, void *bufdata, size_t nbytes);
00456 ssize_t a4l_write_buffer(a4l_cxt_t * cxt, const void *bufdata, size_t nbytes);
00457 int a4l_select(a4l_cxt_t *cxt,
00458                rtdm_selector_t *selector,
00459                enum rtdm_selecttype type, unsigned fd_index);
00460 
00461 #endif /* __KERNEL__ */
00462 
00463 /* MMAP ioctl argument structure */
00464 struct a4l_mmap_arg {
00465         unsigned int idx_subd;
00466         unsigned long size;
00467         void *ptr;
00468 };
00469 typedef struct a4l_mmap_arg a4l_mmap_t;
00470 
00471 /* Constants related with buffer size
00472    (might be used with BUFCFG ioctl) */
00473 #define A4L_BUF_MAXSIZE 0x1000000
00474 #define A4L_BUF_DEFSIZE 0x10000
00475 #define A4L_BUF_DEFMAGIC 0xffaaff55
00476 
00477 /* BUFCFG ioctl argument structure */
00478 struct a4l_buffer_config {
00479         /* NOTE: with the last buffer implementation, the field
00480            idx_subd became useless; the buffer are now
00481            per-context. So, the buffer size configuration is specific
00482            to an opened device. There is a little exception: we can
00483            define a default buffer size for a device.
00484            So far, a hack is used to implement the configuration of
00485            the default buffer size */
00486         unsigned int idx_subd;
00487         unsigned long buf_size;
00488 };
00489 typedef struct a4l_buffer_config a4l_bufcfg_t;
00490 
00491 /* BUFINFO ioctl argument structure */
00492 struct a4l_buffer_info {
00493         unsigned int idx_subd;
00494         unsigned long buf_size;
00495         unsigned long rw_count;
00496 };
00497 typedef struct a4l_buffer_info a4l_bufinfo_t;
00498 
00499 /* BUFCFG2 / BUFINFO2 ioctl argument structure */
00500 struct a4l_buffer_config2 {
00501         unsigned long wake_count;
00502         unsigned long reserved[3];
00503 };
00504 typedef struct a4l_buffer_config2 a4l_bufcfg2_t;
00505 
00506 /* POLL ioctl argument structure */
00507 struct a4l_poll {
00508         unsigned int idx_subd;
00509         unsigned long arg;
00510 };
00511 typedef struct a4l_poll a4l_poll_t;
00512 
00513 #endif /* !DOXYGEN_CPP */
00514 
00515 #endif /* __ANALOGY_BUFFER_H__ */

Generated on Tue Jul 10 2012 20:41:22 for Xenomai API by  doxygen 1.7.1