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 */
quicki2c_hid_parse(struct hid_device * hid)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
quicki2c_hid_start(struct hid_device * hid)33 static int quicki2c_hid_start(struct hid_device *hid)
34 {
35 return 0;
36 }
37
quicki2c_hid_stop(struct hid_device * hid)38 static void quicki2c_hid_stop(struct hid_device *hid)
39 {
40 }
41
quicki2c_hid_open(struct hid_device * hid)42 static int quicki2c_hid_open(struct hid_device *hid)
43 {
44 return 0;
45 }
46
quicki2c_hid_close(struct hid_device * hid)47 static void quicki2c_hid_close(struct hid_device *hid)
48 {
49 }
50
quicki2c_hid_raw_request(struct hid_device * hid,unsigned char reportnum,__u8 * buf,size_t len,unsigned char rtype,int reqtype)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
quicki2c_hid_power(struct hid_device * hid,int lvl)80 static int quicki2c_hid_power(struct hid_device *hid, int lvl)
81 {
82 return 0;
83 }
84
quicki2c_hid_output_report(struct hid_device * hid,u8 * buf,size_t count)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 */
quicki2c_hid_probe(struct quicki2c_device * qcdev)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 strscpy(hid->phys, dev_name(qcdev->dev), sizeof(hid->phys));
131
132 ret = hid_add_device(hid);
133 if (ret) {
134 hid_destroy_device(hid);
135 return ret;
136 }
137
138 qcdev->hid_dev = hid;
139
140 return 0;
141 }
142
143 /**
144 * quicki2c_hid_remove() - Destroy HID device
145 *
146 * @qcdev: point to quicki2c device
147 *
148 * Return: 0 on success, non zero on error.
149 */
quicki2c_hid_remove(struct quicki2c_device * qcdev)150 void quicki2c_hid_remove(struct quicki2c_device *qcdev)
151 {
152 hid_destroy_device(qcdev->hid_dev);
153 }
154
155 /**
156 * quicki2c_hid_send_report() - Send HID input report data to HID core
157 *
158 * @qcdev: point to quicki2c device
159 * @data: point to input report data buffer
160 * @data_len: the length of input report data
161 *
162 * Return: 0 on success, non zero on error.
163 */
quicki2c_hid_send_report(struct quicki2c_device * qcdev,void * data,size_t data_len)164 int quicki2c_hid_send_report(struct quicki2c_device *qcdev,
165 void *data, size_t data_len)
166 {
167 int ret;
168
169 ret = hid_input_report(qcdev->hid_dev, HID_INPUT_REPORT, data, data_len, 1);
170 if (ret)
171 dev_err(qcdev->dev, "Failed to send HID input report, ret = %d.\n", ret);
172
173 return ret;
174 }
175