Re: [Uclinux-dist-devel] IIO ring buffer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jun 28, 2010 at 6:26 PM, Jonathan Cameron <jic23@xxxxxxxxx> wrote:
> On 06/28/10 08:59, Barry Song wrote:
>> On Sat, Jun 26, 2010 at 1:18 AM, Jonathan Cameron <jic23@xxxxxxxxx> wrote:
>>> Hi Barry,
>>>
>>> I've dropped back to the original patch for a close analysis of what is
>>> going on.  Sorry for the delay in getting to this!
>>>
>>>> Just RFC for discussion. It is not the last patch To keep the change
>>>> lest, i extract the common factor for most iio devices to a common
>>>> ring trigger module. Most devices can use the interfaces in this
>>>> module directly. So copy-paste for ring and trigger is not necessary
>>>> now.
>>> This time I'm going to concentrate of specific issues.
>>>
>>> Note I'm reading the code as being directed at the vast majority
>>> of cases.  What you do here fairly radically changes the job of
>>> the device driver. What I don't want to do is end up with
>>> cases where a tiny difference in hardware results in two completely
>>> different approaches being needed to write the driver.
>>>
>>> In a fairly illogical process I wrote this from the bottom :)
>>>
>>>>
>>>> For iio core changes:
>>>> 1. extract xxx_state to iio_state and add a private data to contain
>>>> chip-specific data
>>>> 2. extract all xxx_ring/xxx_trigger api to common api
>>>>
>>>> Index: drivers/staging/iio/iio.h
>>>> ===================================================================
>>>> --- drivers/staging/iio/iio.h (revision 8893)
>>>> +++ drivers/staging/iio/iio.h (working copy)
>>>> @@ -447,4 +447,46 @@
>>>>
>>>>  int iio_get_new_idr_val(struct idr *this_idr);
>>>>  void iio_free_idr_val(struct idr *this_idr, int id);
>>>> +
>>>> +/**
>>>> + * struct iio_state - hardware level hooks for iio device
>>>> + * @work_trigger_to_ring: bh for triggered event handling
>>>> + * @inter:           used to check if new interrupt has been triggered
>>>> + * @last_timestamp:  passing timestamp from th to bh of interrupt handler
>>>> + * @indio_dev:               industrial I/O device structure
>>>> + * @trig:            data ready trigger registered with iio
>>>> + * @tx:                      transmit buffer
>>>> + * @rx:                      recieve buffer
>>>> + * @buf_lock:                mutex to protect tx and rx
>>>> + * @irq:                interrupt number
>>>> + * @set_irq:            control the disable/enable of external interrupt
>>>> + * @hw_read_ring:       read ring data from hardware by spi/i2c.
>>>> + **/
>>>> +struct iio_state {
>>>> +     struct device                   *parent_dev;
>>>> +     struct work_struct              work_trigger_to_ring;
>>>> +     s64                             last_timestamp;
>>>> +     struct iio_dev                  *indio_dev;
>>>> +     struct iio_trigger              *trig;
>>>
>>> Not all drivers will want shared centralized buffers.  Simple
>>> devices might use the various spi and i2c functions that allocate
>>> data storage as needed within the functions.
>>>> +     u8                              *tx;
>>>> +     u8                              *rx;
>>>> +     struct mutex                    buf_lock;
>>>
>>> Assumes single irq (lot of adis devices can have several) and makes
>>> a copy of it to get round deliberate hiding of bus info.
>>>> +     int                             irq;
>>>> +     int (*set_irq)(struct iio_state *st, bool enable);
>>>
>>> My issues with this are given where it is used.
>>>> +     int (*hw_read_ring)(struct iio_state *st, u8 *rx);
>>>
>>> (as uncommented above) This is used to hide the bus specific info.
>>>> +     void *priv;
>>>> +};
>>>> +
>>>> +static inline void iio_state_set_privdata(struct iio_state *st, void *data)
>>>> +{
>>>> +     st->priv = data;
>>>> +}
>>>> +
>>>> +static inline void * iio_state_get_privdata(struct iio_state *st)
>>>> +{
>>>> +     return st->priv;
>>>> +}
>>>> +
>>>>  #endif /* _INDUSTRIAL_IO_H_ */
>>>> Index: drivers/staging/iio/common-ring-trigger.c
>>>> ===================================================================
>>>> --- drivers/staging/iio/common-ring-trigger.c (revision 0)
>>>> +++ drivers/staging/iio/common-ring-trigger.c (revision 0)
>>>> @@ -0,0 +1,277 @@
>>>> +/* The software ring with trigger which can be used by most drivers
>>>> + *
>>>> + * Copyright (c) 2010 Barry Song
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify it
>>>> + * under the terms of the GNU General Public License version 2 as published by
>>>> + * the Free Software Foundation.
>>>> + *
>>>> + */
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/device.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/fs.h>
>>>> +#include <linux/poll.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/cdev.h>
>>>> +#include <linux/slab.h>
>>>> +
>>>> +#include "iio.h"
>>>> +#include "ring_generic.h"
>>>> +#include "trigger.h"
>>>> +#include "ring_sw.h"
>>>> +
>>>> +/*
>>>> + * combine_8_to_16(): utility function to munge to u8s into u16
>>>> + */
>>>> +static inline u16 combine_8_to_16(u8 lower, u8 upper)
>>>> +{
>>>> +     u16 _lower = lower;
>>>> +     u16 _upper = upper;
>>>> +     return _lower | (_upper << 8);
>>>> +}
>>>> +
>>>> +static void iio_common_ring_poll_func_th(struct iio_dev *indio_dev)
>>>> +{
>>>> +     struct iio_state *st = iio_dev_get_devdata(indio_dev);
>>>> +     st->last_timestamp = indio_dev->trig->timestamp;
>>>> +     schedule_work(&st->work_trigger_to_ring);
>>>> +}
>>>> +
>>> We discussed various options for this, but I'm personally yet to be
>>> convinced that we aren't making the driver code much harder to follow
>>> for the sake of saving lines of code.
>>>
>>> I'm also not sure that the approach currently used here is the right
>>> way to do it in any driver which doesn't help.  One thing I would
>>> like to do is to loose the additional data copy required by the current
>>> approach of building a local record by copying form the raw data, then
>>> copying this record into the buffer.
>>>
>>> Preallocating space is easy enough with kfifo so I will probably do
>>> a rework of those patches shortly. For my sw_ring buffer I'm not sure
>>> if it can be easily done, but I'll look into it.
>> That main problem here is that the data layout is not coincident for
>> kinds of chips. But the SW ring procedure is needed by all drivers. My
>> idea is letting all the following done in bottom level driver:
>>
>> if (st->indio_dev->scan_count)
>>         if (st->hw_read_ring(st, st->rx) >= 0)
>>                  for (; i < st->indio_dev->scan_count; i++) {
>>                         data[i] = combine_8_to_16(st->rx[i*2+1],
>>                      ...
>>                   *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
>>
>> Then the flow will be:
>> 1. allocate buffer to hold data
> Yes.  Ideally that will change to be a call to a routine supplied by the
> buffer implementation as part of a move towards multiple buffer implementations.
> Note this one would need a hook to have the driver tell it how much space the
> next step will be needing.  This hook would also clean up the buffer allocation
> code in preenable.
>
>> 2. fill the buffer according to special data layout
>> 3. store_to ring
> Yup, this will become a paired operation with step 1.  (more of a 'done
> with buffer so it can no be read from the ring, or pushed onto the ring
> depending on implementation'.)
>> 4. notify the event
>>
>> The procedure is common for all chips using SW ring, only step 2 need
>> be instantized. Then adding hook named get_ring_elemants(), which read
>> HW and organize data layout,  is ok in fact.
> Agreed.  This way the driver still maintains control of what is going on
> and is still easy to read, but some of the complexity (error checking etc)
> is moved to a standard function.  My next question is where to put this function.
> Perhaps within the sw ring implementation?
>
>>
>>>
>>>> +static void iio_common_trigger_bh_to_ring(struct work_struct *work_s)
>>>> +{
>>>> +     struct iio_state *st
>>>> +             = container_of(work_s, struct iio_state,
>>>> +                             work_trigger_to_ring);
>>>> +
>>>> +     int i = 0;
>>>> +     s16 *data;
>>>> +     size_t datasize = st->indio_dev
>>>> +             ->ring->access.get_bpd(st->indio_dev->ring);
>>>> +
>>>> +     data = kmalloc(datasize , GFP_KERNEL);
>>>> +        if (data == NULL) {
>>>> +                dev_err(st->parent_dev, "memory alloc failed in ring bh");
>>>> +                return;
>>>> +        }
>>>> +
>>>> +     if (st->indio_dev->scan_count)
>>>> +             if (st->hw_read_ring(st, st->rx) >= 0)
>>>> +                     for (; i < st->indio_dev->scan_count; i++) {
>>>> +                             data[i] = combine_8_to_16(st->rx[i*2+1],
>>>> +                                             st->rx[i*2]);
>>>> +                     }
>>>> +
>>>> +        /* Guaranteed to be aligned with 8 byte boundary */
>>>> +        if (st->indio_dev->scan_timestamp)
>>>> +                *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
>>>> +
>>>> +        st->indio_dev->ring->access.store_to(st->indio_dev->ring,
>>>> +                                            (u8 *)data,
>>>> +                                            st->last_timestamp);
>>>> +
>>>> +        iio_trigger_notify_done(st->indio_dev->trig);
>>>> +        kfree(data);
>>>> +
>>>> +        return;
>>>> +}
>>>> +
>>>
>>> This one is pretty specific, though only in the central
>>> section working out the size. Can we come up with an easy way to
>>> share the rest of the code?
>>>
>>> The previous discussion including some possible solutions.
>>> I'm yet to be convinced that there is a clean way to do the equivalent
>>> of this given the large amount of knowledge your shared code would have
>>> to have about the underlying data.
>>
>> Here the main problem is sizeof(16) is thinked suitable for all chips.
> True for a lot of chips, but not all.  I'd rather not have that restriction
> in there.
>> Could we add a size_per_element field, then we calucate the total bpd
>> according to the size_per_element and scan_count?
> That would work, but is going to be non trivial as we would also want to
> generate the userspace interface (attributes currently handled by drivers)
> from these values.
>
> As I said above, I'd be more inclined (for now anyway) to let the driver provide
> a 'get_bpd' call back.  It would be handy both here, and in the buffer
> fill code.
>
> With either approach, we then have a nice general form of this function that
> can be used with all sw buffers, so perhaps this belongs in the ring_sw
> module as well?
>>
>>>> +static int iio_common_ring_preenable(struct iio_dev *indio_dev)
>>>> +{
>>>> +     size_t size;
>>>> +     dev_dbg(&indio_dev->dev, "%s\n", __func__);
>>>> +     /* Check if there are any scan elements enabled, if not fail*/
>>>> +     if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
>>>> +             return -EINVAL;
>>>> +
>>>> +     if (indio_dev->ring->access.set_bpd) {
>>>> +             if (indio_dev->scan_timestamp)
>>>> +                     if (indio_dev->scan_count)
>>>> +                             /* Timestamp (aligned to s64) and data */
>>>> +                             size = (((indio_dev->scan_count * sizeof(s16))
>>>> +                                                     + sizeof(s64) - 1)
>>>> +                                             & ~(sizeof(s64) - 1))
>>>> +                                     + sizeof(s64);
>>>> +                     else /* Timestamp only  */
>>>> +                             size = sizeof(s64);
>>>> +             else /* Data only */
>>>> +                     size = indio_dev->scan_count*sizeof(s16);
>>>> +             indio_dev->ring->access.set_bpd(indio_dev->ring, size);
>>>> +     }
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>
>>> Agree entirely with the next two.  Have moved to industrialio-trigger
>>> in todays first patch set.  They apply in all current cases and
>>> for that matter in any I have yet thought up.
>>
>> Acked.
>>
>>>> +static int iio_common_ring_postenable(struct iio_dev *indio_dev)
>>>> +{
>>>> +        return indio_dev->trig
>>>> +                ? iio_trigger_attach_poll_func(indio_dev->trig,
>>>> +                                               indio_dev->pollfunc)
>>>> +                : 0;
>>>> +}
>>>> +
>>>> +static int iio_common_ring_predisable(struct iio_dev *indio_dev)
>>>> +{
>>>> +        return indio_dev->trig
>>>> +                ? iio_trigger_dettach_poll_func(indio_dev->trig,
>>>> +                                                indio_dev->pollfunc)
>>>> +                : 0;
>>>> +}
>>>
>>>
>>>> +
>>>> +int iio_configure_common_ring(struct iio_dev *indio_dev)
>>>> +{
>>>> +     int ret = 0;
>>>> +     struct iio_state *st = indio_dev->dev_data;
>>>> +     struct iio_ring_buffer *ring;
>>>> +     INIT_WORK(&st->work_trigger_to_ring, iio_common_trigger_bh_to_ring);
>>>> +
>>> One reason I'm not keen on this as is, is that it means that all
>>> drivers using this code have to use the same buffer implementation.
>>> I'm very keen to make this selectable on a per driver basis.
>>
>> Why can't all devices by SW rings use the same buffer implementation?
>> Why do they want a different SW ring?
> Although we aren't using it much at the moment, the ability to do this looks
> to be crucial for the future of IIO.  A non exhaustive list of why includes:
>
> 1) ring_sw is terrible.  I wrote it late one night. No one has ever taken
>   on reviewing it and I for one am far from convinced it is correct. It was only
>   meant to be a proof of concept (though we have been using it for a while in
>   'production' data capture systems).
>
> 2) ring_sw is unsuprisingly a ring buffer.  In many applications fifo behaviour
>   is preferable.
>
> 3) ring_sw has maximum size of one page.  Not good for devices at high rates.
>
> 4) lots of interesting work is going on in the area of lockless ring buffers in
>   the kernel at the moment.  Whilst then tend to be complex, they have much better
>   scalablity than mine.
>
> 5) the buffer hooks are probably the best way to interface to input which people
>   keep requesting.
>
> 6) in slow applications a simple locked buffer would be more appropriate unless we
>   are sure there are no downsides to the lockless case.
>
> So in the medium term (or short if someone else does it ;)  we should have
>
> * Something equivalent to ring_sw with all of the hooks for events to userspace etc.
> * kfifo based fifo.  It's simple, but may require excessive locking. (also with this
>  I'm interested in whether I can mess around within spi / i2c subsystems to get
>  some controllers to do scatter gather dma directly into the buffer)
> * input hooked buffer.
> * high performance large ring buffer.  (I'm waiting to see what comes out of the tracing
>  discussions to see if it is relevant to us).
>
>
>>
>>> Obviously we could add hooks to make that work, but then we begin
>>> to destroy the point of your patch.
>>>
>>>> +     ring = iio_sw_rb_allocate(indio_dev);
>>>> +     if (!ring) {
>>>> +             ret = -ENOMEM;
>>>> +             return ret;
>>>> +     }
>>>> +     indio_dev->ring = ring;
>>>> +
>>>> +     iio_ring_sw_register_funcs(&ring->access);
>>>
>>> As discussed above. This one is actually a bit of a pain.
>>>> +     ring->preenable = &iio_common_ring_preenable;
>>> These last two are the same for all triggered software ring buffers,
>>> so I've moved the code into industrialio-trigger.c for now.
>>>> +     ring->postenable = &iio_common_ring_postenable;
>>>> +     ring->predisable = &iio_common_ring_predisable;
>>>> +     ring->owner = THIS_MODULE;
>>>> +
>>>
>>> This makes it clear that it is sensible to have an alloc_pollfunc function
>>> as the next 8 or so lines occur every single time.  That was in my first
>>> patch set today.
>>
>> Acked.
>>
>>>> +     indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
>>>> +     if (indio_dev->pollfunc == NULL) {
>>>> +             ret = -ENOMEM;
>>>> +             goto error_iio_sw_rb_free;;
>>>> +     }
>>>> +     indio_dev->pollfunc->poll_func_main = &iio_common_ring_poll_func_th;
>>>> +     indio_dev->pollfunc->private_data = indio_dev;
>>>> +     indio_dev->modes |= INDIO_RING_TRIGGERED;
>>>> +     return 0;
>>>> +
>>>> +error_iio_sw_rb_free:
>>>> +     iio_sw_rb_free(indio_dev->ring);
>>>> +     return ret;
>>>> +}
>>>> +EXPORT_SYMBOL(iio_configure_common_ring);
>>>> +
>>> Small save, but worth having if we can sort the configure function so
>>> everyone is happy.
>>>> +void iio_unconfigure_common_ring(struct iio_dev *indio_dev)
>>>> +{
>>>> +     kfree(indio_dev->pollfunc);
>>>> +     iio_sw_rb_free(indio_dev->ring);
>>>> +}
>>>> +EXPORT_SYMBOL(iio_unconfigure_common_ring);
>>>> +
>>>
>>> Only purpose of these wrapping functions is to allow for clean
>>> Kconfig selection of whether ring is enable or not.  I have just
>>> sent out a patch that adds relevant stubs to the core allowing these
>>> to go from all drivers anyway.  Glad to get those out of the way!
>>> Thanks for making the waste apparent.
>>
>> Acked.
>>
>>>> +int iio_initialize_common_ring(struct iio_ring_buffer *ring)
>>>> +{
>>>> +     return iio_ring_buffer_register(ring, 0);
>>>> +}
>>>> +EXPORT_SYMBOL(iio_initialize_common_ring);
>>>> +
>>>> +void iio_uninitialize_common_ring(struct iio_ring_buffer *ring)
>>>> +{
>>>> +     iio_ring_buffer_unregister(ring);
>>>> +}
>>>> +EXPORT_SYMBOL(iio_uninitialize_common_ring);
>>>> +
>>>> +static int iio_common_trigger_poll(struct iio_dev *dev_info,
>>>> +                                    int index,
>>>> +                                    s64 timestamp,
>>>> +                                    int no_test)
>>>> +{
>>>> +     struct iio_state *st = iio_dev_get_devdata(dev_info);
>>>> +     struct iio_trigger *trig = st->trig;
>>>> +
>>>> +     trig->timestamp = timestamp;
>>>> +     iio_trigger_poll(trig);
>>>> +
>>>> +     return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +IIO_EVENT_SH(common_trig, &iio_common_trigger_poll);
>>> You already know from previous emails that there is an issue with
>>> this one given in creates a couple of structures.  Would have
>>> to be a separate instance per driver.
>>
>> Yes. Here i will give a seperate instance per driver.
>>
>>>> +
>>>> +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
>>>> +
>>>> +static struct attribute *iio_trigger_attrs[] = {
>>>> +     &dev_attr_name.attr,
>>>> +     NULL,
>>>> +};
>>>> +
>>>> +static const struct attribute_group iio_trigger_attr_group = {
>>>> +     .attrs = iio_trigger_attrs,
>>>> +};
>>>> +
>>>
>>> Hiding away the bus type requires a copy of the irq already available.
>>>> +static int iio_common_trigger_try_reen(struct iio_trigger *trig)
>>>> +{
>>>> +     struct iio_state *st = trig->private_data;
>>>> +     enable_irq(st->irq);
>>>> +     return 0;
>>>> +}
>>>> +
>>>
>>> This is far too specific for my liking.  It only even applies to
>>> the majority of your drivers due to their current simple nature.
>>> If you are going to do this unification I'd like to see it post
>>> addition of full hardware event handling (I'm intending to do
>>> this at somepoint but am low on time currently and only have an
>>> adis16350 to play with)
>>>
>>> Assumptions:
>>> 1) Interrupt line is used for dataready and other events.
>>>        If this isn't true then the driver should be using the event
>>>        list system at all.  Adds overhead to this path for no gain.
>>>        With some of the adis sensors you have 2 interrupt lines.
>>>        A sensible option would be to setup one line for dataready
>>>        and the other for all other events.
>>> 2) Assumes that we have data ready on the first interrupt line.
>>>        Perhaps this makes sense but it isn't a current requirement
>>>        or even a suggested option.
>>
>> Here we can build the matched pair for interrupt index  and trigger
>> name, then we can check the interrupt index by trigger name with the
>> pair.
> The complexity is not that we might have multiple triggers, its that
> the physical lines may be doing other things as well such as threshold
> interrupts etc.  Can we hold this chunk of the patch until we have a few
> more devices implementing events and see where we are at that stage?
>
> It certainly looks like there are some savings in code to be made
> here, but I'm not yet of the best way to do it!
>
>> If one device has more than one trigger and one interrupt, we transfer
>> the param of interrupt index to set_irq(), then the process flow can
>> be shared too.
> True.
>> Anyway, bottom drivers don't want to implement the trigger_set_state
>> per trigger if the flow is same.
> I don't follow what you mean here.
>>
>>>> +static int iio_common_trigger_set_state(struct iio_trigger *trig,
>>>> +             bool state)
>>>> +{
>>>> +     struct iio_state *st = trig->private_data;
>>>> +     struct iio_dev *indio_dev = st->indio_dev;
>>>> +     int ret = 0;
>>>> +
>>>> +     dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
>>>> +     ret = st->set_irq(st, state);
>>>> +     if (state == false) {
>>>> +             iio_remove_event_from_list(&iio_event_common_trig,
>>>> +                             &indio_dev->interrupts[0]
>>>> +                             ->ev_list);
>>>> +             flush_scheduled_work();
>>>> +     } else {
>>>> +             iio_add_event_to_list(&iio_event_common_trig,
>>>> +                             &indio_dev->interrupts[0]->ev_list);
>>>> +     }
>>>> +     return ret;
>>>> +}
>>>> +
>>>
>>> The rest of your factoring out obviously requires the shared driver
>>> state structure.  This all makes sense if we think that is a desirable
>>> thing to do.
>>>> +int iio_probe_common_trigger(struct iio_dev *indio_dev)
>>>> +{
>>>> +     int ret;
>>>> +     struct iio_state *st = indio_dev->dev_data;
>>>> +
>>>> +     st->trig = iio_allocate_trigger();
>>>> +     st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
>>>> +     if (!st->trig->name) {
>>>> +             ret = -ENOMEM;
>>>> +             goto error_free_trig;
>>>> +     }
>>>> +     snprintf((char *)st->trig->name,
>>>> +                     IIO_TRIGGER_NAME_LENGTH,
>>>> +                     "iio-dev%d", indio_dev->id);
>>>> +     st->trig->dev.parent = st->parent_dev;
>>>> +     st->trig->owner = THIS_MODULE;
>>>> +     st->trig->private_data = st;
>>>> +     st->trig->set_trigger_state = &iio_common_trigger_set_state;
>>>> +     st->trig->try_reenable = &iio_common_trigger_try_reen;
>>>> +     st->trig->control_attrs = &iio_trigger_attr_group;
>>>> +     ret = iio_trigger_register(st->trig);
>>>> +
>>>> +     /* select default trigger */
>>>> +     indio_dev->trig = st->trig;
>>>> +     if (ret)
>>>> +             goto error_free_trig_name;
>>>> +
>>>> +     return 0;
>>>> +
>>>> +error_free_trig_name:
>>>> +     kfree(st->trig->name);
>>>> +error_free_trig:
>>>> +     iio_free_trigger(st->trig);
>>>> +
>>>> +     return ret;
>>>> +}
>>>> +EXPORT_SYMBOL(iio_probe_common_trigger);
>>>> +
>>>
>>>
>>>> +void iio_remove_common_trigger(struct iio_dev *indio_dev)
>>>> +{
>>>> +     struct iio_state *state = indio_dev->dev_data;
>>>> +
>>>> +     iio_trigger_unregister(state->trig);
>>>> +     kfree(state->trig->name);
>>>> +     iio_free_trigger(state->trig);
>>>> +}
>>>> +EXPORT_SYMBOL(iio_remove_common_trigger);
>>>
>>> snipped rest as it is obvious boiler pate.

For this, how about we let bottom driver to implement
set_trigger_state(), try_reenable(), and control_attrs of trigger, but
probe() and remove() can be common like this:

drivers/staging/iio/ring_sw.h

struct iio_sw_ring_helper_state {
       struct work_struct              work_trigger_to_ring;
       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
       int (*get_ring_element)(struct iio_sw_ring_helper_state *st, u8 *buf);
       s64                             last_timestamp;
};

drivers/staging/iio/ring_sw.c

+int iio_sw_probe_trigger(struct iio_dev *indio_dev, char *name,
struct attribute_group *attr_group)
+{
+        int ret;
+        struct iio_sw_ring_helper_state *st = (struct
iio_sw_ring_helper_state *)indio_dev->dev_data;

+        st->trig = iio_allocate_trigger();
+        st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+        if (!st->trig->name) {
+                ret = -ENOMEM;
+                goto error_free_trig;
+        }
+       snprintf((char *)st->trig->name,
+                        IIO_TRIGGER_NAME_LENGTH,
+                        "%s%d", name, indio_dev->id);
+        st->trig->dev.parent = st->parent_dev;
+        st->trig->owner = THIS_MODULE;
+        st->trig->private_data = st;
+        st->trig->control_attrs = attr_group;
+        ret = iio_trigger_register(st->trig);

+        indio_dev->trig = st->trig;
+        if (ret)
+                goto error_free_trig_name;

+        return 0;

+error_free_trig_name:
        kfree(st->trig->name);
+error_free_trig:
+        iio_free_trigger(st->trig);

+        return ret;
+}
+EXPORT_SYMBOL(iio_sw_probe_trigger);

+void iio_sw_remove_trigger(struct iio_dev *indio_dev)
+{
+        struct iio_state *state = indio_dev->dev_data;
+
+        iio_trigger_unregister(state->trig);
+        kfree(state->trig->name);
+        iio_free_trigger(state->trig);
+}
+EXPORT_SYMBOL(iio_sw_remove_trigger);

name and attribute_group can be params for iio_sw_probe_trigger()
since functions depend on them. But set_trigger_state(),
try_reenable() can be given chip-special entries in bottom driver
after  iio_sw_probe_trigger() returns successfully.


>>>
>>> As an aside. There is an awful lot of repeated code relating to low level
>>> device access in the adis drivers. Perhaps that is a good opportunity for
>>> unifying code?  Maybe we want and adis_library module? Or perhaps a number
>>> of the devices can be combined into a single driver? Just a thought
>>> that came up whilst looking at that code again.
>>
>> Good idea in fact. Many codes are same, for example spi read. But it
>> is really difficult to find the orderliness to build a library for the
>> moment.
> One for a later round of clean ups!  Perhaps I'll take a look at how
> easy this would be to do.
>
> Jonathan
>
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux