diff mbox series

[RFC,v2,2/2] HID: ghid: add example program for GET_REPORT

Message ID 20220802201556.1510069-3-sunil@amarulasolutions.com (mailing list archive)
State Superseded
Headers show
Series Extend functionality for GET_REPORT | expand

Commit Message

Suniel Mahesh Aug. 2, 2022, 8:15 p.m. UTC
This adds a user-space ghid sample get report program at
gadget side. This program sends reports from userspace(gadget side)
which are saved in the kernel in a list.

When a host requests a particular report based on report number
and type, corresponding report can be send to host, instead of a
zero filled in report.

This program can add, delete reports and modify an existing report.

Signed-off-by: Suniel Mahesh <sunil@amarulasolutions.com>
---
Changes for v2:
- no changes
---
 samples/Kconfig         |  10 +++
 samples/Makefile        |   1 +
 samples/ghid/Makefile   |   4 ++
 samples/ghid/test-hid.c | 134 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 149 insertions(+)
 create mode 100644 samples/ghid/Makefile
 create mode 100644 samples/ghid/test-hid.c
diff mbox series

Patch

diff --git a/samples/Kconfig b/samples/Kconfig
index 470ee3baf2e1..f3d7873bb966 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -86,6 +86,16 @@  config SAMPLE_FPROBE
 	  This builds a fprobe example module. This module has an option 'symbol'.
 	  You can specify a probed symbol or symbols separated with ','.
 
+config SAMPLE_GHID_GET_REPORT
+        bool "GHID sample get report"
+        depends on CC_CAN_LINK && HEADERS_INSTALL
+        help
+          Build GHID sample get report program. This program can send reports from
+	  userspace(gadget side) which are saved in the kernel in a linked list.
+	  When a host requests a particular report based on report number and type,
+	  corresponding report can be send to host, instead of a zero filled in report.
+	  This program can add, delete reports and modify an existing report.
+
 config SAMPLE_KFIFO
 	tristate "Build kfifo examples -- loadable modules only"
 	depends on m
diff --git a/samples/Makefile b/samples/Makefile
index 701e912ab5af..1d58f7a0381e 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -6,6 +6,7 @@  subdir-$(CONFIG_SAMPLE_ANDROID_BINDERFS) += binderfs
 obj-$(CONFIG_SAMPLE_CONFIGFS)		+= configfs/
 obj-$(CONFIG_SAMPLE_CONNECTOR)		+= connector/
 obj-$(CONFIG_SAMPLE_FANOTIFY_ERROR)	+= fanotify/
+subdir-$(SAMPLE_GHID_GET_REPORT)	+= ghid
 subdir-$(CONFIG_SAMPLE_HIDRAW)		+= hidraw
 obj-$(CONFIG_SAMPLE_HW_BREAKPOINT)	+= hw_breakpoint/
 obj-$(CONFIG_SAMPLE_KDB)		+= kdb/
diff --git a/samples/ghid/Makefile b/samples/ghid/Makefile
new file mode 100644
index 000000000000..8c93ded625c1
--- /dev/null
+++ b/samples/ghid/Makefile
@@ -0,0 +1,4 @@ 
+# SPDX-License-Identifier: GPL-2.0-only
+userprogs-always-y += test-hid
+
+userccflags += -I usr/include
diff --git a/samples/ghid/test-hid.c b/samples/ghid/test-hid.c
new file mode 100644
index 000000000000..f76786509047
--- /dev/null
+++ b/samples/ghid/test-hid.c
@@ -0,0 +1,134 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * usb hidg GET_REPORT example, device/gadget side
+ * This program tests the newly implemented GET_REPORT feature
+ *
+ * Copyright (c) 2022 Amarula Solutions India PVT LTD
+ *
+ * Authors:
+ * Copyright (c) 2022 Suniel Mahesh <sunil@amarulasolutions.com>
+ *
+ */
+
+#include <pthread.h>
+/* Linux */
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/hidraw.h>
+#include <linux/uhid.h>
+#include <uapi/linux/usb/g_hid.h>
+
+/* Unix */
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* C */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+/*
+ * fix for failing compilation on systems that don't
+ * yet populate new version of uapi/linux/usb/g_hid.h
+ * to userspace.
+ */
+#define GADGET_ADD_REPORT_STATUS	_IOWR('g', 0x41, struct uhid_set_report_req)
+#define GADGET_REMOVE_REPORT_STATUS	_IOWR('g', 0x42, struct uhid_get_report_req)
+#define GADGET_UPDATE_REPORT_STATUS	_IOWR('g', 0x43, struct uhid_set_report_req)
+
+struct uhid_set_report_req *create_report(void)
+{
+	struct uhid_set_report_req *rep;
+	int i;
+
+	rep = (struct uhid_set_report_req *)calloc(1, sizeof(struct uhid_set_report_req));
+	if (rep == NULL) {
+		perror("calloc() failed");
+		exit(EXIT_FAILURE);
+	}
+
+	printf("enter report id:\n");
+	scanf("%u", &rep->id);
+	printf("enter report number:\n");
+	scanf("%hhu", &rep->rnum);
+	printf("enter report type:\n");
+	scanf("%hhu", &rep->rtype);
+	printf("enter report size:\n");
+	scanf("%hu", &rep->size);
+	printf("enter report data:\n");
+
+	for (i = 0; i < rep->size; i++)
+		scanf("%hhu", &rep->data[i]);
+
+	return rep;
+}
+
+int main(int argc, char **argv)
+{
+	const char *filename = NULL;
+	struct uhid_set_report_req *report;
+	int fd = 0, res = 0, i, reports;
+
+	if (argc < 1) {
+		fprintf(stderr, "Usage: %s /dev/hidg0\n", argv[0]);
+		return -1;
+	}
+
+	filename = argv[1];
+	fd = open(filename, O_RDWR, 0666);
+
+	if (fd == -1) {
+		perror(filename);
+		return -2;
+	}
+
+	printf("enter no of reports to send from userspace:\n");
+	scanf("%d", &reports);
+
+	if (reports == 0)
+		goto out;
+
+	for (i = 0; i < reports; i++) {
+		report = create_report();
+/* send reports to device */
+		res = ioctl(fd, GADGET_ADD_REPORT_STATUS, report);
+		if (res < 0) {
+			perror("GADGET_ADD_REPORT_STATUS");
+			res = -3;
+			goto test_end;
+		}
+		free(report);
+	}
+
+/* delete report with report number specified */
+	printf("deleting report w.r.t rtype and rnum:\n");
+	report = create_report();
+	res = ioctl(fd, GADGET_REMOVE_REPORT_STATUS, report);
+	if (res < 0) {
+		perror("GADGET_REMOVE_REPORT_STATUS");
+		res = -4;
+		goto test_end;
+	}
+	free(report);
+
+/* modify an existing report identified by report number */
+	printf("modify report w.r.t rtype and rnum:\n");
+	report = create_report();
+	res = ioctl(fd, GADGET_UPDATE_REPORT_STATUS, report);
+	if (res < 0) {
+		perror("GADGET_UPDATE_REPORT_STATUS");
+		res = -5;
+	}
+
+test_end:
+	free(report);
+	report = NULL;
+out:
+	close(fd);
+	return res;
+}