Module: xenomai-abe Branch: experimental Commit: deac8867bedda1ff284498f3b46435683ffe3bee URL: http://git.xenomai.org/?p=xenomai-abe.git;a=commit;h=deac8867bedda1ff284498f3b46435683ffe3bee
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 | 80 ++++++++++++++++-------------- include/analogy/buffer.h | 23 +++++++++ include/analogy/ioctl.h | 7 ++- ksrc/drivers/analogy/buffer.c | 86 +++++++++++++++++++++++++++++--- ksrc/drivers/analogy/rtdm_interface.c | 8 ++- src/drvlib/analogy/async.c | 31 ++++++++++++ 6 files changed, 185 insertions(+), 50 deletions(-) diff --git a/include/analogy/analogy.h b/include/analogy/analogy.h index 15736a8..6a81674 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); +int a4l_sys_chaninfo(int fd, + 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 cb06a0f..f07c385 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 bfb0929..6b296a8 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 75f91e1..3042ad5 100644 --- a/ksrc/drivers/analogy/rtdm_interface.c +++ b/ksrc/drivers/analogy/rtdm_interface.c @@ -48,9 +48,11 @@ int (*a4l_ioctl_functions[NB_IOCTL_FUNCTIONS]) (a4l_cxt_t *, void *) = { a4l_ioctl_bufcfg, a4l_ioctl_bufinfo, a4l_ioctl_poll, - a4l_ioctl_mmap, - a4l_ioctl_nbchaninfo, - a4l_ioctl_nbrnginfo + a4l_ioctl_mmap, + a4l_ioctl_nbchaninfo, + 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 273115a..5f046d2 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