Re: [PATCH 6/7] iio: inv_mpu6050: Check channel configuration on preenable

From: Jonathan Cameron
Date: Wed May 04 2016 - 14:24:28 EST

On 4 May 2016 16:34:46 BST, Crestez Dan Leonard <leonard.crestez@xxxxxxxxx> wrote:
>On 05/04/2016 12:01 PM, Jonathan Cameron wrote:
>> On 03/05/16 14:01, Crestez Dan Leonard wrote:
>>> On 05/01/2016 08:34 PM, Jonathan Cameron wrote:
>>>> On 29/04/16 20:02, Crestez Dan Leonard wrote:
>>>>> Right now it is possible to only enable some of the x/y/z
>channels, for
>>>>> example you can enable accel_z without x or y. If you actually do
>>>>> what you get is actually only the x channel.
>>>>> In theory the device supports selecting gyro x/y/z channels
>>>>> individually. It would also be possible to selectively enable
>>>>> accel by unpacking the data read from the hardware into a format
>the iio
>>>>> core accepts.
>>>>> It is easier to simply refuse incorrect configuration.
>>>> Or see suggestion inline. This isn't an uncommon problem!
>>>>> +/* Validate channels are set in a correct configuration */
>>>>> +static int inv_mpu_buffer_preenable(struct iio_dev *indio_dev)
>>>>> +{
>>>> This should not be in the preenable. It's perfectly possible to
>know that mode was invalid
>>>> earlier than this. Use the core demux to handle this case by
>>>> available_scanmasks. The the core will handle demuxing the data
>stream if needed to
>>>> provide the channels enabled only in the kfifo.
>>> But available_scanmasks is a list! Listing every valid scanmask
>>> work for accel/gyro but the next patch adds support for up to 4
>>> and each slave can be enabled/disabled. This would requires
>>> 2^6 == 64 possible scanmasks, right?
>> Not that bad (a whole 256 bytes ;), but I get your point.
>>> I tried to do this same validation inside .validate_scan_mask but
>>> function is called for each individual scan bit. What I want is to
>>> validate the scan mask once it's entirely configured, and preenable
>>> seems to be the best choice.
>> We want to know earlier that a given set of channels isn't possible.
>>> This could be implemented with an "adjust_scan_mask" driver function
>>> which adds bits to a trial scanmask until the configuration is
>> I'd call it scan_mask_available_match or similar but yes, this
>> would work for me. So in iio_scan_mask_set we'd have something like:
>> if (indio_dev->available_scan_masks) {
>> mask = iio_scan_mask_match(indio_dev->available_scan_masks,
>> indio_dev->masklength,
>> trialmask, false);
>> if (!mask)
>> goto err_invalid_mask;
>> } else if (indio_dev->ops->scan_mask_available_match) {
>> mask =
>> trialmask);
>> if (!mask)
>> goto err_invalid_mask;
>> }
>> Bit of complexity needed to avoid any memory issues (probably use a
>> buffer in the driver private struct to point mask at once filled),
>> Scan mask available could then compute the minimum possible scan mask
>for the
>> device in question given the requirements of trialmask.
>> An easy change that effectively provides a dynamic equivalent of our
>> list of available scan masks. I'd advocate only using it when the
>> device complexity make it worthwhile (much like dynamic allocation of
>> specs currently) - so not many cases.
>>> I think a better solution would be to add a .get_buffer_offsets
>>> function and have the iio core handled demuxing based on offsets
>>> than just scan_mask.
>> Scan mask isn't about just this. A common case is not that you have
>> to enable additional channels to end up with a valid set of readings
>> but rather that you can only read a (complex) subset of channels at
>> a time in buffered mode. The simplest being onehot, but there are
>> quite a few other cases (two parallel ADCs each of which is muxed to
>> subset of the channels via slow muxes for example).
>>> This would also handle alignment for external channels with
>>> != 16. For example if I enable accel and an external u32 channel iio
>>> expects the following layout:
>>> <u16 ACCEL_X> <u16 ACCEL_Y> <u16 ACCEL_Z> <u16 PAD> <u32
>>> while my device gives the following:
>>> <u16 ACCEL_X> <u16 ACCEL_Y> <u16 ACCEL_Z> <u32 external>
>>> I could add memcpy mangling in my driver but handling this belongs
>>> the iio core.
>> Matter of opinion. I'd take this as a driver requirement - much like
>> common case of data that is packed tighter than this or irritatingly
>> interleaved.
>> <u4 ACCEL_X_11_8> <u4 ACCEL_Y_11_8> <u8 ACCEL_X_7_0> <u8 ACCEL_Y_7_0>
>> not uncommon.
>> Where do we draw the line between what should be in the core and in a
>> driver? I'm not against seeing a proposal for byte based packing
>> in the core, but I'm not convinced the added complexity (see other
>> about the endian mess) is worth it without seeing code.
>>> I'd rather avoid depending on new features in the iio core and just
>>> simple validations instead. This is because the feature I'm adding
>>> already complex.
>> I think your earlier suggestion that you dismissed is a trivial
>> of the core and provides everything you need - so that's the route
>> that I'd advocate.
>Implementing some sort of "scan_mask_available_match" won't deal with
>alignment issues for external channels so it only partially fixes my
>current problem. Maybe for some other driver?
>If you object to validations inside preenable it would be best to just
>implement manual byte mangling inside the driver. I'd split it in two:
> inv_mpu_get_scan_offsets();
> iio_format_aligned_sample(&scan_offsets);
>The second part would be sortof generic but implemented statically
>inside the driver. Since this would implicitly skip unneeded values
>hardware it will support arbitrary scan masks.

This would be a great first step. Will let us get a handle on how it all works.

Can always shift this put of the driver later if it makes sense.

Will be interesting to see what the code looks like.

Sent from my Android device with K-9 Mail. Please excuse my brevity.