On 03/06/14 00:14, Reyad Attiyat wrote:
Updated magn_3d_channel enum for all possible north channels Added functions to setup iio_chan_spec array depending on which hid usage reports are found Renamed magn_val to iio_val to differentiate the index being used Updated magn_3d_state struct to hold pointer array (magn_val_addr[]) which points to iio_val[] Updated magn_3d_parse_report to scan for all compass usages and create iio channels for each Signed-off-by: Reyad Attiyat <reyad.attiyat@xxxxxxxxx>
Hi Reyad, I've taken a rather quick look at this. Will probably want to take one more close look at a newer version. Various bits and bobs inline - mostly fine! Jonathan
--- drivers/iio/magnetometer/hid-sensor-magn-3d.c | 271 +++++++++++++++++--------- 1 file changed, 177 insertions(+), 94 deletions(-) diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 6d162b7..32f4d90 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -34,63 +34,54 @@ enum magn_3d_channel { CHANNEL_SCAN_INDEX_X, CHANNEL_SCAN_INDEX_Y, CHANNEL_SCAN_INDEX_Z, + CHANNEL_SCAN_INDEX_NORTH_MAGN, + CHANNEL_SCAN_INDEX_NORTH_TRUE, + CHANNEL_SCAN_INDEX_NORTH_TILT_COMP, + CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP, MAGN_3D_CHANNEL_MAX, }; +#define IIO_CHANNEL_MAX MAGN_3D_CHANNEL_MAX
Please don't define a generic sounding name for a local constant. Why not use MAGN_3D_CHANNEL_MAX everywhere?
+ struct magn_3d_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX]; - u32 magn_val[MAGN_3D_CHANNEL_MAX]; -}; + u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX]; -static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS, - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS, - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS + u32 iio_val[IIO_CHANNEL_MAX]; + int num_iio_channels; }; -/* Channel definitions */ -static const struct iio_chan_spec magn_3d_channels[] = { - { - .type = IIO_MAGN, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | - BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_X, - }, { - .type = IIO_MAGN, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | - BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_Y, - }, { - .type = IIO_MAGN, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | - BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_Z, +/* Find index into magn_3d_state magn[] and magn_val_addr[] from HID Usage */ +static int magn_3d_usage_id_to_chan_index(unsigned usage_id){ + int offset = -1;
I'd personally prefer offset = -EINVAL and to have it assigned as a default element in the switch statement rather that here.
+ + switch (usage_id) { + case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS: + offset = CHANNEL_SCAN_INDEX_X; + break; + case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS: + offset = CHANNEL_SCAN_INDEX_Y; + break; + case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS: + offset = CHANNEL_SCAN_INDEX_Z; + break; + case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH: + offset = CHANNEL_SCAN_INDEX_NORTH_TILT_COMP; + break; + case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH: + offset = CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP; + break; + case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH: + offset = CHANNEL_SCAN_INDEX_NORTH_MAGN; + break; + case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH: + offset = CHANNEL_SCAN_INDEX_NORTH_TRUE; + break; } -}; -/* Adjust channel real bits based on report descriptor */ -static void magn_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; + return offset; } /* Channel read_raw handler */ @@ -101,21 +92,31 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, { struct magn_3d_state *magn_state = iio_priv(indio_dev); int report_id = -1; - u32 address; + unsigned usage_id; + int chan_index = -1; int ret; int ret_type; + dev_dbg(&indio_dev->dev, "magn_3d_read_raw\n"); + *val = 0; *val2 = 0; switch (mask) { case 0: + /* We store the HID usage ID of the iio channel + * in its address field + */ + usage_id = chan->address; + chan_index = magn_3d_usage_id_to_chan_index(usage_id);
+ if(chan_index < 0) + return -EINVAL; + report_id = - magn_state->magn[chan->scan_index].report_id; - address = magn_3d_addresses[chan->scan_index]; + magn_state->magn[chan_index].report_id; if (report_id >= 0) *val = sensor_hub_input_attr_get_raw_value( magn_state->common_attributes.hsdev, - HID_USAGE_SENSOR_COMPASS_3D, address, + HID_USAGE_SENSOR_COMPASS_3D, usage_id, report_id); else { *val = 0; @@ -202,12 +203,13 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, magn_state->common_attributes.data_ready); if (magn_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - magn_state->magn_val, - sizeof(magn_state->magn_val)); + &(magn_state->iio_val), + sizeof(magn_state->iio_val)); return 0; } + /* Capture samples in local storage */ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, unsigned usage_id, @@ -217,63 +219,143 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); int offset; + u32 *magn_val; int ret = -EINVAL; - switch (usage_id) { + offset = magn_3d_usage_id_to_chan_index(usage_id); + if(offset < 0) + return ret; + + magn_val = magn_state->magn_val_addr[offset]; + if(!magn_val) + return ret; + + *(magn_val) = *(u32 *)raw_data; + + return 0; +} + +/* Setup the iio_chan_spec for HID Usage ID */ +static int magn_3d_setup_new_iio_chan(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + unsigned attr_usage_id, + struct iio_chan_spec *iio_chans, + struct magn_3d_state *st) +{ + int ret = -1;
This is kind of backwards to normal practice for this sort of function. Better to maintain ret in the correct state at all times. Hence start with it being 0 and set to negative when there is an error rather than the other way around.
+ int iio_index; + int magn_index; + struct iio_chan_spec *channel; + + /* Setup magn_3d_state for new channel */ + magn_index = magn_3d_usage_id_to_chan_index(attr_usage_id); + if(magn_index < 0 || magn_index >= MAGN_3D_CHANNEL_MAX){ + return -1; + } + + /* Check if usage attribute exists in the sensor hub device */ + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + attr_usage_id, + &(st->magn[magn_index])); + if(ret != 0){ + /* Usage not found. Nothing to setup.*/ + return 0; + } + + iio_index = st->num_iio_channels; + if(iio_index < 0 || iio_index >= IIO_CHANNEL_MAX){
I'd be tempted to allocate space dynamically but I guess this works.
+ return -2; + } + + /* Check if this usage hasn't been setup */ + if(st->magn_val_addr[magn_index] != NULL){
Space before that bracket here and elsewhere. Don't return your own error codes. Use standard ones. I guess thees are left from debugging.
+ return -3; + } + st->magn_val_addr[magn_index] = &(st->iio_val[iio_index]); + + /* Setup IIO Channel spec */ + channel = &(iio_chans[iio_index]);
Just pass this is in as a pointer in the first place? That is a pointer to the current channel location, that may or may not be filled by this function.
+ + channel->type = IIO_MAGN; + channel->address = attr_usage_id; + channel->modified = 1; + + switch (attr_usage_id){ + case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH: + channel->channel2 = IIO_MOD_NORTH_MAGN_TILT_COMP; + break; + case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH: + channel->channel2 = IIO_MOD_NORTH_TRUE_TILT_COMP; + break; + case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH: + channel->channel2 = IIO_MOD_NORTH_MAGN; + break; + case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH: + channel->channel2 = IIO_MOD_NORTH_TRUE; + break; case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS: + channel->channel2 = IIO_MOD_X; + break; case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS: + channel->channel2 = IIO_MOD_Y; + break; case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS: - offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS; - magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] = - *(u32 *)raw_data; - ret = 0; - break; - default: + channel->channel2 = IIO_MOD_Z; break; + default: + return -4;
huh? why -4. -EINVAL or -ENOSUP or something similar perhaps.
} + channel->info_mask_shared_by_type = + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS); + + channel->scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + channel->scan_type.realbits = st->magn[magn_index].size * 8; + /* Maximum size of a sample to capture is u32 */ + channel->scan_type.storagebits = sizeof(u32) * 8; +
I'd keen num_iio_channels outside this function and increment it if this function does not return an error.
+ (st->num_iio_channels)++;
Don't do this. ret should have been valid throughout... if not something odd is going on with your use of ret. Hmm. I see it is in the original code :( feel free to clean this up.
+ ret = 0; + return ret; } -/* Parse report which is specific to an usage id*/ +/* Read the HID reports and setup IIO Channels */ static int magn_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, + struct iio_chan_spec *iio_chans, unsigned usage_id, struct magn_3d_state *st) { - int ret; + int ret = 0; int i; - for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { - ret = sensor_hub_input_get_attribute_info(hsdev, - HID_INPUT_REPORT, - usage_id, - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i, - &st->magn[CHANNEL_SCAN_INDEX_X + i]); - if (ret < 0) - break; - magn_3d_adjust_channel_bit_mask(channels, - CHANNEL_SCAN_INDEX_X + i, - st->magn[CHANNEL_SCAN_INDEX_X + i].size); - } - dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n", - st->magn[0].index, - st->magn[0].report_id, - st->magn[1].index, st->magn[1].report_id, - st->magn[2].index, st->magn[2].report_id); - - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ORIENTATION, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } + dev_dbg(&pdev->dev, "magn_3d_parse_reports Usage ID: %x\n", usage_id); + for(i = HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS; + i <= HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS && ret == 0; + i++) + ret = magn_3d_setup_new_iio_chan(hsdev, + usage_id, + i, + iio_chans, + st); + + dev_dbg(&pdev->dev, "magn_3d_parse_reports Found %d\n magnetic axis. Returned: %d", st->num_iio_channels, ret); + for(i = HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH; + i <= HID_USAGE_SENSOR_ORIENT_TRUE_NORTH && ret == 0; + i++) + ret = magn_3d_setup_new_iio_chan(hsdev, + usage_id, + i, + iio_chans, + st);
As stated above, I'd use whether this succeeds for a given channel to increment the location in iio_chans and then pass in only the 'next' channel location on each pass. Moving the bounds checks out here as well would be make for a cleaner magn_3d_setup_new_iio_chan function.
+ dev_dbg(&pdev->dev, "magn_3d_parse_reports Found %d\n magnetic channels. Returned: %d", st->num_iio_channels, ret); return ret; } @@ -307,10 +389,11 @@ static int hid_magn_3d_probe(struct platform_device *pdev) return ret; } - channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels), - GFP_KERNEL); + channels = kcalloc(MAGN_3D_CHANNEL_MAX, + sizeof(struct iio_chan_spec), + GFP_KERNEL); if (!channels) { - dev_err(&pdev->dev, "failed to duplicate channels\n"); + dev_err(&pdev->dev, "failed to allocate memory for iio channel\n"); return -ENOMEM; } @@ -322,7 +405,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) } indio_dev->channels = channels; - indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels); + indio_dev->num_channels = magn_state->num_iio_channels;
With a bit of rearranging it strikes me that you can fill num_channels directly rather than having another copy of it....
indio_dev->dev.parent = &pdev->dev; indio_dev->info = &magn_3d_info; indio_dev->name = name;
-- 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