Module: xenomai-abe Branch: analogy Commit: eaa3f39d5bd61dea3ee652aaafbc0646cf1603e3 URL: http://git.xenomai.org/?p=xenomai-abe.git;a=commit;h=eaa3f39d5bd61dea3ee652aaafbc0646cf1603e3
Author: Alexis Berlemont <alexis.berlem...@gmail.com> Date: Thu Jan 6 00:37:11 2011 +0100 analogy: 1st rework of fake driver The goal is to remove loop testing driver; fake integrates now three subdevices to reproduce the loop behaviour. The implementation is cleaner and that will help validate the waveform tools. --- ksrc/drivers/analogy/testing/fake.c | 331 +++++++++++++++++++++++++++-------- 1 files changed, 260 insertions(+), 71 deletions(-) diff --git a/ksrc/drivers/analogy/testing/fake.c b/ksrc/drivers/analogy/testing/fake.c index c8e8682..803ff00 100644 --- a/ksrc/drivers/analogy/testing/fake.c +++ b/ksrc/drivers/analogy/testing/fake.c @@ -1,24 +1,34 @@ #include <linux/module.h> #include <analogy/analogy_driver.h> -#define AI_TASK_PERIOD 1000000 +#define TASK_PERIOD 1000000 #define AI_SUBD 0 #define DIO_SUBD 1 +#define AO_SUBD 2 +#define AI2_SUBD 3 + +#define TRANSFER_SIZE 0x1000 /* --- Driver related structures --- */ struct fake_priv { - /* Configuration parameters */ + /* Attach configuration parameters + (they should be relocated in ai_priv) */ unsigned long amplitude_div; unsigned long quanta_cnt; -}; - -struct ai_priv { /* Task descriptor */ - a4l_task_t timer_task; + a4l_task_t task; + /* Statuses of the asynchronous subdevices */ + int ai_running; + int ao_running; + int ai2_running; +}; + +struct ai_priv { + /* Specific timing fields */ unsigned long scan_period_ns; unsigned long convert_period_ns; @@ -29,8 +39,11 @@ struct ai_priv { /* Misc fields */ unsigned long amplitude_div; unsigned long quanta_cnt; - int timer_running; +}; +struct ao_ai2_priv { + uint8_t buffer[TRANSFER_SIZE]; + int count; }; struct dio_priv { @@ -40,8 +53,9 @@ struct dio_priv { /* --- Channels / ranges part --- */ -/* Channels descriptor */ -static a4l_chdesc_t ai_chandesc = { +/* Channels descriptors */ + +static a4l_chdesc_t analog_chandesc = { .mode = A4L_CHAN_GLOBAL_CHANDESC, .length = 8, .chans = { @@ -58,7 +72,7 @@ static a4l_chdesc_t dio_chandesc = { }; /* Ranges tab */ -static a4l_rngtab_t ai_rngtab = { +static a4l_rngtab_t analog_rngtab = { .length = 2, .rngs = { RANGE_V(-5,5), @@ -66,10 +80,11 @@ static a4l_rngtab_t ai_rngtab = { }, }; /* Ranges descriptor */ -static a4l_rngdesc_t ai_rngdesc = RNG_GLOBAL(ai_rngtab); +static a4l_rngdesc_t analog_rngdesc = RNG_GLOBAL(analog_rngtab); + +/* Command options masks */ -/* Command options mask */ -static a4l_cmd_t test_cmd_mask = { +static a4l_cmd_t ai_cmd_mask = { .idx_subd = 0, .start_src = TRIG_NOW, .scan_begin_src = TRIG_TIMER, @@ -78,9 +93,20 @@ static a4l_cmd_t test_cmd_mask = { .stop_src = TRIG_COUNT|TRIG_NONE, }; +static a4l_cmd_t ao_cmd_mask = { + .idx_subd = 0, + .start_src = TRIG_NOW | TRIG_INT, + .scan_begin_src = TRIG_TIMER, + .convert_src = TRIG_NOW | TRIG_TIMER, + .scan_end_src = TRIG_COUNT, + .stop_src = TRIG_COUNT| TRIG_NONE, +}; + /* --- Analog input simulation --- */ -static uint16_t ai_value_output(struct ai_priv *priv) +/* --- Values generation for 1st AI --- */ + +static inline uint16_t ai_value_output(struct ai_priv *priv) { static uint16_t output_tab[8] = { 0x0001, 0x2000, 0x4000, 0x6000, @@ -104,76 +130,137 @@ static uint16_t ai_value_output(struct ai_priv *priv) return output_tab[idx] / priv->amplitude_div; } -/* --- Task part --- */ - -/* Timer task routine */ -static void ai_task_proc(void *arg) +int ai_push_values(a4l_subd_t *subd) { - a4l_subd_t *subd = (a4l_subd_t *)arg; struct ai_priv *priv = (struct ai_priv *)subd->priv; - a4l_cmd_t *cmd = NULL; - uint64_t now_ns, elapsed_ns=0; + a4l_cmd_t *cmd = a4l_get_cmd(subd); + uint64_t now_ns, elapsed_ns = 0; + int i = 0; + + if (!cmd) + return -EPIPE; + + now_ns = a4l_get_time(); + elapsed_ns += now_ns - priv->last_ns + priv->reminder_ns; + priv->last_ns = now_ns; + + while(elapsed_ns >= priv->scan_period_ns) { + int j; + + for(j = 0; j < cmd->nb_chan; j++) { + uint16_t value = ai_value_output(priv); + a4l_buf_put(subd, &value, sizeof(uint16_t)); + } + + elapsed_ns -= priv->scan_period_ns; + i++; + } - while(1) { - int running; + priv->current_ns += i * priv->scan_period_ns; + priv->reminder_ns = elapsed_ns; + + if (i != 0) + a4l_buf_evt(subd, 0); + + return 0; +} + +/* --- Data retrieval for AO --- */ + +int ao_pull_values(a4l_subd_t *subd) +{ + struct ao_ai2_priv *priv = (struct ao_ai2_priv *)subd->priv; + int err; + + /* Let's have a look at how many samples are available */ + priv->count = a4l_buf_count(subd) < TRANSFER_SIZE ? + a4l_buf_count(subd) : TRANSFER_SIZE; + + err = a4l_buf_get(subd, priv->buffer, priv->count); + if (err < 0) { + priv->count = 0; + a4l_err(subd->dev, + "ao_get_values: a4l_buf_get failed (err=%d)\n", err); + } - RTDM_EXECUTE_ATOMICALLY(running = priv->timer_running); + return err; +} - if(running) - { - int i = 0; +/* --- Data redirection for 2nd AI (from AO) --- */ - cmd = a4l_get_cmd(subd); +int ai2_push_values(a4l_subd_t *subd) +{ + struct ao_ai2_priv *priv = *((struct ao_ai2_priv **)subd->priv); + int err = 0; + + if (priv->count) { + err = a4l_buf_put(subd, priv->buffer, priv->count); + a4l_err(subd->dev, + "ao_redirect_values: " + "a4l_buf_get failed (err=%d)\n", err); + } - now_ns = a4l_get_time(); - elapsed_ns += now_ns - priv->last_ns + priv->reminder_ns; - priv->last_ns = now_ns; + return err; +} - while(elapsed_ns >= priv->scan_period_ns) { - int j; +/* --- Global task part --- */ - for(j = 0; j < cmd->nb_chan; j++) { - uint16_t value = ai_value_output(priv); - a4l_buf_put(subd, &value, sizeof(uint16_t)); - } +/* One task is enough for all the asynchronous subdevices, it is just + a fake driver after all */ - elapsed_ns -= priv->scan_period_ns; - i++; +static void task_proc(void *arg) +{ + a4l_dev_t *dev = (a4l_dev_t *)arg; + a4l_subd_t *ai_subd = (a4l_subd_t *)a4l_get_subd(dev, AI_SUBD); + a4l_subd_t *ao_subd = (a4l_subd_t *)a4l_get_subd(dev, AO_SUBD); + a4l_subd_t *ai2_subd = (a4l_subd_t *)a4l_get_subd(dev, AI2_SUBD); - } + struct fake_priv *priv = (struct fake_priv *)dev->priv; - priv->current_ns += i * priv->scan_period_ns; - priv->reminder_ns = elapsed_ns; + while (1) { + + int running; + + RTDM_EXECUTE_ATOMICALLY(running = priv->ai_running); + if (running && ai_push_values(ai_subd) < 0) + break; + + RTDM_EXECUTE_ATOMICALLY(running = priv->ao_running); + if (running && ao_pull_values(ao_subd) < 0) + break; - if (i != 0) - a4l_buf_evt(subd, 0); - } - a4l_task_sleep(AI_TASK_PERIOD); + RTDM_EXECUTE_ATOMICALLY(running = priv->ai2_running); + if (running && ai2_push_values(ai2_subd) < 0) + break; + + a4l_task_sleep(TASK_PERIOD); } } + /* --- Asynchronous AI functions --- */ static int ai_cmd(a4l_subd_t *subd, a4l_cmd_t *cmd) { - struct ai_priv *priv = (struct ai_priv *)subd->priv; - - priv->scan_period_ns = cmd->scan_begin_arg; - priv->convert_period_ns = (cmd->convert_src==TRIG_TIMER)? + struct fake_priv *priv = (struct fake_priv *)subd->dev->priv; + struct ai_priv *ai_priv = (struct ai_priv *)subd->priv; + + ai_priv->scan_period_ns = cmd->scan_begin_arg; + ai_priv->convert_period_ns = (cmd->convert_src==TRIG_TIMER)? cmd->convert_arg:0; a4l_dbg(1, drv_dbg, subd->dev, "ai_cmd: scan_period=%luns convert_period=%luns\n", - priv->scan_period_ns, priv->convert_period_ns); - - priv->last_ns = a4l_get_time(); + ai_priv->scan_period_ns, ai_priv->convert_period_ns); - priv->current_ns = ((unsigned long)priv->last_ns); - priv->reminder_ns = 0; + ai_priv->last_ns = a4l_get_time(); - RTDM_EXECUTE_ATOMICALLY(priv->timer_running = 1); + ai_priv->current_ns = ((unsigned long)ai_priv->last_ns); + ai_priv->reminder_ns = 0; + RTDM_EXECUTE_ATOMICALLY(priv->ai_running = 1); + return 0; } @@ -195,9 +282,9 @@ static int ai_cmdtest(a4l_subd_t *subd, a4l_cmd_t *cmd) static int ai_cancel(a4l_subd_t *subd) { - struct ai_priv *priv = (struct ai_priv *)subd->priv; + struct fake_priv *priv = (struct fake_priv *)subd->dev->priv; - RTDM_EXECUTE_ATOMICALLY(priv->timer_running = 0); + RTDM_EXECUTE_ATOMICALLY(priv->ai_running = 0); return 0; } @@ -210,6 +297,54 @@ static void ai_munge(a4l_subd_t *subd, void *buf, unsigned long size) ((uint16_t *)buf)[i] += 1; } +/* --- Asynchronous A0 functions --- */ + +int ao_cmd(a4l_subd_t *subd, a4l_cmd_t *cmd) +{ + a4l_info(subd->dev, "ao_cmd: (subd=%d)\n", subd->idx); + return 0; +} + +int ao_trigger(a4l_subd_t *subd, lsampl_t trignum) +{ + struct fake_priv *priv = (struct fake_priv *)subd->dev->priv; + + a4l_info(subd->dev, "ao_trigger: (subd=%d)\n", subd->idx); + RTDM_EXECUTE_ATOMICALLY(priv->ao_running = 1); + return 0; +} + +int ao_cancel(a4l_subd_t *subd) +{ + struct fake_priv *priv = (struct fake_priv *)subd->dev->priv; + + a4l_info(subd->dev, "ao_cancel: (subd=%d)\n", subd->idx); + RTDM_EXECUTE_ATOMICALLY(priv->ao_running = 0); + return 0; +} + +/* --- Asynchronous 2nd AI functions --- */ + +int ai2_cmd(a4l_subd_t *subd, a4l_cmd_t *cmd) +{ + struct fake_priv *priv = (struct fake_priv *)subd->dev->priv; + + a4l_info(subd->dev, "ao_cmd: (subd=%d)\n", subd->idx); + RTDM_EXECUTE_ATOMICALLY(priv->ai2_running = 1); + return 0; +} + +int ai2_cancel(a4l_subd_t *subd) +{ + struct fake_priv *priv = (struct fake_priv *)subd->dev->priv; + + a4l_info(subd->dev, "ao_cancel: (subd=%d)\n", subd->idx); + RTDM_EXECUTE_ATOMICALLY(priv->ai2_running = 0); + return 0; +} + + + /* --- Synchronous AI functions --- */ static int ai_insn_read(a4l_subd_t *subd, a4l_kinsn_t *insn) @@ -252,13 +387,13 @@ void setup_ai_subd(a4l_subd_t *subd) subd->flags |= A4L_SUBD_AI; subd->flags |= A4L_SUBD_CMD; subd->flags |= A4L_SUBD_MMAP; - subd->rng_desc = &ai_rngdesc; - subd->chan_desc = &ai_chandesc; + subd->rng_desc = &analog_rngdesc; + subd->chan_desc = &analog_chandesc; subd->do_cmd = ai_cmd; subd->do_cmdtest = ai_cmdtest; subd->cancel = ai_cancel; subd->munge = ai_munge; - subd->cmd_mask = &test_cmd_mask; + subd->cmd_mask = &ai_cmd_mask; subd->insn_read = ai_insn_read; } @@ -271,6 +406,32 @@ void setup_dio_subd(a4l_subd_t *subd) subd->insn_bits = dio_insn_bits; } +void setup_ao_subd(a4l_subd_t *subd) +{ + /* Fill the subdevice structure */ + subd->flags |= A4L_SUBD_AO; + subd->flags |= A4L_SUBD_CMD; + subd->flags |= A4L_SUBD_MMAP; + subd->rng_desc = &analog_rngdesc; + subd->chan_desc = &analog_chandesc; + subd->do_cmd = ao_cmd; + subd->cancel = ao_cancel; + subd->cmd_mask = &ao_cmd_mask; +} + +void setup_ai2_subd(a4l_subd_t *subd) +{ + /* Fill the subdevice structure */ + subd->flags |= A4L_SUBD_AI; + subd->flags |= A4L_SUBD_CMD; + subd->flags |= A4L_SUBD_MMAP; + subd->rng_desc = &analog_rngdesc; + subd->chan_desc = &analog_chandesc; + subd->do_cmd = ai2_cmd; + subd->cancel = ai2_cancel; + subd->cmd_mask = &ai_cmd_mask; +} + /* --- Attach / detach functions --- */ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg) @@ -278,7 +439,8 @@ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg) int ret = 0; a4l_subd_t *subd; struct fake_priv *priv = (struct fake_priv *)dev->priv; - struct ai_priv * ai_priv; + struct ai_priv *ai_priv; + struct ao_ai2_priv *shared_priv; a4l_dbg(1, drv_dbg, dev, "starting attach procedure...\n"); @@ -305,15 +467,9 @@ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg) return -ENOMEM; ai_priv = (struct ai_priv*)subd->priv; - ai_priv->timer_running = 0; ai_priv->amplitude_div = priv->amplitude_div; ai_priv->quanta_cnt = priv->quanta_cnt; - ret = a4l_task_init(&ai_priv->timer_task, - "Fake AI task", - ai_task_proc, - subd, A4L_TASK_HIGHEST_PRIORITY); - ret = a4l_add_subd(dev, subd); if(ret != AI_SUBD) return (ret < 0) ? ret : -EINVAL; @@ -331,6 +487,40 @@ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg) a4l_dbg(1, drv_dbg, dev, "DIO subdevice registered\n"); + + /* Add the AO subdevice to the device */ + subd = a4l_alloc_subd(sizeof(struct ao_ai2_priv), setup_ao_subd); + if(subd == NULL) + return -ENOMEM; + + memset(subd->priv, 0, sizeof(struct ao_ai2_priv)); + shared_priv = (struct ao_ai2_priv *)subd->priv; + + ret = a4l_add_subd(dev, subd); + if(ret != AO_SUBD) + return (ret < 0) ? ret : -EINVAL; + + a4l_dbg(1, drv_dbg, dev, "AO subdevice registered\n"); + + /* Add the 2nd AI subdevice to the device */ + subd = a4l_alloc_subd(sizeof(struct ao_ai2_priv *), setup_ai2_subd); + if(subd == NULL) + return -ENOMEM; + + memcpy(subd->priv, &shared_priv, sizeof(struct ao_ai2_priv *)); + ret = a4l_add_subd(dev, subd); + if(ret != AI2_SUBD) + return (ret < 0) ? ret : -EINVAL; + + a4l_dbg(1, drv_dbg, dev, "AI2 subdevice registered\n"); + + ret = a4l_task_init(&priv->task, + "Fake AI task", + task_proc, + dev, A4L_TASK_HIGHEST_PRIORITY); + + a4l_dbg(1, drv_dbg, dev, "AI2 subdevice registered\n"); + a4l_dbg(1, drv_dbg, dev, "attach procedure complete\n"); return 0; @@ -338,10 +528,9 @@ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg) int test_detach(a4l_dev_t *dev) { - a4l_subd_t *subd = a4l_get_subd(dev, AI_SUBD); - struct ai_priv *priv = (struct ai_priv *)subd->priv; + struct fake_priv *priv = (struct fake_priv *)dev->priv; - a4l_task_destroy(&priv->timer_task); + a4l_task_destroy(&priv->task); a4l_dbg(1, drv_dbg, dev, "detach procedure complete\n"); _______________________________________________ Xenomai-git mailing list Xenomai-git@gna.org https://mail.gna.org/listinfo/xenomai-git