Skip to content

Commit 77d3d8e

Browse files
spandruvadagregkh
authored andcommitted
HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads
commit f784fce upstream. sensor_hub_input_attr_get_raw_value() is limited to returning a single 32-bit value, which is insufficient for sensors that report data larger than 32 bits, such as a quaternion with four s16 elements. Add sensor_hub_input_attr_read_values() that accepts a caller-provided buffer and accumulates incoming data until the buffer is full. The two paths are distinguished in sensor_hub_raw_event() by pending.max_raw_size being non-zero, preserving backward compatibility. Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Co-developed-by: Zhang Lixu <lixu.zhang@intel.com> Signed-off-by: Zhang Lixu <lixu.zhang@intel.com> Acked-by: Jiri Kosina <jkosina@suse.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com> Cc: <Stable@vger.kernel.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent acce9de commit 77d3d8e

2 files changed

Lines changed: 96 additions & 6 deletions

File tree

drivers/hid/hid-sensor-hub.c

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,54 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
286286
}
287287
EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
288288

289+
int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
290+
u32 usage_id, u32 attr_usage_id,
291+
u32 report_id,
292+
enum sensor_hub_read_flags flag,
293+
u32 buffer_size, u8 *buffer)
294+
{
295+
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
296+
struct hid_report *report;
297+
unsigned long flags;
298+
long cycles;
299+
int ret;
300+
301+
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
302+
if (!report)
303+
return -EINVAL;
304+
305+
mutex_lock(hsdev->mutex_ptr);
306+
if (flag == SENSOR_HUB_SYNC) {
307+
memset(&hsdev->pending, 0, sizeof(hsdev->pending));
308+
init_completion(&hsdev->pending.ready);
309+
hsdev->pending.usage_id = usage_id;
310+
hsdev->pending.attr_usage_id = attr_usage_id;
311+
hsdev->pending.max_raw_size = buffer_size;
312+
hsdev->pending.raw_data = buffer;
313+
314+
spin_lock_irqsave(&data->lock, flags);
315+
hsdev->pending.status = true;
316+
spin_unlock_irqrestore(&data->lock, flags);
317+
}
318+
mutex_lock(&data->mutex);
319+
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
320+
mutex_unlock(&data->mutex);
321+
ret = 0;
322+
if (flag == SENSOR_HUB_SYNC) {
323+
cycles = wait_for_completion_interruptible_timeout(&hsdev->pending.ready,
324+
HZ * 5);
325+
if (cycles == 0)
326+
ret = -ETIMEDOUT;
327+
else if (cycles < 0)
328+
ret = cycles;
329+
330+
hsdev->pending.status = false;
331+
}
332+
mutex_unlock(hsdev->mutex_ptr);
333+
334+
return ret;
335+
}
336+
EXPORT_SYMBOL_GPL(sensor_hub_input_attr_read_values);
289337

290338
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
291339
u32 usage_id,
@@ -479,6 +527,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
479527
struct hid_collection *collection = NULL;
480528
void *priv = NULL;
481529
struct hid_sensor_hub_device *hsdev = NULL;
530+
u32 copy_size;
531+
u32 avail;
482532

483533
hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
484534
report->id, size, report->type);
@@ -518,12 +568,27 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
518568
hsdev->pending.attr_usage_id ==
519569
report->field[i]->logical)) {
520570
hid_dbg(hdev, "data was pending ...\n");
521-
hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
522-
if (hsdev->pending.raw_data)
523-
hsdev->pending.raw_size = sz;
524-
else
525-
hsdev->pending.raw_size = 0;
526-
complete(&hsdev->pending.ready);
571+
if (hsdev->pending.max_raw_size) {
572+
if (hsdev->pending.index < hsdev->pending.max_raw_size) {
573+
avail = hsdev->pending.max_raw_size - hsdev->pending.index;
574+
copy_size = clamp(sz, 0U, avail);
575+
576+
memcpy(hsdev->pending.raw_data + hsdev->pending.index,
577+
ptr, copy_size);
578+
hsdev->pending.index += copy_size;
579+
if (hsdev->pending.index >= hsdev->pending.max_raw_size) {
580+
hsdev->pending.raw_size = hsdev->pending.index;
581+
complete(&hsdev->pending.ready);
582+
}
583+
}
584+
} else {
585+
hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
586+
if (hsdev->pending.raw_data)
587+
hsdev->pending.raw_size = sz;
588+
else
589+
hsdev->pending.raw_size = 0;
590+
complete(&hsdev->pending.ready);
591+
}
527592
}
528593
if (callback->capture_sample) {
529594
if (report->field[i]->logical)

include/linux/hid-sensor-hub.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ struct hid_sensor_hub_attribute_info {
4343
* @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro.
4444
* @raw_size: Response size for a read request.
4545
* @raw_data: Place holder for received response.
46+
* @index: Current write index into raw_data for multi-byte reads.
47+
* @max_raw_size: Total buffer size for multi-byte reads; 0 for single-value reads.
4648
*/
4749
struct sensor_hub_pending {
4850
bool status;
@@ -51,6 +53,8 @@ struct sensor_hub_pending {
5153
u32 attr_usage_id;
5254
int raw_size;
5355
u8 *raw_data;
56+
u32 index;
57+
u32 max_raw_size;
5458
};
5559

5660
/**
@@ -182,6 +186,27 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
182186
bool is_signed
183187
);
184188

189+
/**
190+
* sensor_hub_input_attr_read_values() - Synchronous multi-byte read request
191+
* @hsdev: Hub device instance.
192+
* @usage_id: Attribute usage id of parent physical device as per spec
193+
* @attr_usage_id: Attribute usage id as per spec
194+
* @report_id: Report id to look for
195+
* @flag: Synchronous or asynchronous read
196+
* @buffer_size: Size of the buffer in bytes
197+
* @buffer: Buffer to store the read data
198+
*
199+
* Issues a synchronous or asynchronous read request for an input attribute,
200+
* accumulating data into the provided buffer until it is full.
201+
* Return: 0 on success, -ETIMEDOUT if the device did not respond, or a
202+
* negative error code.
203+
*/
204+
int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
205+
u32 usage_id, u32 attr_usage_id,
206+
u32 report_id,
207+
enum sensor_hub_read_flags flag,
208+
u32 buffer_size, u8 *buffer);
209+
185210
/**
186211
* sensor_hub_set_feature() - Feature set request
187212
* @hsdev: Hub device instance.

0 commit comments

Comments
 (0)