diff mbox series

[v9,6/8] Refactored HID LL driver.

Message ID 20210123134716.13414-7-mail@richard-neumann.de (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show
Series AMD Sensor Fusion Hub driver refactored | expand

Commit Message

Richard Neumann Jan. 23, 2021, 1:47 p.m. UTC
From: Richard Neumann <mail@richard-neumann.de>

Refactored the HID low-level driver to implement the according API.
Implemented functions:

* parse
* start
* stop
* open
* close
* raw_request

Signed-off-by: Richard Neumann <mail@richard-neumann.de>
---
 drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.c | 175 +++++++++++++++++++
 drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.h |  41 +++++
 drivers/hid/amd-sfh-hid/amd_sfh_hid.c        | 174 ------------------
 drivers/hid/amd-sfh-hid/amd_sfh_hid.h        |  67 -------
 4 files changed, 216 insertions(+), 241 deletions(-)
 create mode 100644 drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.c
 create mode 100644 drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.h
 delete mode 100644 drivers/hid/amd-sfh-hid/amd_sfh_hid.c
 delete mode 100644 drivers/hid/amd-sfh-hid/amd_sfh_hid.h
diff mbox series

Patch

diff --git a/drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.c b/drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.c
new file mode 100644
index 000000000000..8667ef41062c
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.c
@@ -0,0 +1,175 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * AMD Sensor Fusion Hub HID low-level driver
+ *
+ * Authors: Sandeep Singh <sandeep.singh@amd.com>
+ *          Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
+ *          Richard Neumann <mail@richard-neumann.de>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/hid.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+
+#include "amd-sfh-hid-ll-drv.h"
+#include "amd-sfh-hid-reports.h"
+#include "amd-sfh-pci.h"
+
+#define AMD_SFH_HID_DMA_SIZE	(sizeof(int) * 8)
+
+/**
+ * amd_sfh_hid_ll_parse - Callback to parse HID descriptor.
+ * @hid:	The HID device
+ *
+ * This function gets called during call to hid_add_device
+ *
+ * Return: 0 on success and non zero on error.
+ */
+static int amd_sfh_hid_ll_parse(struct hid_device *hid)
+{
+	int rc;
+	u8 *buf;
+	size_t size;
+	struct amd_sfh_hid_data *hid_data;
+
+	hid_data = hid->driver_data;
+
+	size = get_descriptor_size(hid_data->sensor_idx, AMD_SFH_DESCRIPTOR);
+	if (size < 0) {
+		hid_err(hid, "Failed to get report descriptor size!\n");
+		return -EINVAL;
+	}
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	rc = get_report_descriptor(hid_data->sensor_idx, buf);
+	if (rc) {
+		hid_err(hid, "Failed to get report descriptor!\n");
+		goto free_buf;
+	}
+
+	rc = hid_parse_report(hid, buf, size);
+	if (rc)
+		hid_err(hid, "Failed to parse HID report!\n");
+
+free_buf:
+	kfree(buf);
+	return rc;
+}
+
+/**
+ * amd_sfh_hid_ll_start - Starts the HID device.
+ * @hid:	The HID device
+ *
+ * Allocates DMA memory on the PCI device.
+ * Returns 0 on success and non-zero on error.
+ */
+static int amd_sfh_hid_ll_start(struct hid_device *hid)
+{
+	struct amd_sfh_hid_data *hid_data = hid->driver_data;
+
+	hid_data->cpu_addr = dma_alloc_coherent(&hid_data->pci_dev->dev,
+						AMD_SFH_HID_DMA_SIZE,
+						&hid_data->dma_handle,
+						GFP_KERNEL);
+	if (!hid_data->cpu_addr)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * amd_sfh_hid_ll_stop - Stops the HID device.
+ * @hid:	The HID device
+ *
+ * Frees the DMA memory on the PCI device.
+ */
+static void amd_sfh_hid_ll_stop(struct hid_device *hid)
+{
+	struct amd_sfh_hid_data *hid_data = hid->driver_data;
+
+	dma_free_coherent(&hid_data->pci_dev->dev, AMD_SFH_HID_DMA_SIZE,
+			  hid_data->cpu_addr, hid_data->dma_handle);
+	hid_data->cpu_addr = NULL;
+}
+
+/**
+ * amd_sfh_hid_ll_open - Opens the HID device.
+ * @hid:	The HID device
+ *
+ * Starts the corresponding sensor via the PCI driver
+ * and schedules report polling.
+ * Always returns 0.
+ */
+static int amd_sfh_hid_ll_open(struct hid_device *hid)
+{
+	struct amd_sfh_hid_data *hid_data = hid->driver_data;
+
+	amd_sfh_start_sensor(hid_data->pci_dev, hid_data->sensor_idx,
+			     hid_data->dma_handle, hid_data->interval);
+	schedule_delayed_work(&hid_data->work, hid_data->interval);
+	return 0;
+}
+
+/**
+ * amd_sfh_hid_ll_close - Closes the HID device.
+ * @hid:	The HID device
+ *
+ * Stops report polling and the corresponding sensor via the PCI driver.
+ */
+static void amd_sfh_hid_ll_close(struct hid_device *hid)
+{
+	struct amd_sfh_hid_data *hid_data = hid->driver_data;
+
+	cancel_delayed_work_sync(&hid_data->work);
+	amd_sfh_stop_sensor(hid_data->pci_dev, hid_data->sensor_idx);
+}
+
+/**
+ * amd_sfh_hid_ll_raw_request - Handles HID requests.
+ * @hid:	The HID device
+ * @reportnum:	The HID report ID
+ * @buf:	The write buffer for HID data
+ * @len:	The size of the write buffer
+ * @rtype:	The report type
+ * @reqtype:	The request type
+ *
+ * Delegates to the reporting functions
+ * defined in amd-sfh-hid-descriptor.h.
+ */
+static int amd_sfh_hid_ll_raw_request(struct hid_device *hid,
+				      unsigned char reportnum, u8 *buf,
+				      size_t len, unsigned char rtype,
+				      int reqtype)
+{
+	struct amd_sfh_hid_data *hid_data = hid->driver_data;
+
+	switch (rtype) {
+	case HID_FEATURE_REPORT:
+		return get_feature_report(hid_data->sensor_idx, reportnum, buf,
+					  len);
+	case HID_INPUT_REPORT:
+		return get_input_report(hid_data->sensor_idx, reportnum, buf,
+					len, hid_data->cpu_addr);
+	default:
+		hid_err(hid, "Unsupported report type: %u\n", rtype);
+		return -EINVAL;
+	}
+}
+
+/**
+ * The HID low-level driver for SFH HID devices.
+ */
+struct hid_ll_driver amd_sfh_hid_ll_driver = {
+	.parse	=	amd_sfh_hid_ll_parse,
+	.start	=	amd_sfh_hid_ll_start,
+	.stop	=	amd_sfh_hid_ll_stop,
+	.open	=	amd_sfh_hid_ll_open,
+	.close	=	amd_sfh_hid_ll_close,
+	.raw_request  =	amd_sfh_hid_ll_raw_request,
+};
diff --git a/drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.h b/drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.h
new file mode 100644
index 000000000000..3c5ea8c7cdb0
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd-sfh-hid-ll-drv.h
@@ -0,0 +1,41 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Sensor Fusion Hub HID low-level driver interface
+ *
+ * Authors: Sandeep Singh <sandeep.singh@amd.com>
+ *          Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
+ *          Richard Neumann <mail@richard-neumann.de>
+ */
+
+#ifndef AMD_SFH_HID_LL_DRV_H
+#define AMD_SFH_HID_LL_DRV_H
+
+#include <linux/hid.h>
+#include <linux/pci.h>
+
+#include "amd-sfh-pci.h"
+
+/**
+ * struct amd_sfh_hid_data - Per HID device driver data.
+ * @sensor_idx:		The sensor index
+ * @pci_dev:		The uderlying PCI device
+ * @work:		Work buffer for device polling
+ * @hid:		Backref to the hid device
+ * @cpu_addr:		The DMA mapped CPU address
+ * @dma_handle:		The DMA handle
+ * @interval:		The sensor update interval
+ */
+struct amd_sfh_hid_data {
+	enum sensor_idx sensor_idx;
+	struct pci_dev *pci_dev;
+	struct delayed_work work;
+	struct hid_device *hid;
+	u32 *cpu_addr;
+	dma_addr_t dma_handle;
+	unsigned int interval;
+};
+
+/* The low-level driver for AMD SFH HID devices */
+extern struct hid_ll_driver amd_sfh_hid_ll_driver;
+
+#endif
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
deleted file mode 100644
index 4f989483aa03..000000000000
--- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
+++ /dev/null
@@ -1,174 +0,0 @@ 
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * AMD MP2 Sensors transport driver
- *
- * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
- *	    Sandeep Singh <sandeep.singh@amd.com>
- */
-#include <linux/hid.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-
-#include "amd_sfh_hid.h"
-
-#define AMD_SFH_RESPONSE_TIMEOUT	1500
-
-/**
- * amdtp_hid_parse() - hid-core .parse() callback
- * @hid:	hid device instance
- *
- * This function gets called during call to hid_add_device
- *
- * Return: 0 on success and non zero on error
- */
-static int amdtp_hid_parse(struct hid_device *hid)
-{
-	struct amdtp_hid_data *hid_data = hid->driver_data;
-	struct amdtp_cl_data *cli_data = hid_data->cli_data;
-
-	return hid_parse_report(hid, cli_data->report_descr[hid_data->index],
-			      cli_data->report_descr_sz[hid_data->index]);
-}
-
-/* Empty callbacks with success return code */
-static int amdtp_hid_start(struct hid_device *hid)
-{
-	return 0;
-}
-
-static void amdtp_hid_stop(struct hid_device *hid)
-{
-}
-
-static int amdtp_hid_open(struct hid_device *hid)
-{
-	return 0;
-}
-
-static void amdtp_hid_close(struct hid_device *hid)
-{
-}
-
-static int amdtp_raw_request(struct hid_device *hdev, u8 reportnum,
-			     u8 *buf, size_t len, u8 rtype, int reqtype)
-{
-	return 0;
-}
-
-static void amdtp_hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
-{
-	int rc;
-
-	switch (reqtype) {
-	case HID_REQ_GET_REPORT:
-		rc = amd_sfh_get_report(hid, rep->id, rep->type);
-		if (rc)
-			dev_err(&hid->dev, "AMDSFH  get report error\n");
-		break;
-	case HID_REQ_SET_REPORT:
-		amd_sfh_set_report(hid, rep->id, reqtype);
-		break;
-	default:
-		break;
-	}
-}
-
-static int amdtp_wait_for_response(struct hid_device *hid)
-{
-	struct amdtp_hid_data *hid_data =  hid->driver_data;
-	struct amdtp_cl_data *cli_data = hid_data->cli_data;
-	int i, ret = 0;
-
-	for (i = 0; i < cli_data->num_hid_devices; i++) {
-		if (cli_data->hid_sensor_hubs[i] == hid)
-			break;
-	}
-
-	if (!cli_data->request_done[i])
-		ret = wait_event_interruptible_timeout(hid_data->hid_wait,
-						       cli_data->request_done[i],
-						       msecs_to_jiffies(AMD_SFH_RESPONSE_TIMEOUT));
-	if (ret == -ERESTARTSYS)
-		return -ERESTARTSYS;
-	else if (ret < 0)
-		return -ETIMEDOUT;
-	else
-		return 0;
-}
-
-void amdtp_hid_wakeup(struct hid_device *hid)
-{
-	struct amdtp_hid_data *hid_data = hid->driver_data;
-	struct amdtp_cl_data *cli_data = hid_data->cli_data;
-
-	cli_data->request_done[cli_data->cur_hid_dev] = true;
-	wake_up_interruptible(&hid_data->hid_wait);
-}
-
-static struct hid_ll_driver amdtp_hid_ll_driver = {
-	.parse	=	amdtp_hid_parse,
-	.start	=	amdtp_hid_start,
-	.stop	=	amdtp_hid_stop,
-	.open	=	amdtp_hid_open,
-	.close	=	amdtp_hid_close,
-	.request  =	amdtp_hid_request,
-	.wait	=	amdtp_wait_for_response,
-	.raw_request  =	amdtp_raw_request,
-};
-
-int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data)
-{
-	struct hid_device *hid;
-	struct amdtp_hid_data *hid_data;
-	int rc;
-
-	hid = hid_allocate_device();
-	if (IS_ERR(hid))
-		return PTR_ERR(hid);
-
-	hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
-	if (!hid_data) {
-		rc = -ENOMEM;
-		goto err_hid_data;
-	}
-
-	hid->ll_driver = &amdtp_hid_ll_driver;
-	hid_data->index = cur_hid_dev;
-	hid_data->cli_data = cli_data;
-	init_waitqueue_head(&hid_data->hid_wait);
-
-	hid->driver_data = hid_data;
-	cli_data->hid_sensor_hubs[cur_hid_dev] = hid;
-	hid->bus = BUS_AMD_AMDTP;
-	hid->vendor = AMD_SFH_HID_VENDOR;
-	hid->product = AMD_SFH_HID_PRODUCT;
-	snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdtp",
-		 hid->vendor, hid->product);
-
-	rc = hid_add_device(hid);
-	if (rc)
-		goto err_hid_device;
-	return 0;
-
-err_hid_device:
-	kfree(hid_data);
-err_hid_data:
-	hid_destroy_device(hid);
-	return rc;
-}
-
-void amdtp_hid_remove(struct amdtp_cl_data *cli_data)
-{
-	int i;
-
-	for (i = 0; i < cli_data->num_hid_devices; ++i) {
-		kfree(cli_data->feature_report[i]);
-		kfree(cli_data->input_report[i]);
-		kfree(cli_data->report_descr[i]);
-		if (cli_data->hid_sensor_hubs[i]) {
-			kfree(cli_data->hid_sensor_hubs[i]->driver_data);
-			hid_destroy_device(cli_data->hid_sensor_hubs[i]);
-			cli_data->hid_sensor_hubs[i] = NULL;
-		}
-	}
-}
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
deleted file mode 100644
index d7eac1728e31..000000000000
--- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
+++ /dev/null
@@ -1,67 +0,0 @@ 
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * AMD MP2 Sensors transport driver
- *
- * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
- *	    Sandeep Singh <sandeep.singh@amd.com>
- */
-
-#ifndef AMDSFH_HID_H
-#define AMDSFH_HID_H
-
-#define MAX_HID_DEVICES		4
-#define BUS_AMD_AMDTP		0x20
-#define AMD_SFH_HID_VENDOR	0x1022
-#define AMD_SFH_HID_PRODUCT	0x0001
-
-struct amdtp_cl_data {
-	u8 init_done;
-	u32 cur_hid_dev;
-	u32 hid_dev_count;
-	u32 num_hid_devices;
-	struct device_info *hid_devices;
-	u8  *report_descr[MAX_HID_DEVICES];
-	int report_descr_sz[MAX_HID_DEVICES];
-	struct hid_device *hid_sensor_hubs[MAX_HID_DEVICES];
-	u8 *hid_descr[MAX_HID_DEVICES];
-	int hid_descr_size[MAX_HID_DEVICES];
-	phys_addr_t phys_addr_base;
-	u32 *sensor_virt_addr[MAX_HID_DEVICES];
-	dma_addr_t sensor_dma_addr[MAX_HID_DEVICES];
-	u32 sensor_sts[MAX_HID_DEVICES];
-	u32 sensor_requested_cnt[MAX_HID_DEVICES];
-	u8 report_type[MAX_HID_DEVICES];
-	u8 report_id[MAX_HID_DEVICES];
-	u8 sensor_idx[MAX_HID_DEVICES];
-	u8 *feature_report[MAX_HID_DEVICES];
-	u8 *input_report[MAX_HID_DEVICES];
-	u8 request_done[MAX_HID_DEVICES];
-	struct delayed_work work;
-	struct delayed_work work_buffer;
-};
-
-/**
- * struct amdtp_hid_data - Per instance HID data
- * @index:		Device index in the order of enumeration
- * @request_done:	Get Feature/Input report complete flag
- *			used during get/set request from hid core
- * @cli_data:		Link to the client instance
- * @hid_wait:		Completion waitq
- *
- * Used to tie hid->driver data to driver client instance
- */
-struct amdtp_hid_data {
-	int index;
-	struct amdtp_cl_data *cli_data;
-	wait_queue_head_t hid_wait;
-};
-
-/* Interface functions between HID LL driver and AMD SFH client */
-void hid_amdtp_set_feature(struct hid_device *hid, char *buf, u32 len, int report_id);
-void hid_amdtp_get_report(struct hid_device *hid, int report_id, int report_type);
-int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data);
-void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
-int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type);
-void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type);
-void amdtp_hid_wakeup(struct hid_device *hid);
-#endif