static int magn_3d_parse_report()

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;
}