Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: hid-sensors: Use software trigger

Recent changes linux mainline resulted in warning:
"genirq: Warn about using IRQF_ONESHOT without a threaded handler"
when HID sensor hub is used.

When INDIO_BUFFER_TRIGGERED is used, the core attaches a poll function
when enabling the buffer. This poll function uses request_threaded_irq()
with both bottom half and top half handlers. But when using HID
sensor hub, bottom half (thread handler) is not registered.

In HID sensors, once a sensor is powered on, the hub collects samples
and pushes data to the host when programmed thresholds are met. When
this data is received for a sensor, it is pushed using
iio_push_to_buffers_with_ts().

The sensor is powered ON or OFF based on the trigger callback
set_trigger_state() when the poll function is attached. During the call
to iio_triggered_buffer_setup_ext(), the HID sensor specifies only a
handler function but provides no thread handler, as there is no data
to read from the hub in thread context. Internally, this results in
calling request_threaded_irq(). Recent kernel changes now warn when
request_threaded_irq() is called without a thread handler.

To address this issue, fundamental changes are required to avoid using
iio_triggered_buffer_setup_ext(). HID sensors can use
INDIO_BUFFER_SOFTWARE instead of INDIO_BUFFER_TRIGGERED, as this can
work in trigger-less mode.

In this approach, when user space opens the buffer, the sensor is powered
on, and when the buffer is closed, the sensor is powered off using
iio_buffer_setup_ops callbacks.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Srinivas Pandruvada and committed by
Jonathan Cameron
c47ac75f 20c2a46d

+30 -18
+30 -18
drivers/iio/common/hid-sensors/hid-sensor-trigger.c
··· 14 14 #include <linux/iio/triggered_buffer.h> 15 15 #include <linux/iio/trigger_consumer.h> 16 16 #include <linux/iio/sysfs.h> 17 + #include <linux/iio/kfifo_buf.h> 17 18 #include "hid-sensor-trigger.h" 18 19 19 20 static ssize_t _hid_sensor_set_report_latency(struct device *dev, ··· 203 202 _hid_sensor_power_state(attrb, true); 204 203 } 205 204 206 - static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, 207 - bool state) 205 + static int buffer_postenable(struct iio_dev *indio_dev) 208 206 { 209 - return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state); 207 + return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 1); 210 208 } 209 + 210 + static int buffer_predisable(struct iio_dev *indio_dev) 211 + { 212 + return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 0); 213 + } 214 + 215 + static const struct iio_buffer_setup_ops hid_sensor_buffer_ops = { 216 + .postenable = buffer_postenable, 217 + .predisable = buffer_predisable, 218 + }; 211 219 212 220 void hid_sensor_remove_trigger(struct iio_dev *indio_dev, 213 221 struct hid_sensor_common *attrb) ··· 229 219 cancel_work_sync(&attrb->work); 230 220 iio_trigger_unregister(attrb->trigger); 231 221 iio_trigger_free(attrb->trigger); 232 - iio_triggered_buffer_cleanup(indio_dev); 233 222 } 234 223 EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, "IIO_HID"); 235 - 236 - static const struct iio_trigger_ops hid_sensor_trigger_ops = { 237 - .set_trigger_state = &hid_sensor_data_rdy_trigger_set_state, 238 - }; 239 224 240 225 int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, 241 226 struct hid_sensor_common *attrb) ··· 244 239 else 245 240 fifo_attrs = NULL; 246 241 247 - ret = iio_triggered_buffer_setup_ext(indio_dev, 248 - &iio_pollfunc_store_time, NULL, 249 - IIO_BUFFER_DIRECTION_IN, 250 - NULL, fifo_attrs); 242 + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED; 243 + 244 + ret = devm_iio_kfifo_buffer_setup_ext(&indio_dev->dev, indio_dev, 245 + &hid_sensor_buffer_ops, 246 + fifo_attrs); 251 247 if (ret) { 252 - dev_err(&indio_dev->dev, "Triggered Buffer Setup Failed\n"); 248 + dev_err(&indio_dev->dev, "Kfifo Buffer Setup Failed\n"); 253 249 return ret; 254 250 } 251 + 252 + /* 253 + * The current user space in distro "iio-sensor-proxy" is not working in 254 + * trigerless mode and it expects 255 + * /sys/bus/iio/devices/iio:device0/trigger/current_trigger. 256 + * The change replacing iio_triggered_buffer_setup_ext() with 257 + * devm_iio_kfifo_buffer_setup_ext() will not create attribute without 258 + * registering a trigger with INDIO_HARDWARE_TRIGGERED. 259 + * So the below code fragment is still required. 260 + */ 255 261 256 262 trig = iio_trigger_alloc(indio_dev->dev.parent, 257 263 "%s-dev%d", name, iio_device_id(indio_dev)); 258 264 if (trig == NULL) { 259 265 dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); 260 - ret = -ENOMEM; 261 - goto error_triggered_buffer_cleanup; 266 + return -ENOMEM; 262 267 } 263 268 264 269 iio_trigger_set_drvdata(trig, attrb); 265 - trig->ops = &hid_sensor_trigger_ops; 266 270 ret = iio_trigger_register(trig); 267 271 268 272 if (ret) { ··· 298 284 iio_trigger_unregister(trig); 299 285 error_free_trig: 300 286 iio_trigger_free(trig); 301 - error_triggered_buffer_cleanup: 302 - iio_triggered_buffer_cleanup(indio_dev); 303 287 return ret; 304 288 } 305 289 EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, "IIO_HID");