in magnetometer/hid-sensor-magn-3d.c [349:464]
static int magn_3d_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec **channels,
int *chan_count,
unsigned usage_id,
struct magn_3d_state *st)
{
int i;
int attr_count = 0;
struct iio_chan_spec *_channels;
/* Scan for each usage attribute supported */
for (i = 0; i < MAGN_3D_CHANNEL_MAX; i++) {
int status;
u32 address = magn_3d_addresses[i];
/* Check if usage attribute exists in the sensor hub device */
status = sensor_hub_input_get_attribute_info(hsdev,
HID_INPUT_REPORT,
usage_id,
address,
&(st->magn[i]));
if (!status)
attr_count++;
}
if (attr_count <= 0) {
dev_err(&pdev->dev,
"failed to find any supported usage attributes in report\n");
return -EINVAL;
}
dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n",
attr_count);
dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %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);
/* Setup IIO channel array */
_channels = devm_kcalloc(&pdev->dev, attr_count,
sizeof(struct iio_chan_spec),
GFP_KERNEL);
if (!_channels) {
dev_err(&pdev->dev,
"failed to allocate space for iio channels\n");
return -ENOMEM;
}
/* attr_count include timestamp channel, and the iio_vals should be aligned to 8byte */
st->iio_vals = devm_kcalloc(&pdev->dev,
((attr_count + 1) % 2 + (attr_count + 1) / 2) * 2,
sizeof(u32), GFP_KERNEL);
if (!st->iio_vals) {
dev_err(&pdev->dev,
"failed to allocate space for iio values array\n");
return -ENOMEM;
}
for (i = 0, *chan_count = 0;
i < MAGN_3D_CHANNEL_MAX && *chan_count < attr_count;
i++){
if (st->magn[i].index >= 0) {
/* Setup IIO channel struct */
(_channels[*chan_count]) = magn_3d_channels[i];
(_channels[*chan_count]).scan_index = *chan_count;
(_channels[*chan_count]).address = i;
if (i != CHANNEL_SCAN_INDEX_TIMESTAMP) {
/* Set magn_val_addr to iio value address */
st->magn_val_addr[i] = &st->iio_vals[*chan_count];
magn_3d_adjust_channel_bit_mask(_channels,
*chan_count,
st->magn[i].size);
}
(*chan_count)++;
}
}
if (*chan_count <= 0) {
dev_err(&pdev->dev,
"failed to find any magnetic channels setup\n");
return -EINVAL;
}
*channels = _channels;
dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n",
*chan_count);
st->magn_flux_attr.scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_COMPASS_3D,
&st->magn[CHANNEL_SCAN_INDEX_X],
&st->magn_flux_attr.scale_pre_decml,
&st->magn_flux_attr.scale_post_decml);
st->rot_attr.scale_precision
= hid_sensor_format_scale(
HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH,
&st->magn[CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP],
&st->rot_attr.scale_pre_decml,
&st->rot_attr.scale_post_decml);
if (st->rot_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_ORIENT_COMP_MAGN_NORTH,
&st->rot_attributes.sensitivity);
dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
st->rot_attributes.sensitivity.index,
st->rot_attributes.sensitivity.report_id);
}
return 0;
}