mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-21 23:57:36 -04:00
HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads
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>
This commit is contained in:
committed by
Jonathan Cameron
parent
3ee2128b6f
commit
f784fcea45
@@ -286,6 +286,54 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
|
||||
|
||||
int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
|
||||
u32 usage_id, u32 attr_usage_id,
|
||||
u32 report_id,
|
||||
enum sensor_hub_read_flags flag,
|
||||
u32 buffer_size, u8 *buffer)
|
||||
{
|
||||
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
|
||||
struct hid_report *report;
|
||||
unsigned long flags;
|
||||
long cycles;
|
||||
int ret;
|
||||
|
||||
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
|
||||
if (!report)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(hsdev->mutex_ptr);
|
||||
if (flag == SENSOR_HUB_SYNC) {
|
||||
memset(&hsdev->pending, 0, sizeof(hsdev->pending));
|
||||
init_completion(&hsdev->pending.ready);
|
||||
hsdev->pending.usage_id = usage_id;
|
||||
hsdev->pending.attr_usage_id = attr_usage_id;
|
||||
hsdev->pending.max_raw_size = buffer_size;
|
||||
hsdev->pending.raw_data = buffer;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
hsdev->pending.status = true;
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
}
|
||||
mutex_lock(&data->mutex);
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
|
||||
mutex_unlock(&data->mutex);
|
||||
ret = 0;
|
||||
if (flag == SENSOR_HUB_SYNC) {
|
||||
cycles = wait_for_completion_interruptible_timeout(&hsdev->pending.ready,
|
||||
HZ * 5);
|
||||
if (cycles == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
else if (cycles < 0)
|
||||
ret = cycles;
|
||||
|
||||
hsdev->pending.status = false;
|
||||
}
|
||||
mutex_unlock(hsdev->mutex_ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sensor_hub_input_attr_read_values);
|
||||
|
||||
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
|
||||
u32 usage_id,
|
||||
@@ -478,6 +526,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
|
||||
struct hid_collection *collection = NULL;
|
||||
void *priv = NULL;
|
||||
struct hid_sensor_hub_device *hsdev = NULL;
|
||||
u32 copy_size;
|
||||
u32 avail;
|
||||
|
||||
hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
|
||||
report->id, size, report->type);
|
||||
@@ -518,12 +568,27 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
|
||||
hsdev->pending.attr_usage_id ==
|
||||
report->field[i]->logical)) {
|
||||
hid_dbg(hdev, "data was pending ...\n");
|
||||
hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
|
||||
if (hsdev->pending.raw_data)
|
||||
hsdev->pending.raw_size = sz;
|
||||
else
|
||||
hsdev->pending.raw_size = 0;
|
||||
complete(&hsdev->pending.ready);
|
||||
if (hsdev->pending.max_raw_size) {
|
||||
if (hsdev->pending.index < hsdev->pending.max_raw_size) {
|
||||
avail = hsdev->pending.max_raw_size - hsdev->pending.index;
|
||||
copy_size = clamp(sz, 0U, avail);
|
||||
|
||||
memcpy(hsdev->pending.raw_data + hsdev->pending.index,
|
||||
ptr, copy_size);
|
||||
hsdev->pending.index += copy_size;
|
||||
if (hsdev->pending.index >= hsdev->pending.max_raw_size) {
|
||||
hsdev->pending.raw_size = hsdev->pending.index;
|
||||
complete(&hsdev->pending.ready);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
|
||||
if (hsdev->pending.raw_data)
|
||||
hsdev->pending.raw_size = sz;
|
||||
else
|
||||
hsdev->pending.raw_size = 0;
|
||||
complete(&hsdev->pending.ready);
|
||||
}
|
||||
}
|
||||
if (callback->capture_sample) {
|
||||
if (report->field[i]->logical)
|
||||
|
||||
@@ -43,6 +43,8 @@ struct hid_sensor_hub_attribute_info {
|
||||
* @attr_usage_id: Usage Id of a field, e.g. X-axis for a gyro.
|
||||
* @raw_size: Response size for a read request.
|
||||
* @raw_data: Place holder for received response.
|
||||
* @index: Current write index into raw_data for multi-byte reads.
|
||||
* @max_raw_size: Total buffer size for multi-byte reads; 0 for single-value reads.
|
||||
*/
|
||||
struct sensor_hub_pending {
|
||||
bool status;
|
||||
@@ -51,6 +53,8 @@ struct sensor_hub_pending {
|
||||
u32 attr_usage_id;
|
||||
int raw_size;
|
||||
u8 *raw_data;
|
||||
u32 index;
|
||||
u32 max_raw_size;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -183,6 +187,27 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
|
||||
bool is_signed
|
||||
);
|
||||
|
||||
/**
|
||||
* sensor_hub_input_attr_read_values() - Synchronous multi-byte read request
|
||||
* @hsdev: Hub device instance.
|
||||
* @usage_id: Attribute usage id of parent physical device as per spec
|
||||
* @attr_usage_id: Attribute usage id as per spec
|
||||
* @report_id: Report id to look for
|
||||
* @flag: Synchronous or asynchronous read
|
||||
* @buffer_size: Size of the buffer in bytes
|
||||
* @buffer: Buffer to store the read data
|
||||
*
|
||||
* Issues a synchronous or asynchronous read request for an input attribute,
|
||||
* accumulating data into the provided buffer until it is full.
|
||||
* Return: 0 on success, -ETIMEDOUT if the device did not respond, or a
|
||||
* negative error code.
|
||||
*/
|
||||
int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
|
||||
u32 usage_id, u32 attr_usage_id,
|
||||
u32 report_id,
|
||||
enum sensor_hub_read_flags flag,
|
||||
u32 buffer_size, u8 *buffer);
|
||||
|
||||
/**
|
||||
* sensor_hub_set_feature() - Feature set request
|
||||
* @hsdev: Hub device instance.
|
||||
|
||||
Reference in New Issue
Block a user