xref: /linux/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Copyright (c) 2024 Intel Corporation */
3 
4 #include <linux/hid.h>
5 #include <linux/input.h>
6 #include <linux/pm_runtime.h>
7 
8 #include "quicki2c-dev.h"
9 #include "quicki2c-hid.h"
10 #include "quicki2c-protocol.h"
11 
12 /**
13  * quicki2c_hid_parse() - HID core parse() callback
14  *
15  * @hid: HID device instance
16  *
17  * This function gets called during call to hid_add_device
18  *
19  * Return: 0 on success and non zero on error.
20  */
21 static int quicki2c_hid_parse(struct hid_device *hid)
22 {
23 	struct quicki2c_device *qcdev = hid->driver_data;
24 
25 	if (qcdev->report_descriptor)
26 		return hid_parse_report(hid, qcdev->report_descriptor,
27 					le16_to_cpu(qcdev->dev_desc.report_desc_len));
28 
29 	dev_err_once(qcdev->dev, "invalid report descriptor\n");
30 	return -EINVAL;
31 }
32 
33 static int quicki2c_hid_start(struct hid_device *hid)
34 {
35 	return 0;
36 }
37 
38 static void quicki2c_hid_stop(struct hid_device *hid)
39 {
40 }
41 
42 static int quicki2c_hid_open(struct hid_device *hid)
43 {
44 	return 0;
45 }
46 
47 static void quicki2c_hid_close(struct hid_device *hid)
48 {
49 }
50 
51 static int quicki2c_hid_raw_request(struct hid_device *hid,
52 				    unsigned char reportnum,
53 				    __u8 *buf, size_t len,
54 				    unsigned char rtype, int reqtype)
55 {
56 	struct quicki2c_device *qcdev = hid->driver_data;
57 	int ret = 0;
58 
59 	ret = pm_runtime_resume_and_get(qcdev->dev);
60 	if (ret)
61 		return ret;
62 
63 	switch (reqtype) {
64 	case HID_REQ_GET_REPORT:
65 		ret = quicki2c_get_report(qcdev, rtype, reportnum, buf, len);
66 		break;
67 	case HID_REQ_SET_REPORT:
68 		ret = quicki2c_set_report(qcdev, rtype, reportnum, buf, len);
69 		break;
70 	default:
71 		dev_err(qcdev->dev, "Not supported request type %d\n", reqtype);
72 		break;
73 	}
74 
75 	pm_runtime_put_autosuspend(qcdev->dev);
76 
77 	return ret;
78 }
79 
80 static int quicki2c_hid_power(struct hid_device *hid, int lvl)
81 {
82 	return 0;
83 }
84 
85 static int quicki2c_hid_output_report(struct hid_device *hid, u8 *buf, size_t count)
86 {
87 	struct quicki2c_device *qcdev = hid->driver_data;
88 
89 	return quicki2c_output_report(qcdev, buf, count);
90 }
91 
92 static struct hid_ll_driver quicki2c_hid_ll_driver = {
93 	.parse = quicki2c_hid_parse,
94 	.start = quicki2c_hid_start,
95 	.stop = quicki2c_hid_stop,
96 	.open = quicki2c_hid_open,
97 	.close = quicki2c_hid_close,
98 	.power = quicki2c_hid_power,
99 	.raw_request = quicki2c_hid_raw_request,
100 	.output_report = quicki2c_hid_output_report,
101 };
102 
103 /**
104  * quicki2c_hid_probe() - Register HID low level driver
105  *
106  * @qcdev: point to quicki2c device
107  *
108  * This function is used to allocate and add HID device.
109  *
110  * Return: 0 on success, non zero on error.
111  */
112 int quicki2c_hid_probe(struct quicki2c_device *qcdev)
113 {
114 	struct hid_device *hid;
115 	int ret;
116 
117 	hid = hid_allocate_device();
118 	if (IS_ERR(hid))
119 		return PTR_ERR(hid);
120 
121 	hid->ll_driver = &quicki2c_hid_ll_driver;
122 	hid->bus = BUS_PCI;
123 	hid->dev.parent = qcdev->dev;
124 	hid->driver_data = qcdev;
125 	hid->version = le16_to_cpu(qcdev->dev_desc.version_id);
126 	hid->vendor = le16_to_cpu(qcdev->dev_desc.vendor_id);
127 	hid->product = le16_to_cpu(qcdev->dev_desc.product_id);
128 	snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quicki2c-hid",
129 		 hid->vendor, hid->product);
130 
131 	ret = hid_add_device(hid);
132 	if (ret) {
133 		hid_destroy_device(hid);
134 		return ret;
135 	}
136 
137 	qcdev->hid_dev = hid;
138 
139 	return 0;
140 }
141 
142 /**
143  * quicki2c_hid_remove() - Destroy HID device
144  *
145  * @qcdev: point to quicki2c device
146  *
147  * Return: 0 on success, non zero on error.
148  */
149 void quicki2c_hid_remove(struct quicki2c_device *qcdev)
150 {
151 	hid_destroy_device(qcdev->hid_dev);
152 }
153 
154 /**
155  * quicki2c_hid_send_report() - Send HID input report data to HID core
156  *
157  * @qcdev: point to quicki2c device
158  * @data: point to input report data buffer
159  * @data_len: the length of input report data
160  *
161  * Return: 0 on success, non zero on error.
162  */
163 int quicki2c_hid_send_report(struct quicki2c_device *qcdev,
164 			     void *data, size_t data_len)
165 {
166 	int ret;
167 
168 	ret = hid_input_report(qcdev->hid_dev, HID_INPUT_REPORT, data, data_len, 1);
169 	if (ret)
170 		dev_err(qcdev->dev, "Failed to send HID input report, ret = %d.\n", ret);
171 
172 	return ret;
173 }
174