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

Author: Alexis Berlemont <alexis.berlem...@gmail.com>
Date:   Tue May 10 23:54:25 2011 +0200

analogy: implement the configuration of a wake-up threshold

Two functions are now available to define a wake-up
threshold. a4l_set/get_wakesize() allows the developer to define the
minimal data amount needed to wake-up a sleeping process (waiting for
an event during an asynchronous acquisition).

---

 include/analogy/analogy.h             |   72 ++++++++++++++-------------
 include/analogy/buffer.h              |   23 +++++++++
 include/analogy/ioctl.h               |    7 ++-
 ksrc/drivers/analogy/buffer.c         |   86 +++++++++++++++++++++++++++++---
 ksrc/drivers/analogy/rtdm_interface.c |    4 +-
 src/drvlib/analogy/async.c            |   31 ++++++++++++
 6 files changed, 179 insertions(+), 44 deletions(-)

diff --git a/include/analogy/analogy.h b/include/analogy/analogy.h
index 88f7f1a..16282fc 100644
--- a/include/analogy/analogy.h
+++ b/include/analogy/analogy.h
@@ -43,22 +43,22 @@ int a4l_sys_read(int fd, void *buf, size_t nbyte);
 
 int a4l_sys_write(int fd, void *buf, size_t nbyte);
 
-int a4l_sys_attach(int fd, a4l_lnkdesc_t * arg);
+int a4l_sys_attach(int fd, a4l_lnkdesc_t *arg);
 
 int a4l_sys_detach(int fd);
 
 int a4l_sys_bufcfg(int fd, unsigned int idx_subd, unsigned long size);
 
-int a4l_sys_desc(int fd, a4l_desc_t * dsc, int pass);
+int a4l_sys_desc(int fd, a4l_desc_t *dsc, int pass);
 
-int a4l_sys_devinfo(int fd, a4l_dvinfo_t * info);
+int a4l_sys_devinfo(int fd, a4l_dvinfo_t *info);
 
-int a4l_sys_subdinfo(int fd, a4l_sbinfo_t * info);
+int a4l_sys_subdinfo(int fd, a4l_sbinfo_t *info);
 
 int a4l_sys_nbchaninfo(int fd, unsigned int idx_subd, unsigned int *nb);
 
 int a4l_sys_chaninfo(int fd, 
-                    unsigned int idx_subd, a4l_chinfo_t * info);
+                    unsigned int idx_subd, a4l_chinfo_t *info);
 
 int a4l_sys_nbrnginfo(int fd,
                      unsigned int idx_subd,
@@ -66,7 +66,7 @@ int a4l_sys_nbrnginfo(int fd,
        
 int a4l_sys_rnginfo(int fd,
                    unsigned int idx_subd,
-                   unsigned int idx_chan, a4l_rnginfo_t * info);
+                   unsigned int idx_chan, a4l_rnginfo_t *info);
 
 /* --- Level 1 API (supposed to be used) --- */
     
@@ -92,83 +92,87 @@ int a4l_get_chinfo(a4l_desc_t *dsc,
 int a4l_get_rnginfo(a4l_desc_t *dsc,
                    unsigned int subd,
                    unsigned int chan,
-                   unsigned int rng, a4l_rnginfo_t ** info);
+                   unsigned int rng, a4l_rnginfo_t **info);
 
 #define a4l_is_rng_global(x) ((x)->flags & A4L_RNG_GLOBAL)
 
-int a4l_snd_command(a4l_desc_t * dsc, a4l_cmd_t *cmd);
+int a4l_snd_command(a4l_desc_t *dsc, a4l_cmd_t *cmd);
     
-int a4l_snd_cancel(a4l_desc_t * dsc, unsigned int idx_subd);
+int a4l_snd_cancel(a4l_desc_t *dsc, unsigned int idx_subd);
 
-int a4l_set_bufsize(a4l_desc_t * dsc,
+int a4l_set_bufsize(a4l_desc_t *dsc,
                    unsigned int idx_subd, unsigned long size);
 
-int a4l_get_bufsize(a4l_desc_t * dsc,
+int a4l_get_bufsize(a4l_desc_t *dsc,
                    unsigned int idx_subd, unsigned long *size);
 
-int a4l_mark_bufrw(a4l_desc_t * dsc,
+int a4l_set_wakesize(a4l_desc_t *dsc, unsigned long size);
+
+int a4l_get_wakesize(a4l_desc_t *dsc, unsigned long *size);
+
+int a4l_mark_bufrw(a4l_desc_t *dsc,
                   unsigned int idx_subd,
                   unsigned long cur, unsigned long *newp);
 
-int a4l_poll(a4l_desc_t * dsc,
+int a4l_poll(a4l_desc_t *dsc,
             unsigned int idx_subd, unsigned long ms_timeout);
     
-int a4l_mmap(a4l_desc_t * dsc,
+int a4l_mmap(a4l_desc_t *dsc,
             unsigned int idx_subd, unsigned long size, void **ptr);
 
-int a4l_async_read(a4l_desc_t * dsc,
+int a4l_async_read(a4l_desc_t *dsc,
                   void *buf, size_t nbyte, unsigned long ms_timeout);
 
-int a4l_async_write(a4l_desc_t * dsc,
+int a4l_async_write(a4l_desc_t *dsc,
                    void *buf, size_t nbyte, unsigned long ms_timeout);
 
-int a4l_snd_insnlist(a4l_desc_t * dsc, a4l_insnlst_t * arg);
+int a4l_snd_insnlist(a4l_desc_t *dsc, a4l_insnlst_t *arg);
 
-int a4l_snd_insn(a4l_desc_t * dsc, a4l_insn_t *arg);
+int a4l_snd_insn(a4l_desc_t *dsc, a4l_insn_t *arg);
 
 /* --- Level 2 API (supposed to be used) --- */
 
-int a4l_sync_write(a4l_desc_t * dsc,
+int a4l_sync_write(a4l_desc_t *dsc,
                   unsigned int idx_subd,
                   unsigned int chan_desc,
                   unsigned int delay, void *buf, size_t nbyte);
        
-int a4l_sync_read(a4l_desc_t * dsc,
+int a4l_sync_read(a4l_desc_t *dsc,
                  unsigned int idx_subd,
                  unsigned int chan_desc,
                  unsigned int delay, void *buf, size_t nbyte);
 
-int a4l_config_subd(a4l_desc_t * dsc,
+int a4l_config_subd(a4l_desc_t *dsc,
                    unsigned int idx_subd, unsigned int type, ...);
 
 int a4l_sync_dio(a4l_desc_t *dsc,
                 unsigned int idx_subd, void *mask, void *buf);
 
-int a4l_sizeof_chan(a4l_chinfo_t * chan);
+int a4l_sizeof_chan(a4l_chinfo_t *chan);
 
 int a4l_sizeof_subd(a4l_sbinfo_t *subd);
 
-int a4l_find_range(a4l_desc_t * dsc,
+int a4l_find_range(a4l_desc_t *dsc,
                   unsigned int idx_subd,
                   unsigned int idx_chan,
                   unsigned long unit,
-                  double min, double max, a4l_rnginfo_t ** rng);
+                  double min, double max, a4l_rnginfo_t **rng);
 
-int a4l_rawtoul(a4l_chinfo_t * chan, unsigned long *dst, void *src, int cnt);
+int a4l_rawtoul(a4l_chinfo_t *chan, unsigned long *dst, void *src, int cnt);
 
-int a4l_rawtof(a4l_chinfo_t * chan,
-              a4l_rnginfo_t * rng, float *dst, void *src, int cnt);
+int a4l_rawtof(a4l_chinfo_t *chan,
+              a4l_rnginfo_t *rng, float *dst, void *src, int cnt);
 
-int a4l_rawtod(a4l_chinfo_t * chan,
-              a4l_rnginfo_t * rng, double *dst, void *src, int cnt);
+int a4l_rawtod(a4l_chinfo_t *chan,
+              a4l_rnginfo_t *rng, double *dst, void *src, int cnt);
 
-int a4l_ultoraw(a4l_chinfo_t * chan, void *dst, unsigned long *src, int cnt);
+int a4l_ultoraw(a4l_chinfo_t *chan, void *dst, unsigned long *src, int cnt);
 
-int a4l_ftoraw(a4l_chinfo_t * chan,
-              a4l_rnginfo_t * rng, void *dst, float *src, int cnt);
+int a4l_ftoraw(a4l_chinfo_t *chan,
+              a4l_rnginfo_t *rng, void *dst, float *src, int cnt);
 
-int a4l_dtoraw(a4l_chinfo_t * chan,
-              a4l_rnginfo_t * rng, void *dst, double *src, int cnt);
+int a4l_dtoraw(a4l_chinfo_t *chan,
+              a4l_rnginfo_t *rng, void *dst, double *src, int cnt);
 
 #endif /* !DOXYGEN_CPP */
 
diff --git a/include/analogy/buffer.h b/include/analogy/buffer.h
index 86d0a64..f809d1d 100644
--- a/include/analogy/buffer.h
+++ b/include/analogy/buffer.h
@@ -87,6 +87,10 @@ struct a4l_buffer {
 
        /* Munge counter */
        unsigned long mng_count;
+
+       /* Theshold below which the user process should not be
+          awakened */
+       unsigned long wake_count;
 };
 typedef struct a4l_buffer a4l_buf_t;
 
@@ -371,6 +375,16 @@ static inline unsigned long __count_to_get(a4l_buf_t * buf)
        return ret;
 }
 
+static inline unsigned long __count_to_end(a4l_buf_t * buf)
+{
+       unsigned long ret = buf->end_count - buf->cns_count;
+
+       if (buf->end_count == 0)
+               return ULONG_MAX;
+
+       return ((long)ret) < 0 ? 0 : ret;
+}
+
 /* --- Buffer internal functions --- */
 
 int a4l_alloc_buffer(a4l_buf_t *buf_desc, int buf_size);
@@ -434,7 +448,9 @@ int a4l_get_chan(struct a4l_subdevice *subd);
 
 int a4l_ioctl_mmap(a4l_cxt_t * cxt, void *arg);
 int a4l_ioctl_bufcfg(a4l_cxt_t * cxt, void *arg);
+int a4l_ioctl_bufcfg2(a4l_cxt_t * cxt, void *arg);
 int a4l_ioctl_bufinfo(a4l_cxt_t * cxt, void *arg);
+int a4l_ioctl_bufinfo2(a4l_cxt_t * cxt, void *arg);
 int a4l_ioctl_poll(a4l_cxt_t * cxt, void *arg);
 ssize_t a4l_read_buffer(a4l_cxt_t * cxt, void *bufdata, size_t nbytes);
 ssize_t a4l_write_buffer(a4l_cxt_t * cxt, const void *bufdata, size_t nbytes);
@@ -480,6 +496,13 @@ struct a4l_buffer_info {
 };
 typedef struct a4l_buffer_info a4l_bufinfo_t;
 
+/* BUFCFG2 / BUFINFO2 ioctl argument structure */
+struct a4l_buffer_config2 {
+       unsigned long wake_count;
+       unsigned long reserved[3];
+};
+typedef struct a4l_buffer_config2 a4l_bufcfg2_t;
+
 /* POLL ioctl argument structure */
 struct a4l_poll {
        unsigned int idx_subd;
diff --git a/include/analogy/ioctl.h b/include/analogy/ioctl.h
index ae9f2b8..56519e5 100644
--- a/include/analogy/ioctl.h
+++ b/include/analogy/ioctl.h
@@ -29,7 +29,7 @@
 
 #include <rtdm/rtdm_driver.h>
 
-#define NB_IOCTL_FUNCTIONS 15
+#define NB_IOCTL_FUNCTIONS 17
 
 #endif /* __KERNEL__ */
 
@@ -52,6 +52,11 @@
 #define A4L_NBCHANINFO _IOR(CIO,13,a4l_chinfo_arg_t)
 #define A4L_NBRNGINFO _IOR(CIO,14,a4l_rnginfo_arg_t)
 
+/* These IOCTLs are bound to be merged with A4L_BUFCFG and A4L_BUFINFO
+   at the next major release */
+#define A4L_BUFCFG2 _IOR(CIO,15,a4l_bufcfg_t)
+#define A4L_BUFINFO2 _IOWR(CIO,16,a4l_bufcfg_t)
+
 #endif /* !DOXYGEN_CPP */
 
 #endif /* __ANALOGY_IOCTL__ */
diff --git a/ksrc/drivers/analogy/buffer.c b/ksrc/drivers/analogy/buffer.c
index 7623674..36e98bf 100644
--- a/ksrc/drivers/analogy/buffer.c
+++ b/ksrc/drivers/analogy/buffer.c
@@ -417,6 +417,7 @@ int a4l_buf_evt(a4l_subd_t *subd, unsigned long evts)
 {
        a4l_buf_t *buf = subd->buf;
        int tmp;
+       unsigned long wake = 0, count = ULONG_MAX;
 
        /* Warning: here, there may be a condition race : the cancel
           function is called by the user side and a4l_buf_evt and all
@@ -428,16 +429,25 @@ int a4l_buf_evt(a4l_subd_t *subd, unsigned long evts)
        if (!buf || !test_bit(A4L_SUBD_BUSY_NR, &subd->status))
                return -ENOENT;
 
-       /* Even if it is a little more complex,
-          atomic operations are used so as 
-          to prevent any kind of corner case */
-       while ((tmp = ffs(evts) - 1) != -1) {
-               set_bit(tmp, &buf->flags);
-               clear_bit(tmp, &evts);
+       /* Here we save the data count available for the user side */
+       if (evts == 0) {
+               count = a4l_subd_is_input(subd) ? 
+                       __count_to_get(buf) : __count_to_put(buf);
+               wake = __count_to_end(buf) < buf->wake_count ? 
+                       __count_to_end(buf) : buf->wake_count;
+       } else {
+               /* Even if it is a little more complex, atomic
+                  operations are used so as to prevent any kind of
+                  corner case */
+               while ((tmp = ffs(evts) - 1) != -1) {
+                       set_bit(tmp, &buf->flags);
+                       clear_bit(tmp, &evts);
+               }
        }
 
-       /* Notify the user-space side */
-       a4l_signal_sync(&buf->sync);
+       if (count >= wake)
+               /* Notify the user-space side */
+               a4l_signal_sync(&buf->sync);
 
        return 0;
 }
@@ -626,6 +636,40 @@ int a4l_ioctl_bufcfg(a4l_cxt_t * cxt, void *arg)
        return a4l_alloc_buffer(buf, buf_cfg.buf_size);
 }
 
+/* The ioctl BUFCFG2 allows the user space process to define the
+   minimal amount of data which should trigger a wake-up. If the ABI
+   could be broken, this facility would be handled by the original
+   BUFCFG ioctl. At the next major release, this ioctl will vanish. */
+
+int a4l_ioctl_bufcfg2(a4l_cxt_t * cxt, void *arg)
+{
+       a4l_dev_t *dev = a4l_get_dev(cxt);
+       a4l_buf_t *buf = cxt->buffer;
+       a4l_bufcfg2_t buf_cfg;
+
+       /* Basic checking */
+       if (!test_bit(A4L_DEV_ATTACHED_NR, &dev->flags)) {
+               __a4l_err("a4l_ioctl_bufcfg2: unattached device\n");
+               return -EINVAL;
+       }
+
+       if (rtdm_safe_copy_from_user(cxt->user_info,
+                                    &buf_cfg, 
+                                    arg, sizeof(a4l_bufcfg2_t)) != 0)
+               return -EFAULT;
+
+       if (buf_cfg.wake_count > buf->size) {
+               __a4l_err("a4l_ioctl_bufcfg2: "
+                         "wake-up threshold too big (> buffer size: %lu)\n", 
+                         buf->size);
+               return -EINVAL;
+       }
+
+       buf->wake_count = buf_cfg.wake_count;
+
+       return 0;
+}
+
 /* 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) */
@@ -735,6 +779,32 @@ a4l_ioctl_bufinfo_out:
        return 0;
 }
 
+/* The ioctl BUFINFO2 tells the user application the minimal amount of
+data which should trigger a wake-up. If the ABI could be broken, this
+facility would be handled by the original BUFINFO ioctl. At the next
+major release, this ioctl will vanish. */
+
+int a4l_ioctl_bufinfo2(a4l_cxt_t * cxt, void *arg)
+{
+       a4l_dev_t *dev = a4l_get_dev(cxt);
+       a4l_buf_t *buf = cxt->buffer;
+       a4l_bufcfg2_t buf_cfg;
+
+       /* Basic checking */
+       if (!test_bit(A4L_DEV_ATTACHED_NR, &dev->flags)) {
+               __a4l_err("a4l_ioctl_bufcfg2: unattached device\n");
+               return -EINVAL;
+       }
+
+       buf_cfg.wake_count = buf->wake_count;
+
+       if (rtdm_safe_copy_to_user(cxt->user_info,
+                                  arg, &buf_cfg, sizeof(a4l_bufcfg2_t)) != 0)
+               return -EFAULT;
+
+       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 */
diff --git a/ksrc/drivers/analogy/rtdm_interface.c 
b/ksrc/drivers/analogy/rtdm_interface.c
index 906a20f..89c080e 100644
--- a/ksrc/drivers/analogy/rtdm_interface.c
+++ b/ksrc/drivers/analogy/rtdm_interface.c
@@ -50,7 +50,9 @@ int (*a4l_ioctl_functions[NB_IOCTL_FUNCTIONS]) (a4l_cxt_t *, 
void *) = {
        a4l_ioctl_poll,
        a4l_ioctl_mmap, 
        a4l_ioctl_nbchaninfo, 
-       a4l_ioctl_nbrnginfo
+       a4l_ioctl_nbrnginfo,
+       a4l_ioctl_bufcfg2,
+       a4l_ioctl_bufinfo2
 };
 
 #ifdef CONFIG_PROC_FS
diff --git a/src/drvlib/analogy/async.c b/src/drvlib/analogy/async.c
index 176a289..4e96b01 100644
--- a/src/drvlib/analogy/async.c
+++ b/src/drvlib/analogy/async.c
@@ -131,6 +131,37 @@ int a4l_set_bufsize(a4l_desc_t * dsc,
        return a4l_sys_bufcfg(dsc->fd, idx_subd, size);
 }
 
+int a4l_set_wakesize(a4l_desc_t * dsc, unsigned long size)
+{
+       int err;
+       a4l_bufcfg2_t cfg = { .wake_count = size };
+
+       /* Basic checking */
+       if (dsc == NULL || dsc->fd < 0)
+               return -EINVAL;
+
+       return  __sys_ioctl(dsc->fd, A4L_BUFCFG2, &cfg);
+       
+       return err;
+}
+
+int a4l_get_wakesize(a4l_desc_t * dsc, unsigned long *size)
+{
+       int err;
+       a4l_bufcfg2_t cfg;
+
+       /* Basic checking */
+       if (size == NULL || dsc == NULL || dsc->fd < 0)
+               return -EINVAL;
+
+       err = __sys_ioctl(dsc->fd, A4L_BUFINFO2, &cfg);
+
+       if (err == 0)
+               *size = cfg.wake_count;
+
+       return err;
+}
+
 /**
  * @brief Get the size of the asynchronous buffer
  *


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to