aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/magnetometer/hid-sensor-magn-3d.c
diff options
context:
space:
mode:
authorReyad Attiyat <reyad.attiyat@gmail.com>2014-07-17 14:18:00 -0400
committerJonathan Cameron <jic23@kernel.org>2014-07-20 08:37:52 -0400
commit2a96540a5c0d136c3c412ec650fad301aaf12bf7 (patch)
tree8ee00e69e046591c6f50c2cea03714a937b2da1b /drivers/iio/magnetometer/hid-sensor-magn-3d.c
parent11b8ddab817eb8070a542d33caeb93cccfa4e383 (diff)
iio: hid-sensor-magn-3d: Scan for usage attributes before setting up iio channels
Scan for and count the HID usage attributes supported by the driver. This allows for the driver to only setup the IIO channels for the sensor usages present in the HID USB reports. Changes from v5 -Fixed kernel panic from invalid pointer dereference -Fixed variable assignment style Signed-off-by: Reyad Attiyat <reyad.attiyat@gmail.com> Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/magnetometer/hid-sensor-magn-3d.c')
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c149
1 files changed, 105 insertions, 44 deletions
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index 41cf29e2a371..c0a659cc6715 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -42,7 +42,12 @@ struct magn_3d_state {
42 struct hid_sensor_hub_callbacks callbacks; 42 struct hid_sensor_hub_callbacks callbacks;
43 struct hid_sensor_common common_attributes; 43 struct hid_sensor_common common_attributes;
44 struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX]; 44 struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
45 u32 magn_val[MAGN_3D_CHANNEL_MAX]; 45
46 /* dynamically sized array to hold sensor values */
47 u32 *iio_vals;
48 /* array of pointers to sensor value */
49 u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX];
50
46 int scale_pre_decml; 51 int scale_pre_decml;
47 int scale_post_decml; 52 int scale_post_decml;
48 int scale_precision; 53 int scale_precision;
@@ -66,7 +71,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
66 BIT(IIO_CHAN_INFO_SCALE) | 71 BIT(IIO_CHAN_INFO_SCALE) |
67 BIT(IIO_CHAN_INFO_SAMP_FREQ) | 72 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
68 BIT(IIO_CHAN_INFO_HYSTERESIS), 73 BIT(IIO_CHAN_INFO_HYSTERESIS),
69 .scan_index = CHANNEL_SCAN_INDEX_X,
70 }, { 74 }, {
71 .type = IIO_MAGN, 75 .type = IIO_MAGN,
72 .modified = 1, 76 .modified = 1,
@@ -76,7 +80,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
76 BIT(IIO_CHAN_INFO_SCALE) | 80 BIT(IIO_CHAN_INFO_SCALE) |
77 BIT(IIO_CHAN_INFO_SAMP_FREQ) | 81 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
78 BIT(IIO_CHAN_INFO_HYSTERESIS), 82 BIT(IIO_CHAN_INFO_HYSTERESIS),
79 .scan_index = CHANNEL_SCAN_INDEX_Y,
80 }, { 83 }, {
81 .type = IIO_MAGN, 84 .type = IIO_MAGN,
82 .modified = 1, 85 .modified = 1,
@@ -86,7 +89,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
86 BIT(IIO_CHAN_INFO_SCALE) | 89 BIT(IIO_CHAN_INFO_SCALE) |
87 BIT(IIO_CHAN_INFO_SAMP_FREQ) | 90 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
88 BIT(IIO_CHAN_INFO_HYSTERESIS), 91 BIT(IIO_CHAN_INFO_HYSTERESIS),
89 .scan_index = CHANNEL_SCAN_INDEX_Z,
90 } 92 }
91}; 93};
92 94
@@ -127,8 +129,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
127 msleep_interruptible(poll_value * 2); 129 msleep_interruptible(poll_value * 2);
128 130
129 report_id = 131 report_id =
130 magn_state->magn[chan->scan_index].report_id; 132 magn_state->magn[chan->address].report_id;
131 address = magn_3d_addresses[chan->scan_index]; 133 address = magn_3d_addresses[chan->address];
132 if (report_id >= 0) 134 if (report_id >= 0)
133 *val = sensor_hub_input_attr_get_raw_value( 135 *val = sensor_hub_input_attr_get_raw_value(
134 magn_state->common_attributes.hsdev, 136 magn_state->common_attributes.hsdev,
@@ -221,8 +223,8 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
221 dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); 223 dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n");
222 if (atomic_read(&magn_state->common_attributes.data_ready)) 224 if (atomic_read(&magn_state->common_attributes.data_ready))
223 hid_sensor_push_data(indio_dev, 225 hid_sensor_push_data(indio_dev,
224 magn_state->magn_val, 226 magn_state->iio_vals,
225 sizeof(magn_state->magn_val)); 227 sizeof(magn_state->iio_vals));
226 228
227 return 0; 229 return 0;
228} 230}
@@ -236,52 +238,119 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
236 struct iio_dev *indio_dev = platform_get_drvdata(priv); 238 struct iio_dev *indio_dev = platform_get_drvdata(priv);
237 struct magn_3d_state *magn_state = iio_priv(indio_dev); 239 struct magn_3d_state *magn_state = iio_priv(indio_dev);
238 int offset; 240 int offset;
239 int ret = -EINVAL; 241 int ret = 0;
242 u32 *iio_val = NULL;
240 243
241 switch (usage_id) { 244 switch (usage_id) {
242 case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS: 245 case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS:
243 case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS: 246 case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS:
244 case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS: 247 case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS:
245 offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS; 248 offset = (usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS)
246 magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] = 249 + CHANNEL_SCAN_INDEX_X;
247 *(u32 *)raw_data;
248 ret = 0;
249 break; 250 break;
250 default: 251 default:
251 break; 252 return -EINVAL;
252 } 253 }
253 254
255 iio_val = magn_state->magn_val_addr[offset];
256
257 if (iio_val != NULL)
258 *iio_val = *((u32 *)raw_data);
259 else
260 ret = -EINVAL;
261
254 return ret; 262 return ret;
255} 263}
256 264
257/* Parse report which is specific to an usage id*/ 265/* Parse report which is specific to an usage id*/
258static int magn_3d_parse_report(struct platform_device *pdev, 266static int magn_3d_parse_report(struct platform_device *pdev,
259 struct hid_sensor_hub_device *hsdev, 267 struct hid_sensor_hub_device *hsdev,
260 struct iio_chan_spec *channels, 268 struct iio_chan_spec **channels,
269 int *chan_count,
261 unsigned usage_id, 270 unsigned usage_id,
262 struct magn_3d_state *st) 271 struct magn_3d_state *st)
263{ 272{
264 int ret;
265 int i; 273 int i;
274 int attr_count = 0;
275 struct iio_chan_spec *_channels;
276
277 /* Scan for each usage attribute supported */
278 for (i = 0; i < MAGN_3D_CHANNEL_MAX; i++) {
279 int status;
280 u32 address = magn_3d_addresses[i];
281
282 /* Check if usage attribute exists in the sensor hub device */
283 status = sensor_hub_input_get_attribute_info(hsdev,
284 HID_INPUT_REPORT,
285 usage_id,
286 address,
287 &(st->magn[i]));
288 if (!status)
289 attr_count++;
290 }
266 291
267 for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { 292 if (attr_count <= 0) {
268 ret = sensor_hub_input_get_attribute_info(hsdev, 293 dev_err(&pdev->dev,
269 HID_INPUT_REPORT, 294 "failed to find any supported usage attributes in report\n");
270 usage_id, 295 return -EINVAL;
271 HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i,
272 &st->magn[CHANNEL_SCAN_INDEX_X + i]);
273 if (ret < 0)
274 break;
275 magn_3d_adjust_channel_bit_mask(channels,
276 CHANNEL_SCAN_INDEX_X + i,
277 st->magn[CHANNEL_SCAN_INDEX_X + i].size);
278 } 296 }
279 dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n", 297
298 dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n",
299 attr_count);
300 dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n",
280 st->magn[0].index, 301 st->magn[0].index,
281 st->magn[0].report_id, 302 st->magn[0].report_id,
282 st->magn[1].index, st->magn[1].report_id, 303 st->magn[1].index, st->magn[1].report_id,
283 st->magn[2].index, st->magn[2].report_id); 304 st->magn[2].index, st->magn[2].report_id);
284 305
306 /* Setup IIO channel array */
307 _channels = devm_kcalloc(&pdev->dev, attr_count,
308 sizeof(struct iio_chan_spec),
309 GFP_KERNEL);
310 if (!_channels) {
311 dev_err(&pdev->dev,
312 "failed to allocate space for iio channels\n");
313 return -ENOMEM;
314 }
315
316 st->iio_vals = devm_kcalloc(&pdev->dev, attr_count,
317 sizeof(u32),
318 GFP_KERNEL);
319 if (!st->iio_vals) {
320 dev_err(&pdev->dev,
321 "failed to allocate space for iio values array\n");
322 return -ENOMEM;
323 }
324
325 for (i = 0, *chan_count = 0;
326 i < MAGN_3D_CHANNEL_MAX && *chan_count < attr_count;
327 i++){
328 if (st->magn[i].index >= 0) {
329 /* Setup IIO channel struct */
330 (_channels[*chan_count]) = magn_3d_channels[i];
331 (_channels[*chan_count]).scan_index = *chan_count;
332 (_channels[*chan_count]).address = i;
333
334 /* Set magn_val_addr to iio value address */
335 st->magn_val_addr[i] = &(st->iio_vals[*chan_count]);
336 magn_3d_adjust_channel_bit_mask(_channels,
337 *chan_count,
338 st->magn[i].size);
339 (*chan_count)++;
340 }
341 }
342
343 if (*chan_count <= 0) {
344 dev_err(&pdev->dev,
345 "failed to find any magnetic channels setup\n");
346 return -EINVAL;
347 }
348
349 *channels = _channels;
350
351 dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n",
352 *chan_count);
353
285 st->scale_precision = hid_sensor_format_scale( 354 st->scale_precision = hid_sensor_format_scale(
286 HID_USAGE_SENSOR_COMPASS_3D, 355 HID_USAGE_SENSOR_COMPASS_3D,
287 &st->magn[CHANNEL_SCAN_INDEX_X], 356 &st->magn[CHANNEL_SCAN_INDEX_X],
@@ -299,7 +368,7 @@ static int magn_3d_parse_report(struct platform_device *pdev,
299 st->common_attributes.sensitivity.report_id); 368 st->common_attributes.sensitivity.report_id);
300 } 369 }
301 370
302 return ret; 371 return 0;
303} 372}
304 373
305/* Function to initialize the processing for usage id */ 374/* Function to initialize the processing for usage id */
@@ -311,6 +380,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
311 struct magn_3d_state *magn_state; 380 struct magn_3d_state *magn_state;
312 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 381 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
313 struct iio_chan_spec *channels; 382 struct iio_chan_spec *channels;
383 int chan_count = 0;
314 384
315 indio_dev = devm_iio_device_alloc(&pdev->dev, 385 indio_dev = devm_iio_device_alloc(&pdev->dev,
316 sizeof(struct magn_3d_state)); 386 sizeof(struct magn_3d_state));
@@ -331,22 +401,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
331 return ret; 401 return ret;
332 } 402 }
333 403
334 channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels), 404 ret = magn_3d_parse_report(pdev, hsdev,
335 GFP_KERNEL); 405 &channels, &chan_count,
336 if (!channels) {
337 dev_err(&pdev->dev, "failed to duplicate channels\n");
338 return -ENOMEM;
339 }
340
341 ret = magn_3d_parse_report(pdev, hsdev, channels,
342 HID_USAGE_SENSOR_COMPASS_3D, magn_state); 406 HID_USAGE_SENSOR_COMPASS_3D, magn_state);
343 if (ret) { 407 if (ret) {
344 dev_err(&pdev->dev, "failed to setup attributes\n"); 408 dev_err(&pdev->dev, "failed to parse report\n");
345 goto error_free_dev_mem; 409 return ret;
346 } 410 }
347 411
348 indio_dev->channels = channels; 412 indio_dev->channels = channels;
349 indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels); 413 indio_dev->num_channels = chan_count;
350 indio_dev->dev.parent = &pdev->dev; 414 indio_dev->dev.parent = &pdev->dev;
351 indio_dev->info = &magn_3d_info; 415 indio_dev->info = &magn_3d_info;
352 indio_dev->name = name; 416 indio_dev->name = name;
@@ -356,7 +420,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
356 NULL, NULL); 420 NULL, NULL);
357 if (ret) { 421 if (ret) {
358 dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); 422 dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
359 goto error_free_dev_mem; 423 return ret;
360 } 424 }
361 atomic_set(&magn_state->common_attributes.data_ready, 0); 425 atomic_set(&magn_state->common_attributes.data_ready, 0);
362 ret = hid_sensor_setup_trigger(indio_dev, name, 426 ret = hid_sensor_setup_trigger(indio_dev, name,
@@ -390,8 +454,6 @@ error_remove_trigger:
390 hid_sensor_remove_trigger(&magn_state->common_attributes); 454 hid_sensor_remove_trigger(&magn_state->common_attributes);
391error_unreg_buffer_funcs: 455error_unreg_buffer_funcs:
392 iio_triggered_buffer_cleanup(indio_dev); 456 iio_triggered_buffer_cleanup(indio_dev);
393error_free_dev_mem:
394 kfree(indio_dev->channels);
395 return ret; 457 return ret;
396} 458}
397 459
@@ -406,7 +468,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
406 iio_device_unregister(indio_dev); 468 iio_device_unregister(indio_dev);
407 hid_sensor_remove_trigger(&magn_state->common_attributes); 469 hid_sensor_remove_trigger(&magn_state->common_attributes);
408 iio_triggered_buffer_cleanup(indio_dev); 470 iio_triggered_buffer_cleanup(indio_dev);
409 kfree(indio_dev->channels);
410 471
411 return 0; 472 return 0;
412} 473}