Tue Jan 26 01:15:39 2021 UTC ()
Back out unintended change in previous.


(thorpej)
diff -r1.14 -r1.15 src/sys/dev/i2c/ihidev.c

cvs diff -r1.14 -r1.15 src/sys/dev/i2c/ihidev.c (switch to unified diff)

--- src/sys/dev/i2c/ihidev.c 2021/01/25 13:30:20 1.14
+++ src/sys/dev/i2c/ihidev.c 2021/01/26 01:15:39 1.15
@@ -1,970 +1,968 @@ @@ -1,970 +1,968 @@
1/* $NetBSD: ihidev.c,v 1.14 2021/01/25 13:30:20 thorpej Exp $ */ 1/* $NetBSD: ihidev.c,v 1.15 2021/01/26 01:15:39 thorpej Exp $ */
2/* $OpenBSD ihidev.c,v 1.13 2017/04/08 02:57:23 deraadt Exp $ */ 2/* $OpenBSD ihidev.c,v 1.13 2017/04/08 02:57:23 deraadt Exp $ */
3 3
4/*- 4/*-
5 * Copyright (c) 2017 The NetBSD Foundation, Inc. 5 * Copyright (c) 2017 The NetBSD Foundation, Inc.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * This code is derived from software contributed to The NetBSD Foundation 8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Manuel Bouyer. 9 * by Manuel Bouyer.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer. 15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright 16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the 17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution. 18 * documentation and/or other materials provided with the distribution.
19 * 19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE. 30 * POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33/* 33/*
34 * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org> 34 * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
35 * 35 *
36 * Permission to use, copy, modify, and distribute this software for any 36 * Permission to use, copy, modify, and distribute this software for any
37 * purpose with or without fee is hereby granted, provided that the above 37 * purpose with or without fee is hereby granted, provided that the above
38 * copyright notice and this permission notice appear in all copies. 38 * copyright notice and this permission notice appear in all copies.
39 * 39 *
40 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 40 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
41 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 41 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 42 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
43 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 43 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
44 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 44 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
45 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 45 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
46 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 46 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
47 */ 47 */
48 48
49/* 49/*
50 * HID-over-i2c driver 50 * HID-over-i2c driver
51 * 51 *
52 * https://msdn.microsoft.com/en-us/library/windows/hardware/dn642101%28v=vs.85%29.aspx 52 * https://msdn.microsoft.com/en-us/library/windows/hardware/dn642101%28v=vs.85%29.aspx
53 * 53 *
54 */ 54 */
55 55
56#include <sys/cdefs.h> 56#include <sys/cdefs.h>
57__KERNEL_RCSID(0, "$NetBSD: ihidev.c,v 1.14 2021/01/25 13:30:20 thorpej Exp $"); 57__KERNEL_RCSID(0, "$NetBSD: ihidev.c,v 1.15 2021/01/26 01:15:39 thorpej Exp $");
58 58
59#include <sys/param.h> 59#include <sys/param.h>
60#include <sys/systm.h> 60#include <sys/systm.h>
61#include <sys/device.h> 61#include <sys/device.h>
62#include <sys/kmem.h> 62#include <sys/kmem.h>
63 63
64 64
65#include <dev/i2c/i2cvar.h> 65#include <dev/i2c/i2cvar.h>
66#include <dev/i2c/ihidev.h> 66#include <dev/i2c/ihidev.h>
67 67
68#include <dev/hid/hid.h> 68#include <dev/hid/hid.h>
69 69
70#if defined(__i386__) || defined(__amd64__) 70#if defined(__i386__) || defined(__amd64__)
71# include "acpica.h" 71# include "acpica.h"
72#endif 72#endif
73#if NACPICA > 0 73#if NACPICA > 0
74#include <dev/acpi/acpivar.h> 74#include <dev/acpi/acpivar.h>
75#include <dev/acpi/acpi_intr.h> 75#include <dev/acpi/acpi_intr.h>
76#endif 76#endif
77 77
78#include "locators.h" 78#include "locators.h"
79 79
80/* #define IHIDEV_DEBUG */ 80/* #define IHIDEV_DEBUG */
81 81
82#ifdef IHIDEV_DEBUG 82#ifdef IHIDEV_DEBUG
83#define DPRINTF(x) printf x 83#define DPRINTF(x) printf x
84#else 84#else
85#define DPRINTF(x) 85#define DPRINTF(x)
86#endif 86#endif
87 87
88/* 7.2 */ 88/* 7.2 */
89enum { 89enum {
90 I2C_HID_CMD_DESCR = 0x0, 90 I2C_HID_CMD_DESCR = 0x0,
91 I2C_HID_CMD_RESET = 0x1, 91 I2C_HID_CMD_RESET = 0x1,
92 I2C_HID_CMD_GET_REPORT = 0x2, 92 I2C_HID_CMD_GET_REPORT = 0x2,
93 I2C_HID_CMD_SET_REPORT = 0x3, 93 I2C_HID_CMD_SET_REPORT = 0x3,
94 I2C_HID_CMD_GET_IDLE = 0x4, 94 I2C_HID_CMD_GET_IDLE = 0x4,
95 I2C_HID_CMD_SET_IDLE = 0x5, 95 I2C_HID_CMD_SET_IDLE = 0x5,
96 I2C_HID_CMD_GET_PROTO = 0x6, 96 I2C_HID_CMD_GET_PROTO = 0x6,
97 I2C_HID_CMD_SET_PROTO = 0x7, 97 I2C_HID_CMD_SET_PROTO = 0x7,
98 I2C_HID_CMD_SET_POWER = 0x8, 98 I2C_HID_CMD_SET_POWER = 0x8,
99 99
100 /* pseudo commands */ 100 /* pseudo commands */
101 I2C_HID_REPORT_DESCR = 0x100, 101 I2C_HID_REPORT_DESCR = 0x100,
102}; 102};
103 103
104static int I2C_HID_POWER_ON = 0x0; 104static int I2C_HID_POWER_ON = 0x0;
105static int I2C_HID_POWER_OFF = 0x1; 105static int I2C_HID_POWER_OFF = 0x1;
106 106
107static int ihidev_match(device_t, cfdata_t, void *); 107static int ihidev_match(device_t, cfdata_t, void *);
108static void ihidev_attach(device_t, device_t, void *); 108static void ihidev_attach(device_t, device_t, void *);
109static int ihidev_detach(device_t, int); 109static int ihidev_detach(device_t, int);
110CFATTACH_DECL_NEW(ihidev, sizeof(struct ihidev_softc), 110CFATTACH_DECL_NEW(ihidev, sizeof(struct ihidev_softc),
111 ihidev_match, ihidev_attach, ihidev_detach, NULL); 111 ihidev_match, ihidev_attach, ihidev_detach, NULL);
112 112
113static bool ihiddev_intr_init(struct ihidev_softc *); 113static bool ihiddev_intr_init(struct ihidev_softc *);
114static void ihiddev_intr_fini(struct ihidev_softc *); 114static void ihiddev_intr_fini(struct ihidev_softc *);
115 115
116static bool ihidev_suspend(device_t, const pmf_qual_t *); 116static bool ihidev_suspend(device_t, const pmf_qual_t *);
117static bool ihidev_resume(device_t, const pmf_qual_t *); 117static bool ihidev_resume(device_t, const pmf_qual_t *);
118static int ihidev_hid_command(struct ihidev_softc *, int, void *, bool); 118static int ihidev_hid_command(struct ihidev_softc *, int, void *, bool);
119static int ihidev_intr(void *); 119static int ihidev_intr(void *);
120static void ihidev_softintr(void *); 120static void ihidev_softintr(void *);
121static int ihidev_reset(struct ihidev_softc *, bool); 121static int ihidev_reset(struct ihidev_softc *, bool);
122static int ihidev_hid_desc_parse(struct ihidev_softc *); 122static int ihidev_hid_desc_parse(struct ihidev_softc *);
123 123
124static int ihidev_maxrepid(void *, int); 124static int ihidev_maxrepid(void *, int);
125static int ihidev_print(void *, const char *); 125static int ihidev_print(void *, const char *);
126static int ihidev_submatch(device_t, cfdata_t, const int *, void *); 126static int ihidev_submatch(device_t, cfdata_t, const int *, void *);
127 127
128static const struct device_compatible_entry compat_data[] = { 128static const struct device_compatible_entry compat_data[] = {
129 { .compat = "PNP0C50" }, 
130 { .compat = "ACPI0C50" }, 
131 { .compat = "hid-over-i2c" }, 129 { .compat = "hid-over-i2c" },
132 { } 130 { }
133}; 131};
134 132
135static int 133static int
136ihidev_match(device_t parent, cfdata_t match, void *aux) 134ihidev_match(device_t parent, cfdata_t match, void *aux)
137{ 135{
138 struct i2c_attach_args * const ia = aux; 136 struct i2c_attach_args * const ia = aux;
139 int match_result; 137 int match_result;
140 138
141 if (iic_use_direct_match(ia, match, compat_data, &match_result)) 139 if (iic_use_direct_match(ia, match, compat_data, &match_result))
142 return I2C_MATCH_DIRECT_COMPATIBLE; 140 return I2C_MATCH_DIRECT_COMPATIBLE;
143 141
144 return 0; 142 return 0;
145} 143}
146 144
147static void 145static void
148ihidev_attach(device_t parent, device_t self, void *aux) 146ihidev_attach(device_t parent, device_t self, void *aux)
149{ 147{
150 struct ihidev_softc *sc = device_private(self); 148 struct ihidev_softc *sc = device_private(self);
151 struct i2c_attach_args *ia = aux; 149 struct i2c_attach_args *ia = aux;
152 struct ihidev_attach_arg iha; 150 struct ihidev_attach_arg iha;
153 device_t dev; 151 device_t dev;
154 int repid, repsz; 152 int repid, repsz;
155 int isize; 153 int isize;
156 uint32_t v; 154 uint32_t v;
157 int locs[IHIDBUSCF_NLOCS]; 155 int locs[IHIDBUSCF_NLOCS];
158 156
159 157
160 sc->sc_dev = self; 158 sc->sc_dev = self;
161 sc->sc_tag = ia->ia_tag; 159 sc->sc_tag = ia->ia_tag;
162 sc->sc_addr = ia->ia_addr; 160 sc->sc_addr = ia->ia_addr;
163 sc->sc_phandle = ia->ia_cookie; 161 sc->sc_phandle = ia->ia_cookie;
164 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM); 162 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
165 163
166 if (!prop_dictionary_get_uint32(ia->ia_prop, "hid-descr-addr", &v)) { 164 if (!prop_dictionary_get_uint32(ia->ia_prop, "hid-descr-addr", &v)) {
167 aprint_error(": no hid-descr-addr value\n"); 165 aprint_error(": no hid-descr-addr value\n");
168 return; 166 return;
169 } 167 }
170 168
171 sc->sc_hid_desc_addr = v; 169 sc->sc_hid_desc_addr = v;
172 170
173 if (ihidev_hid_command(sc, I2C_HID_CMD_DESCR, NULL, false) || 171 if (ihidev_hid_command(sc, I2C_HID_CMD_DESCR, NULL, false) ||
174 ihidev_hid_desc_parse(sc)) { 172 ihidev_hid_desc_parse(sc)) {
175 aprint_error(": failed fetching initial HID descriptor\n"); 173 aprint_error(": failed fetching initial HID descriptor\n");
176 return; 174 return;
177 } 175 }
178 176
179 aprint_naive("\n"); 177 aprint_naive("\n");
180 aprint_normal(": vendor 0x%x product 0x%x, %s\n", 178 aprint_normal(": vendor 0x%x product 0x%x, %s\n",
181 le16toh(sc->hid_desc.wVendorID), le16toh(sc->hid_desc.wProductID), 179 le16toh(sc->hid_desc.wVendorID), le16toh(sc->hid_desc.wProductID),
182 ia->ia_name); 180 ia->ia_name);
183 181
184 sc->sc_nrepid = ihidev_maxrepid(sc->sc_report, sc->sc_reportlen); 182 sc->sc_nrepid = ihidev_maxrepid(sc->sc_report, sc->sc_reportlen);
185 if (sc->sc_nrepid < 0) 183 if (sc->sc_nrepid < 0)
186 return; 184 return;
187 185
188 aprint_normal_dev(self, "%d report id%s\n", sc->sc_nrepid, 186 aprint_normal_dev(self, "%d report id%s\n", sc->sc_nrepid,
189 sc->sc_nrepid > 1 ? "s" : ""); 187 sc->sc_nrepid > 1 ? "s" : "");
190 188
191 sc->sc_nrepid++; 189 sc->sc_nrepid++;
192 sc->sc_subdevs = kmem_zalloc(sc->sc_nrepid * sizeof(struct ihidev *), 190 sc->sc_subdevs = kmem_zalloc(sc->sc_nrepid * sizeof(struct ihidev *),
193 KM_SLEEP); 191 KM_SLEEP);
194 192
195 /* find largest report size and allocate memory for input buffer */ 193 /* find largest report size and allocate memory for input buffer */
196 sc->sc_isize = le16toh(sc->hid_desc.wMaxInputLength); 194 sc->sc_isize = le16toh(sc->hid_desc.wMaxInputLength);
197 for (repid = 0; repid < sc->sc_nrepid; repid++) { 195 for (repid = 0; repid < sc->sc_nrepid; repid++) {
198 repsz = hid_report_size(sc->sc_report, sc->sc_reportlen, 196 repsz = hid_report_size(sc->sc_report, sc->sc_reportlen,
199 hid_input, repid); 197 hid_input, repid);
200 198
201 isize = repsz + 2; /* two bytes for the length */ 199 isize = repsz + 2; /* two bytes for the length */
202 isize += (sc->sc_nrepid != 1); /* one byte for the report ID */ 200 isize += (sc->sc_nrepid != 1); /* one byte for the report ID */
203 if (isize > sc->sc_isize) 201 if (isize > sc->sc_isize)
204 sc->sc_isize = isize; 202 sc->sc_isize = isize;
205 203
206 DPRINTF(("%s: repid %d size %d\n", sc->sc_dev.dv_xname, repid, 204 DPRINTF(("%s: repid %d size %d\n", sc->sc_dev.dv_xname, repid,
207 repsz)); 205 repsz));
208 } 206 }
209 sc->sc_ibuf = kmem_zalloc(sc->sc_isize, KM_SLEEP); 207 sc->sc_ibuf = kmem_zalloc(sc->sc_isize, KM_SLEEP);
210 if (! ihiddev_intr_init(sc)) { 208 if (! ihiddev_intr_init(sc)) {
211 return; 209 return;
212 } 210 }
213 211
214 iha.iaa = ia; 212 iha.iaa = ia;
215 iha.parent = sc; 213 iha.parent = sc;
216 214
217 /* Look for a driver claiming all report IDs first. */ 215 /* Look for a driver claiming all report IDs first. */
218 iha.reportid = IHIDEV_CLAIM_ALLREPORTID; 216 iha.reportid = IHIDEV_CLAIM_ALLREPORTID;
219 locs[IHIDBUSCF_REPORTID] = IHIDEV_CLAIM_ALLREPORTID; 217 locs[IHIDBUSCF_REPORTID] = IHIDEV_CLAIM_ALLREPORTID;
220 dev = config_found_sm_loc(self, "ihidbus", locs, &iha, 218 dev = config_found_sm_loc(self, "ihidbus", locs, &iha,
221 ihidev_print, ihidev_submatch); 219 ihidev_print, ihidev_submatch);
222 if (dev != NULL) { 220 if (dev != NULL) {
223 for (repid = 0; repid < sc->sc_nrepid; repid++) 221 for (repid = 0; repid < sc->sc_nrepid; repid++)
224 sc->sc_subdevs[repid] = device_private(dev); 222 sc->sc_subdevs[repid] = device_private(dev);
225 return; 223 return;
226 } 224 }
227 225
228 for (repid = 0; repid < sc->sc_nrepid; repid++) { 226 for (repid = 0; repid < sc->sc_nrepid; repid++) {
229 if (hid_report_size(sc->sc_report, sc->sc_reportlen, hid_input, 227 if (hid_report_size(sc->sc_report, sc->sc_reportlen, hid_input,
230 repid) == 0 && 228 repid) == 0 &&
231 hid_report_size(sc->sc_report, sc->sc_reportlen, 229 hid_report_size(sc->sc_report, sc->sc_reportlen,
232 hid_output, repid) == 0 && 230 hid_output, repid) == 0 &&
233 hid_report_size(sc->sc_report, sc->sc_reportlen, 231 hid_report_size(sc->sc_report, sc->sc_reportlen,
234 hid_feature, repid) == 0) 232 hid_feature, repid) == 0)
235 continue; 233 continue;
236 234
237 iha.reportid = repid; 235 iha.reportid = repid;
238 locs[IHIDBUSCF_REPORTID] = repid; 236 locs[IHIDBUSCF_REPORTID] = repid;
239 dev = config_found_sm_loc(self, "ihidbus", locs, 237 dev = config_found_sm_loc(self, "ihidbus", locs,
240 &iha, ihidev_print, ihidev_submatch); 238 &iha, ihidev_print, ihidev_submatch);
241 sc->sc_subdevs[repid] = device_private(dev); 239 sc->sc_subdevs[repid] = device_private(dev);
242 } 240 }
243 241
244 /* power down until we're opened */ 242 /* power down until we're opened */
245 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF, false)) { 243 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF, false)) {
246 aprint_error_dev(sc->sc_dev, "failed to power down\n"); 244 aprint_error_dev(sc->sc_dev, "failed to power down\n");
247 return; 245 return;
248 } 246 }
249 if (!pmf_device_register(self, ihidev_suspend, ihidev_resume)) 247 if (!pmf_device_register(self, ihidev_suspend, ihidev_resume))
250 aprint_error_dev(self, "couldn't establish power handler\n"); 248 aprint_error_dev(self, "couldn't establish power handler\n");
251} 249}
252 250
253static int 251static int
254ihidev_detach(device_t self, int flags) 252ihidev_detach(device_t self, int flags)
255{ 253{
256 struct ihidev_softc *sc = device_private(self); 254 struct ihidev_softc *sc = device_private(self);
257 255
258 mutex_enter(&sc->sc_intr_lock); 256 mutex_enter(&sc->sc_intr_lock);
259 ihiddev_intr_fini(sc); 257 ihiddev_intr_fini(sc);
260 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 258 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
261 &I2C_HID_POWER_OFF, true)) 259 &I2C_HID_POWER_OFF, true))
262 aprint_error_dev(sc->sc_dev, "failed to power down\n"); 260 aprint_error_dev(sc->sc_dev, "failed to power down\n");
263 mutex_exit(&sc->sc_intr_lock); 261 mutex_exit(&sc->sc_intr_lock);
264 if (sc->sc_ibuf != NULL) { 262 if (sc->sc_ibuf != NULL) {
265 kmem_free(sc->sc_ibuf, sc->sc_isize); 263 kmem_free(sc->sc_ibuf, sc->sc_isize);
266 sc->sc_ibuf = NULL; 264 sc->sc_ibuf = NULL;
267 } 265 }
268 266
269 if (sc->sc_report != NULL) 267 if (sc->sc_report != NULL)
270 kmem_free(sc->sc_report, sc->sc_reportlen); 268 kmem_free(sc->sc_report, sc->sc_reportlen);
271 269
272 pmf_device_deregister(self); 270 pmf_device_deregister(self);
273 return (0); 271 return (0);
274} 272}
275 273
276static bool 274static bool
277ihidev_suspend(device_t self, const pmf_qual_t *q) 275ihidev_suspend(device_t self, const pmf_qual_t *q)
278{ 276{
279 struct ihidev_softc *sc = device_private(self); 277 struct ihidev_softc *sc = device_private(self);
280 278
281 mutex_enter(&sc->sc_intr_lock); 279 mutex_enter(&sc->sc_intr_lock);
282 if (sc->sc_refcnt > 0) { 280 if (sc->sc_refcnt > 0) {
283 printf("ihidev power off\n"); 281 printf("ihidev power off\n");
284 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 282 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
285 &I2C_HID_POWER_OFF, true)) 283 &I2C_HID_POWER_OFF, true))
286 aprint_error_dev(sc->sc_dev, "failed to power down\n"); 284 aprint_error_dev(sc->sc_dev, "failed to power down\n");
287 } 285 }
288 mutex_exit(&sc->sc_intr_lock); 286 mutex_exit(&sc->sc_intr_lock);
289 return true; 287 return true;
290} 288}
291 289
292static bool 290static bool
293ihidev_resume(device_t self, const pmf_qual_t *q) 291ihidev_resume(device_t self, const pmf_qual_t *q)
294{ 292{
295 struct ihidev_softc *sc = device_private(self); 293 struct ihidev_softc *sc = device_private(self);
296 294
297 mutex_enter(&sc->sc_intr_lock); 295 mutex_enter(&sc->sc_intr_lock);
298 if (sc->sc_refcnt > 0) { 296 if (sc->sc_refcnt > 0) {
299 printf("ihidev power reset\n"); 297 printf("ihidev power reset\n");
300 ihidev_reset(sc, true); 298 ihidev_reset(sc, true);
301 } 299 }
302 mutex_exit(&sc->sc_intr_lock); 300 mutex_exit(&sc->sc_intr_lock);
303 return true; 301 return true;
304} 302}
305 303
306static int 304static int
307ihidev_hid_command(struct ihidev_softc *sc, int hidcmd, void *arg, bool poll) 305ihidev_hid_command(struct ihidev_softc *sc, int hidcmd, void *arg, bool poll)
308{ 306{
309 int i, res = 1; 307 int i, res = 1;
310 int flags = poll ? I2C_F_POLL : 0; 308 int flags = poll ? I2C_F_POLL : 0;
311 309
312 iic_acquire_bus(sc->sc_tag, flags); 310 iic_acquire_bus(sc->sc_tag, flags);
313 311
314 switch (hidcmd) { 312 switch (hidcmd) {
315 case I2C_HID_CMD_DESCR: { 313 case I2C_HID_CMD_DESCR: {
316 /* 314 /*
317 * 5.2.2 - HID Descriptor Retrieval 315 * 5.2.2 - HID Descriptor Retrieval
318 * register is passed from the controller 316 * register is passed from the controller
319 */ 317 */
320 uint8_t cmd[] = { 318 uint8_t cmd[] = {
321 htole16(sc->sc_hid_desc_addr) & 0xff, 319 htole16(sc->sc_hid_desc_addr) & 0xff,
322 htole16(sc->sc_hid_desc_addr) >> 8, 320 htole16(sc->sc_hid_desc_addr) >> 8,
323 }; 321 };
324 322
325 DPRINTF(("%s: HID command I2C_HID_CMD_DESCR at 0x%x\n", 323 DPRINTF(("%s: HID command I2C_HID_CMD_DESCR at 0x%x\n",
326 sc->sc_dev.dv_xname, htole16(sc->sc_hid_desc_addr))); 324 sc->sc_dev.dv_xname, htole16(sc->sc_hid_desc_addr)));
327 325
328 /* 20 00 */ 326 /* 20 00 */
329 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 327 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
330 &cmd, sizeof(cmd), &sc->hid_desc_buf, 328 &cmd, sizeof(cmd), &sc->hid_desc_buf,
331 sizeof(struct i2c_hid_desc), flags); 329 sizeof(struct i2c_hid_desc), flags);
332 330
333 DPRINTF(("%s: HID descriptor:", sc->sc_dev.dv_xname)); 331 DPRINTF(("%s: HID descriptor:", sc->sc_dev.dv_xname));
334 for (i = 0; i < sizeof(struct i2c_hid_desc); i++) 332 for (i = 0; i < sizeof(struct i2c_hid_desc); i++)
335 DPRINTF((" %.2x", sc->hid_desc_buf[i])); 333 DPRINTF((" %.2x", sc->hid_desc_buf[i]));
336 DPRINTF(("\n")); 334 DPRINTF(("\n"));
337 335
338 break; 336 break;
339 } 337 }
340 case I2C_HID_CMD_RESET: { 338 case I2C_HID_CMD_RESET: {
341 uint8_t cmd[] = { 339 uint8_t cmd[] = {
342 htole16(sc->hid_desc.wCommandRegister) & 0xff, 340 htole16(sc->hid_desc.wCommandRegister) & 0xff,
343 htole16(sc->hid_desc.wCommandRegister) >> 8, 341 htole16(sc->hid_desc.wCommandRegister) >> 8,
344 0, 342 0,
345 I2C_HID_CMD_RESET, 343 I2C_HID_CMD_RESET,
346 }; 344 };
347 345
348 DPRINTF(("%s: HID command I2C_HID_CMD_RESET\n", 346 DPRINTF(("%s: HID command I2C_HID_CMD_RESET\n",
349 sc->sc_dev.dv_xname)); 347 sc->sc_dev.dv_xname));
350 348
351 /* 22 00 00 01 */ 349 /* 22 00 00 01 */
352 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 350 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
353 &cmd, sizeof(cmd), NULL, 0, flags); 351 &cmd, sizeof(cmd), NULL, 0, flags);
354 352
355 break; 353 break;
356 } 354 }
357 case I2C_HID_CMD_GET_REPORT: { 355 case I2C_HID_CMD_GET_REPORT: {
358 struct i2c_hid_report_request *rreq = 356 struct i2c_hid_report_request *rreq =
359 (struct i2c_hid_report_request *)arg; 357 (struct i2c_hid_report_request *)arg;
360 358
361 uint8_t cmd[] = { 359 uint8_t cmd[] = {
362 htole16(sc->hid_desc.wCommandRegister) & 0xff, 360 htole16(sc->hid_desc.wCommandRegister) & 0xff,
363 htole16(sc->hid_desc.wCommandRegister) >> 8, 361 htole16(sc->hid_desc.wCommandRegister) >> 8,
364 0, 362 0,
365 I2C_HID_CMD_GET_REPORT, 363 I2C_HID_CMD_GET_REPORT,
366 0, 0, 0, 364 0, 0, 0,
367 }; 365 };
368 int cmdlen = 7; 366 int cmdlen = 7;
369 int dataoff = 4; 367 int dataoff = 4;
370 int report_id = rreq->id; 368 int report_id = rreq->id;
371 int report_id_len = 1; 369 int report_id_len = 1;
372 int report_len = rreq->len + 2; 370 int report_len = rreq->len + 2;
373 int d; 371 int d;
374 uint8_t *tmprep; 372 uint8_t *tmprep;
375 373
376 DPRINTF(("%s: HID command I2C_HID_CMD_GET_REPORT %d " 374 DPRINTF(("%s: HID command I2C_HID_CMD_GET_REPORT %d "
377 "(type %d, len %d)\n", sc->sc_dev.dv_xname, report_id, 375 "(type %d, len %d)\n", sc->sc_dev.dv_xname, report_id,
378 rreq->type, rreq->len)); 376 rreq->type, rreq->len));
379 377
380 /* 378 /*
381 * 7.2.2.4 - "The protocol is optimized for Report < 15. If a 379 * 7.2.2.4 - "The protocol is optimized for Report < 15. If a
382 * report ID >= 15 is necessary, then the Report ID in the Low 380 * report ID >= 15 is necessary, then the Report ID in the Low
383 * Byte must be set to 1111 and a Third Byte is appended to the 381 * Byte must be set to 1111 and a Third Byte is appended to the
384 * protocol. This Third Byte contains the entire/actual report 382 * protocol. This Third Byte contains the entire/actual report
385 * ID." 383 * ID."
386 */ 384 */
387 if (report_id >= 15) { 385 if (report_id >= 15) {
388 cmd[dataoff++] = report_id; 386 cmd[dataoff++] = report_id;
389 report_id = 15; 387 report_id = 15;
390 report_id_len = 2; 388 report_id_len = 2;
391 } else 389 } else
392 cmdlen--; 390 cmdlen--;
393 391
394 cmd[2] = report_id | rreq->type << 4; 392 cmd[2] = report_id | rreq->type << 4;
395 393
396 cmd[dataoff++] = sc->hid_desc.wDataRegister & 0xff; 394 cmd[dataoff++] = sc->hid_desc.wDataRegister & 0xff;
397 cmd[dataoff] = sc->hid_desc.wDataRegister >> 8; 395 cmd[dataoff] = sc->hid_desc.wDataRegister >> 8;
398 396
399 /* 397 /*
400 * 7.2.2.2 - Response will be a 2-byte length value, the report 398 * 7.2.2.2 - Response will be a 2-byte length value, the report
401 * id with length determined above, and then the report. 399 * id with length determined above, and then the report.
402 * Allocate rreq->len + 2 + 2 bytes, read into that temporary 400 * Allocate rreq->len + 2 + 2 bytes, read into that temporary
403 * buffer, and then copy only the report back out to 401 * buffer, and then copy only the report back out to
404 * rreq->data. 402 * rreq->data.
405 */ 403 */
406 report_len += report_id_len; 404 report_len += report_id_len;
407 tmprep = kmem_zalloc(report_len, KM_NOSLEEP); 405 tmprep = kmem_zalloc(report_len, KM_NOSLEEP);
408 406
409 /* type 3 id 8: 22 00 38 02 23 00 */ 407 /* type 3 id 8: 22 00 38 02 23 00 */
410 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 408 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
411 &cmd, cmdlen, tmprep, report_len, flags); 409 &cmd, cmdlen, tmprep, report_len, flags);
412 410
413 d = tmprep[0] | tmprep[1] << 8; 411 d = tmprep[0] | tmprep[1] << 8;
414 if (d != report_len) { 412 if (d != report_len) {
415 DPRINTF(("%s: response size %d != expected length %d\n", 413 DPRINTF(("%s: response size %d != expected length %d\n",
416 sc->sc_dev.dv_xname, d, report_len)); 414 sc->sc_dev.dv_xname, d, report_len));
417 } 415 }
418 416
419 if (report_id_len == 2) 417 if (report_id_len == 2)
420 d = tmprep[2] | tmprep[3] << 8; 418 d = tmprep[2] | tmprep[3] << 8;
421 else 419 else
422 d = tmprep[2]; 420 d = tmprep[2];
423 421
424 if (d != rreq->id) { 422 if (d != rreq->id) {
425 DPRINTF(("%s: response report id %d != %d\n", 423 DPRINTF(("%s: response report id %d != %d\n",
426 sc->sc_dev.dv_xname, d, rreq->id)); 424 sc->sc_dev.dv_xname, d, rreq->id));
427 iic_release_bus(sc->sc_tag, 0); 425 iic_release_bus(sc->sc_tag, 0);
428 kmem_free(tmprep, report_len); 426 kmem_free(tmprep, report_len);
429 return (1); 427 return (1);
430 } 428 }
431 429
432 DPRINTF(("%s: response:", sc->sc_dev.dv_xname)); 430 DPRINTF(("%s: response:", sc->sc_dev.dv_xname));
433 for (i = 0; i < report_len; i++) 431 for (i = 0; i < report_len; i++)
434 DPRINTF((" %.2x", tmprep[i])); 432 DPRINTF((" %.2x", tmprep[i]));
435 DPRINTF(("\n")); 433 DPRINTF(("\n"));
436 434
437 memcpy(rreq->data, tmprep + 2 + report_id_len, rreq->len); 435 memcpy(rreq->data, tmprep + 2 + report_id_len, rreq->len);
438 kmem_free(tmprep, report_len); 436 kmem_free(tmprep, report_len);
439 437
440 break; 438 break;
441 } 439 }
442 case I2C_HID_CMD_SET_REPORT: { 440 case I2C_HID_CMD_SET_REPORT: {
443 struct i2c_hid_report_request *rreq = 441 struct i2c_hid_report_request *rreq =
444 (struct i2c_hid_report_request *)arg; 442 (struct i2c_hid_report_request *)arg;
445 443
446 uint8_t cmd[] = { 444 uint8_t cmd[] = {
447 htole16(sc->hid_desc.wCommandRegister) & 0xff, 445 htole16(sc->hid_desc.wCommandRegister) & 0xff,
448 htole16(sc->hid_desc.wCommandRegister) >> 8, 446 htole16(sc->hid_desc.wCommandRegister) >> 8,
449 0, 447 0,
450 I2C_HID_CMD_SET_REPORT, 448 I2C_HID_CMD_SET_REPORT,
451 0, 0, 0, 0, 0, 0, 449 0, 0, 0, 0, 0, 0,
452 }; 450 };
453 int cmdlen = 10; 451 int cmdlen = 10;
454 int report_id = rreq->id; 452 int report_id = rreq->id;
455 int report_len = 2 + (report_id ? 1 : 0) + rreq->len; 453 int report_len = 2 + (report_id ? 1 : 0) + rreq->len;
456 int dataoff; 454 int dataoff;
457 uint8_t *finalcmd; 455 uint8_t *finalcmd;
458 456
459 DPRINTF(("%s: HID command I2C_HID_CMD_SET_REPORT %d " 457 DPRINTF(("%s: HID command I2C_HID_CMD_SET_REPORT %d "
460 "(type %d, len %d):", sc->sc_dev.dv_xname, report_id, 458 "(type %d, len %d):", sc->sc_dev.dv_xname, report_id,
461 rreq->type, rreq->len)); 459 rreq->type, rreq->len));
462 for (i = 0; i < rreq->len; i++) 460 for (i = 0; i < rreq->len; i++)
463 DPRINTF((" %.2x", ((uint8_t *)rreq->data)[i])); 461 DPRINTF((" %.2x", ((uint8_t *)rreq->data)[i]));
464 DPRINTF(("\n")); 462 DPRINTF(("\n"));
465 463
466 /* 464 /*
467 * 7.2.2.4 - "The protocol is optimized for Report < 15. If a 465 * 7.2.2.4 - "The protocol is optimized for Report < 15. If a
468 * report ID >= 15 is necessary, then the Report ID in the Low 466 * report ID >= 15 is necessary, then the Report ID in the Low
469 * Byte must be set to 1111 and a Third Byte is appended to the 467 * Byte must be set to 1111 and a Third Byte is appended to the
470 * protocol. This Third Byte contains the entire/actual report 468 * protocol. This Third Byte contains the entire/actual report
471 * ID." 469 * ID."
472 */ 470 */
473 dataoff = 4; 471 dataoff = 4;
474 if (report_id >= 15) { 472 if (report_id >= 15) {
475 cmd[dataoff++] = report_id; 473 cmd[dataoff++] = report_id;
476 report_id = 15; 474 report_id = 15;
477 } else 475 } else
478 cmdlen--; 476 cmdlen--;
479 477
480 cmd[2] = report_id | rreq->type << 4; 478 cmd[2] = report_id | rreq->type << 4;
481 479
482 if (rreq->type == I2C_HID_REPORT_TYPE_FEATURE) { 480 if (rreq->type == I2C_HID_REPORT_TYPE_FEATURE) {
483 cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister) 481 cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister)
484 & 0xff; 482 & 0xff;
485 cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister) 483 cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister)
486 >> 8; 484 >> 8;
487 } else { 485 } else {
488 cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister) 486 cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister)
489 & 0xff; 487 & 0xff;
490 cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister) 488 cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister)
491 >> 8; 489 >> 8;
492 } 490 }
493 491
494 cmd[dataoff++] = report_len & 0xff; 492 cmd[dataoff++] = report_len & 0xff;
495 cmd[dataoff++] = report_len >> 8; 493 cmd[dataoff++] = report_len >> 8;
496 cmd[dataoff] = rreq->id; 494 cmd[dataoff] = rreq->id;
497 495
498 finalcmd = kmem_zalloc(cmdlen + rreq->len, KM_NOSLEEP); 496 finalcmd = kmem_zalloc(cmdlen + rreq->len, KM_NOSLEEP);
499 497
500 memcpy(finalcmd, cmd, cmdlen); 498 memcpy(finalcmd, cmd, cmdlen);
501 memcpy(finalcmd + cmdlen, rreq->data, rreq->len); 499 memcpy(finalcmd + cmdlen, rreq->data, rreq->len);
502 500
503 /* type 3 id 4: 22 00 34 03 23 00 04 00 04 03 */ 501 /* type 3 id 4: 22 00 34 03 23 00 04 00 04 03 */
504 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 502 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
505 finalcmd, cmdlen + rreq->len, NULL, 0, flags); 503 finalcmd, cmdlen + rreq->len, NULL, 0, flags);
506 kmem_free(finalcmd, cmdlen + rreq->len); 504 kmem_free(finalcmd, cmdlen + rreq->len);
507 505
508 break; 506 break;
509 } 507 }
510 508
511 case I2C_HID_CMD_SET_POWER: { 509 case I2C_HID_CMD_SET_POWER: {
512 int power = *(int *)arg; 510 int power = *(int *)arg;
513 uint8_t cmd[] = { 511 uint8_t cmd[] = {
514 htole16(sc->hid_desc.wCommandRegister) & 0xff, 512 htole16(sc->hid_desc.wCommandRegister) & 0xff,
515 htole16(sc->hid_desc.wCommandRegister) >> 8, 513 htole16(sc->hid_desc.wCommandRegister) >> 8,
516 power, 514 power,
517 I2C_HID_CMD_SET_POWER, 515 I2C_HID_CMD_SET_POWER,
518 }; 516 };
519 517
520 DPRINTF(("%s: HID command I2C_HID_CMD_SET_POWER(%d)\n", 518 DPRINTF(("%s: HID command I2C_HID_CMD_SET_POWER(%d)\n",
521 sc->sc_dev.dv_xname, power)); 519 sc->sc_dev.dv_xname, power));
522 520
523 /* 22 00 00 08 */ 521 /* 22 00 00 08 */
524 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 522 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
525 &cmd, sizeof(cmd), NULL, 0, flags); 523 &cmd, sizeof(cmd), NULL, 0, flags);
526 524
527 break; 525 break;
528 } 526 }
529 case I2C_HID_REPORT_DESCR: { 527 case I2C_HID_REPORT_DESCR: {
530 uint8_t cmd[] = { 528 uint8_t cmd[] = {
531 htole16(sc->hid_desc.wReportDescRegister) & 0xff, 529 htole16(sc->hid_desc.wReportDescRegister) & 0xff,
532 htole16(sc->hid_desc.wReportDescRegister) >> 8, 530 htole16(sc->hid_desc.wReportDescRegister) >> 8,
533 }; 531 };
534 532
535 DPRINTF(("%s: HID command I2C_HID_REPORT_DESCR at 0x%x with " 533 DPRINTF(("%s: HID command I2C_HID_REPORT_DESCR at 0x%x with "
536 "size %d\n", sc->sc_dev.dv_xname, cmd[0], 534 "size %d\n", sc->sc_dev.dv_xname, cmd[0],
537 sc->sc_reportlen)); 535 sc->sc_reportlen));
538 536
539 /* 20 00 */ 537 /* 20 00 */
540 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 538 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
541 &cmd, sizeof(cmd), sc->sc_report, sc->sc_reportlen, flags); 539 &cmd, sizeof(cmd), sc->sc_report, sc->sc_reportlen, flags);
542 540
543 DPRINTF(("%s: HID report descriptor:", sc->sc_dev.dv_xname)); 541 DPRINTF(("%s: HID report descriptor:", sc->sc_dev.dv_xname));
544 for (i = 0; i < sc->sc_reportlen; i++) 542 for (i = 0; i < sc->sc_reportlen; i++)
545 DPRINTF((" %.2x", sc->sc_report[i])); 543 DPRINTF((" %.2x", sc->sc_report[i]));
546 DPRINTF(("\n")); 544 DPRINTF(("\n"));
547 545
548 break; 546 break;
549 } 547 }
550 default: 548 default:
551 aprint_error_dev(sc->sc_dev, "unknown command %d\n", 549 aprint_error_dev(sc->sc_dev, "unknown command %d\n",
552 hidcmd); 550 hidcmd);
553 } 551 }
554 552
555 iic_release_bus(sc->sc_tag, flags); 553 iic_release_bus(sc->sc_tag, flags);
556 554
557 return (res); 555 return (res);
558} 556}
559 557
560static int 558static int
561ihidev_reset(struct ihidev_softc *sc, bool poll) 559ihidev_reset(struct ihidev_softc *sc, bool poll)
562{ 560{
563 DPRINTF(("%s: resetting\n", sc->sc_dev.dv_xname)); 561 DPRINTF(("%s: resetting\n", sc->sc_dev.dv_xname));
564 562
565 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 563 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
566 &I2C_HID_POWER_ON, poll)) { 564 &I2C_HID_POWER_ON, poll)) {
567 aprint_error_dev(sc->sc_dev, "failed to power on\n"); 565 aprint_error_dev(sc->sc_dev, "failed to power on\n");
568 return (1); 566 return (1);
569 } 567 }
570 568
571 DELAY(1000); 569 DELAY(1000);
572 570
573 if (ihidev_hid_command(sc, I2C_HID_CMD_RESET, 0, poll)) { 571 if (ihidev_hid_command(sc, I2C_HID_CMD_RESET, 0, poll)) {
574 aprint_error_dev(sc->sc_dev, "failed to reset hardware\n"); 572 aprint_error_dev(sc->sc_dev, "failed to reset hardware\n");
575 573
576 ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 574 ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
577 &I2C_HID_POWER_OFF, poll); 575 &I2C_HID_POWER_OFF, poll);
578 576
579 return (1); 577 return (1);
580 } 578 }
581 579
582 DELAY(1000); 580 DELAY(1000);
583 581
584 return (0); 582 return (0);
585} 583}
586 584
587/* 585/*
588 * 5.2.2 - HID Descriptor Retrieval 586 * 5.2.2 - HID Descriptor Retrieval
589 * 587 *
590 * parse HID Descriptor that has already been read into hid_desc with 588 * parse HID Descriptor that has already been read into hid_desc with
591 * I2C_HID_CMD_DESCR 589 * I2C_HID_CMD_DESCR
592 */ 590 */
593static int 591static int
594ihidev_hid_desc_parse(struct ihidev_softc *sc) 592ihidev_hid_desc_parse(struct ihidev_softc *sc)
595{ 593{
596 int retries = 3; 594 int retries = 3;
597 595
598 /* must be v01.00 */ 596 /* must be v01.00 */
599 if (le16toh(sc->hid_desc.bcdVersion) != 0x0100) { 597 if (le16toh(sc->hid_desc.bcdVersion) != 0x0100) {
600 aprint_error_dev(sc->sc_dev, 598 aprint_error_dev(sc->sc_dev,
601 "bad HID descriptor bcdVersion (0x%x)\n", 599 "bad HID descriptor bcdVersion (0x%x)\n",
602 le16toh(sc->hid_desc.bcdVersion)); 600 le16toh(sc->hid_desc.bcdVersion));
603 return (1); 601 return (1);
604 } 602 }
605 603
606 /* must be 30 bytes for v1.00 */ 604 /* must be 30 bytes for v1.00 */
607 if (le16toh(sc->hid_desc.wHIDDescLength != 605 if (le16toh(sc->hid_desc.wHIDDescLength !=
608 sizeof(struct i2c_hid_desc))) { 606 sizeof(struct i2c_hid_desc))) {
609 aprint_error_dev(sc->sc_dev, 607 aprint_error_dev(sc->sc_dev,
610 "bad HID descriptor size (%d != %zu)\n", 608 "bad HID descriptor size (%d != %zu)\n",
611 le16toh(sc->hid_desc.wHIDDescLength), 609 le16toh(sc->hid_desc.wHIDDescLength),
612 sizeof(struct i2c_hid_desc)); 610 sizeof(struct i2c_hid_desc));
613 return (1); 611 return (1);
614 } 612 }
615 613
616 if (le16toh(sc->hid_desc.wReportDescLength) <= 0) { 614 if (le16toh(sc->hid_desc.wReportDescLength) <= 0) {
617 aprint_error_dev(sc->sc_dev, 615 aprint_error_dev(sc->sc_dev,
618 "bad HID report descriptor size (%d)\n", 616 "bad HID report descriptor size (%d)\n",
619 le16toh(sc->hid_desc.wReportDescLength)); 617 le16toh(sc->hid_desc.wReportDescLength));
620 return (1); 618 return (1);
621 } 619 }
622 620
623 while (retries-- > 0) { 621 while (retries-- > 0) {
624 if (ihidev_reset(sc, false)) { 622 if (ihidev_reset(sc, false)) {
625 if (retries == 0) 623 if (retries == 0)
626 return(1); 624 return(1);
627 625
628 DELAY(1000); 626 DELAY(1000);
629 } 627 }
630 else 628 else
631 break; 629 break;
632 } 630 }
633 631
634 sc->sc_reportlen = le16toh(sc->hid_desc.wReportDescLength); 632 sc->sc_reportlen = le16toh(sc->hid_desc.wReportDescLength);
635 sc->sc_report = kmem_zalloc(sc->sc_reportlen, KM_NOSLEEP); 633 sc->sc_report = kmem_zalloc(sc->sc_reportlen, KM_NOSLEEP);
636 634
637 if (ihidev_hid_command(sc, I2C_HID_REPORT_DESCR, 0, false)) { 635 if (ihidev_hid_command(sc, I2C_HID_REPORT_DESCR, 0, false)) {
638 aprint_error_dev(sc->sc_dev, "failed fetching HID report\n"); 636 aprint_error_dev(sc->sc_dev, "failed fetching HID report\n");
639 return (1); 637 return (1);
640 } 638 }
641 639
642 return (0); 640 return (0);
643} 641}
644 642
645static bool 643static bool
646ihiddev_intr_init(struct ihidev_softc *sc) 644ihiddev_intr_init(struct ihidev_softc *sc)
647{ 645{
648#if NACPICA > 0 646#if NACPICA > 0
649 ACPI_HANDLE hdl = (void *)(uintptr_t)sc->sc_phandle; 647 ACPI_HANDLE hdl = (void *)(uintptr_t)sc->sc_phandle;
650 struct acpi_resources res; 648 struct acpi_resources res;
651 ACPI_STATUS rv; 649 ACPI_STATUS rv;
652 char buf[100]; 650 char buf[100];
653 651
654 rv = acpi_resource_parse(sc->sc_dev, hdl, "_CRS", &res, 652 rv = acpi_resource_parse(sc->sc_dev, hdl, "_CRS", &res,
655 &acpi_resource_parse_ops_quiet); 653 &acpi_resource_parse_ops_quiet);
656 if (ACPI_FAILURE(rv)) { 654 if (ACPI_FAILURE(rv)) {
657 aprint_error_dev(sc->sc_dev, "can't parse '_CRS'\n"); 655 aprint_error_dev(sc->sc_dev, "can't parse '_CRS'\n");
658 return false; 656 return false;
659 } 657 }
660 658
661 const struct acpi_irq * const irq = acpi_res_irq(&res, 0); 659 const struct acpi_irq * const irq = acpi_res_irq(&res, 0);
662 if (irq == NULL) { 660 if (irq == NULL) {
663 aprint_error_dev(sc->sc_dev, "no IRQ resource\n"); 661 aprint_error_dev(sc->sc_dev, "no IRQ resource\n");
664 acpi_resource_cleanup(&res); 662 acpi_resource_cleanup(&res);
665 return false; 663 return false;
666 } 664 }
667 665
668 sc->sc_intr_type = 666 sc->sc_intr_type =
669 irq->ar_type == ACPI_EDGE_SENSITIVE ? IST_EDGE : IST_LEVEL; 667 irq->ar_type == ACPI_EDGE_SENSITIVE ? IST_EDGE : IST_LEVEL;
670 668
671 acpi_resource_cleanup(&res); 669 acpi_resource_cleanup(&res);
672 670
673 sc->sc_ih = acpi_intr_establish(sc->sc_dev, sc->sc_phandle, IPL_TTY, 671 sc->sc_ih = acpi_intr_establish(sc->sc_dev, sc->sc_phandle, IPL_TTY,
674 false, ihidev_intr, sc, device_xname(sc->sc_dev)); 672 false, ihidev_intr, sc, device_xname(sc->sc_dev));
675 if (sc->sc_ih == NULL) { 673 if (sc->sc_ih == NULL) {
676 aprint_error_dev(sc->sc_dev, "can't establish interrupt\n"); 674 aprint_error_dev(sc->sc_dev, "can't establish interrupt\n");
677 return false; 675 return false;
678 } 676 }
679 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", 677 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n",
680 acpi_intr_string(sc->sc_ih, buf, sizeof(buf))); 678 acpi_intr_string(sc->sc_ih, buf, sizeof(buf)));
681 679
682 sc->sc_sih = softint_establish(SOFTINT_SERIAL, ihidev_softintr, sc); 680 sc->sc_sih = softint_establish(SOFTINT_SERIAL, ihidev_softintr, sc);
683 if (sc->sc_sih == NULL) { 681 if (sc->sc_sih == NULL) {
684 aprint_error_dev(sc->sc_dev, 682 aprint_error_dev(sc->sc_dev,
685 "can't establish soft interrupt\n"); 683 "can't establish soft interrupt\n");
686 return false; 684 return false;
687 } 685 }
688 686
689 return true; 687 return true;
690#else 688#else
691 aprint_error_dev(sc->sc_dev, "can't establish interrupt\n"); 689 aprint_error_dev(sc->sc_dev, "can't establish interrupt\n");
692 return false; 690 return false;
693#endif 691#endif
694} 692}
695 693
696static void 694static void
697ihiddev_intr_fini(struct ihidev_softc *sc) 695ihiddev_intr_fini(struct ihidev_softc *sc)
698{ 696{
699#if NACPICA > 0 697#if NACPICA > 0
700 if (sc->sc_ih != NULL) { 698 if (sc->sc_ih != NULL) {
701 acpi_intr_disestablish(sc->sc_ih); 699 acpi_intr_disestablish(sc->sc_ih);
702 } 700 }
703 if (sc->sc_sih != NULL) { 701 if (sc->sc_sih != NULL) {
704 softint_disestablish(sc->sc_sih); 702 softint_disestablish(sc->sc_sih);
705 } 703 }
706#endif 704#endif
707} 705}
708 706
709static void 707static void
710ihidev_intr_mask(struct ihidev_softc * const sc) 708ihidev_intr_mask(struct ihidev_softc * const sc)
711{ 709{
712 710
713 if (sc->sc_intr_type == IST_LEVEL) { 711 if (sc->sc_intr_type == IST_LEVEL) {
714#if NACPICA > 0 712#if NACPICA > 0
715 acpi_intr_mask(sc->sc_ih); 713 acpi_intr_mask(sc->sc_ih);
716#endif 714#endif
717 } 715 }
718} 716}
719 717
720static void 718static void
721ihidev_intr_unmask(struct ihidev_softc * const sc) 719ihidev_intr_unmask(struct ihidev_softc * const sc)
722{ 720{
723 721
724 if (sc->sc_intr_type == IST_LEVEL) { 722 if (sc->sc_intr_type == IST_LEVEL) {
725#if NACPICA > 0 723#if NACPICA > 0
726 acpi_intr_unmask(sc->sc_ih); 724 acpi_intr_unmask(sc->sc_ih);
727#endif 725#endif
728 } 726 }
729} 727}
730 728
731static int 729static int
732ihidev_intr(void *arg) 730ihidev_intr(void *arg)
733{ 731{
734 struct ihidev_softc * const sc = arg; 732 struct ihidev_softc * const sc = arg;
735 733
736 mutex_enter(&sc->sc_intr_lock); 734 mutex_enter(&sc->sc_intr_lock);
737 735
738 /* 736 /*
739 * Schedule our soft interrupt handler. If we're using a level- 737 * Schedule our soft interrupt handler. If we're using a level-
740 * triggered interrupt, we have to mask it off while we wait 738 * triggered interrupt, we have to mask it off while we wait
741 * for service. 739 * for service.
742 */ 740 */
743 softint_schedule(sc->sc_sih); 741 softint_schedule(sc->sc_sih);
744 ihidev_intr_mask(sc); 742 ihidev_intr_mask(sc);
745 743
746 mutex_exit(&sc->sc_intr_lock); 744 mutex_exit(&sc->sc_intr_lock);
747 745
748 return 1; 746 return 1;
749} 747}
750 748
751static void 749static void
752ihidev_softintr(void *arg) 750ihidev_softintr(void *arg)
753{ 751{
754 struct ihidev_softc * const sc = arg; 752 struct ihidev_softc * const sc = arg;
755 struct ihidev *scd; 753 struct ihidev *scd;
756 u_int psize; 754 u_int psize;
757 int res, i; 755 int res, i;
758 u_char *p; 756 u_char *p;
759 u_int rep = 0; 757 u_int rep = 0;
760 758
761 mutex_enter(&sc->sc_intr_lock); 759 mutex_enter(&sc->sc_intr_lock);
762 iic_acquire_bus(sc->sc_tag, 0); 760 iic_acquire_bus(sc->sc_tag, 0);
763 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0, 761 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0,
764 sc->sc_ibuf, sc->sc_isize, 0); 762 sc->sc_ibuf, sc->sc_isize, 0);
765 iic_release_bus(sc->sc_tag, 0); 763 iic_release_bus(sc->sc_tag, 0);
766 mutex_exit(&sc->sc_intr_lock); 764 mutex_exit(&sc->sc_intr_lock);
767 765
768 if (res != 0) 766 if (res != 0)
769 goto out; 767 goto out;
770 768
771 /* 769 /*
772 * 6.1.1 - First two bytes are the packet length, which must be less 770 * 6.1.1 - First two bytes are the packet length, which must be less
773 * than or equal to wMaxInputLength 771 * than or equal to wMaxInputLength
774 */ 772 */
775 psize = sc->sc_ibuf[0] | sc->sc_ibuf[1] << 8; 773 psize = sc->sc_ibuf[0] | sc->sc_ibuf[1] << 8;
776 if (!psize || psize > sc->sc_isize) { 774 if (!psize || psize > sc->sc_isize) {
777 DPRINTF(("%s: %s: invalid packet size (%d vs. %d)\n", 775 DPRINTF(("%s: %s: invalid packet size (%d vs. %d)\n",
778 sc->sc_dev.dv_xname, __func__, psize, sc->sc_isize)); 776 sc->sc_dev.dv_xname, __func__, psize, sc->sc_isize));
779 goto out; 777 goto out;
780 } 778 }
781 779
782 /* 3rd byte is the report id */ 780 /* 3rd byte is the report id */
783 p = sc->sc_ibuf + 2; 781 p = sc->sc_ibuf + 2;
784 psize -= 2; 782 psize -= 2;
785 if (sc->sc_nrepid != 1) 783 if (sc->sc_nrepid != 1)
786 rep = *p++, psize--; 784 rep = *p++, psize--;
787 785
788 if (rep >= sc->sc_nrepid) { 786 if (rep >= sc->sc_nrepid) {
789 aprint_error_dev(sc->sc_dev, "%s: bad report id %d\n", 787 aprint_error_dev(sc->sc_dev, "%s: bad report id %d\n",
790 __func__, rep); 788 __func__, rep);
791 goto out; 789 goto out;
792 } 790 }
793 791
794 DPRINTF(("%s: %s: hid input (rep %d):", sc->sc_dev.dv_xname, 792 DPRINTF(("%s: %s: hid input (rep %d):", sc->sc_dev.dv_xname,
795 __func__, rep)); 793 __func__, rep));
796 for (i = 0; i < sc->sc_isize; i++) 794 for (i = 0; i < sc->sc_isize; i++)
797 DPRINTF((" %.2x", sc->sc_ibuf[i])); 795 DPRINTF((" %.2x", sc->sc_ibuf[i]));
798 DPRINTF(("\n")); 796 DPRINTF(("\n"));
799 797
800 scd = sc->sc_subdevs[rep]; 798 scd = sc->sc_subdevs[rep];
801 if (scd == NULL || !(scd->sc_state & IHIDEV_OPEN)) 799 if (scd == NULL || !(scd->sc_state & IHIDEV_OPEN))
802 goto out; 800 goto out;
803 801
804 scd->sc_intr(scd, p, psize); 802 scd->sc_intr(scd, p, psize);
805 803
806 out: 804 out:
807 /* 805 /*
808 * If our interrupt is level-triggered, re-enable it now. 806 * If our interrupt is level-triggered, re-enable it now.
809 */ 807 */
810 ihidev_intr_unmask(sc); 808 ihidev_intr_unmask(sc);
811} 809}
812 810
813static int 811static int
814ihidev_maxrepid(void *buf, int len) 812ihidev_maxrepid(void *buf, int len)
815{ 813{
816 struct hid_data *d; 814 struct hid_data *d;
817 struct hid_item h; 815 struct hid_item h;
818 int maxid; 816 int maxid;
819 817
820 maxid = -1; 818 maxid = -1;
821 h.report_ID = 0; 819 h.report_ID = 0;
822 for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); ) 820 for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); )
823 if ((int)h.report_ID > maxid) 821 if ((int)h.report_ID > maxid)
824 maxid = h.report_ID; 822 maxid = h.report_ID;
825 hid_end_parse(d); 823 hid_end_parse(d);
826 824
827 return (maxid); 825 return (maxid);
828} 826}
829 827
830static int 828static int
831ihidev_print(void *aux, const char *pnp) 829ihidev_print(void *aux, const char *pnp)
832{ 830{
833 struct ihidev_attach_arg *iha = aux; 831 struct ihidev_attach_arg *iha = aux;
834 832
835 if (iha->reportid == IHIDEV_CLAIM_ALLREPORTID) 833 if (iha->reportid == IHIDEV_CLAIM_ALLREPORTID)
836 return (QUIET); 834 return (QUIET);
837  835
838 if (pnp) 836 if (pnp)
839 aprint_normal("hid at %s", pnp); 837 aprint_normal("hid at %s", pnp);
840 838
841 if (iha->reportid != 0) 839 if (iha->reportid != 0)
842 aprint_normal(" reportid %d", iha->reportid); 840 aprint_normal(" reportid %d", iha->reportid);
843 841
844 return (UNCONF); 842 return (UNCONF);
845} 843}
846 844
847static int 845static int
848ihidev_submatch(device_t parent, cfdata_t cf, const int *locs, void *aux) 846ihidev_submatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
849{ 847{
850 struct ihidev_attach_arg *iha = aux; 848 struct ihidev_attach_arg *iha = aux;
851 849
852 if (cf->ihidevcf_reportid != IHIDEV_UNK_REPORTID && 850 if (cf->ihidevcf_reportid != IHIDEV_UNK_REPORTID &&
853 cf->ihidevcf_reportid != iha->reportid) 851 cf->ihidevcf_reportid != iha->reportid)
854 return (0); 852 return (0);
855 853
856 return config_match(parent, cf, aux); 854 return config_match(parent, cf, aux);
857} 855}
858 856
859int 857int
860ihidev_open(struct ihidev *scd) 858ihidev_open(struct ihidev *scd)
861{ 859{
862 struct ihidev_softc *sc = scd->sc_parent; 860 struct ihidev_softc *sc = scd->sc_parent;
863 861
864 DPRINTF(("%s: %s: state=%d refcnt=%d\n", sc->sc_dev.dv_xname, 862 DPRINTF(("%s: %s: state=%d refcnt=%d\n", sc->sc_dev.dv_xname,
865 __func__, scd->sc_state, sc->sc_refcnt)); 863 __func__, scd->sc_state, sc->sc_refcnt));
866 864
867 if (scd->sc_state & IHIDEV_OPEN) 865 if (scd->sc_state & IHIDEV_OPEN)
868 return (EBUSY); 866 return (EBUSY);
869 867
870 scd->sc_state |= IHIDEV_OPEN; 868 scd->sc_state |= IHIDEV_OPEN;
871 869
872 if (sc->sc_refcnt++ || sc->sc_isize == 0) 870 if (sc->sc_refcnt++ || sc->sc_isize == 0)
873 return (0); 871 return (0);
874 872
875 /* power on */ 873 /* power on */
876 ihidev_reset(sc, false); 874 ihidev_reset(sc, false);
877 875
878 return (0); 876 return (0);
879} 877}
880 878
881void 879void
882ihidev_close(struct ihidev *scd) 880ihidev_close(struct ihidev *scd)
883{ 881{
884 struct ihidev_softc *sc = scd->sc_parent; 882 struct ihidev_softc *sc = scd->sc_parent;
885 883
886 DPRINTF(("%s: %s: state=%d refcnt=%d\n", sc->sc_dev.dv_xname, 884 DPRINTF(("%s: %s: state=%d refcnt=%d\n", sc->sc_dev.dv_xname,
887 __func__, scd->sc_state, sc->sc_refcnt)); 885 __func__, scd->sc_state, sc->sc_refcnt));
888 886
889 if (!(scd->sc_state & IHIDEV_OPEN)) 887 if (!(scd->sc_state & IHIDEV_OPEN))
890 return; 888 return;
891 889
892 scd->sc_state &= ~IHIDEV_OPEN; 890 scd->sc_state &= ~IHIDEV_OPEN;
893 891
894 if (--sc->sc_refcnt) 892 if (--sc->sc_refcnt)
895 return; 893 return;
896 894
897 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 895 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
898 &I2C_HID_POWER_OFF, false)) 896 &I2C_HID_POWER_OFF, false))
899 aprint_error_dev(sc->sc_dev, "failed to power down\n"); 897 aprint_error_dev(sc->sc_dev, "failed to power down\n");
900} 898}
901 899
902void 900void
903ihidev_get_report_desc(struct ihidev_softc *sc, void **desc, int *size) 901ihidev_get_report_desc(struct ihidev_softc *sc, void **desc, int *size)
904{ 902{
905 *desc = sc->sc_report; 903 *desc = sc->sc_report;
906 *size = sc->sc_reportlen; 904 *size = sc->sc_reportlen;
907} 905}
908 906
909/* convert hid_* constants used throughout HID code to i2c HID equivalents */ 907/* convert hid_* constants used throughout HID code to i2c HID equivalents */
910int 908int
911ihidev_report_type_conv(int hid_type_id) 909ihidev_report_type_conv(int hid_type_id)
912{ 910{
913 switch (hid_type_id) { 911 switch (hid_type_id) {
914 case hid_input: 912 case hid_input:
915 return I2C_HID_REPORT_TYPE_INPUT; 913 return I2C_HID_REPORT_TYPE_INPUT;
916 case hid_output: 914 case hid_output:
917 return I2C_HID_REPORT_TYPE_OUTPUT; 915 return I2C_HID_REPORT_TYPE_OUTPUT;
918 case hid_feature: 916 case hid_feature:
919 return I2C_HID_REPORT_TYPE_FEATURE; 917 return I2C_HID_REPORT_TYPE_FEATURE;
920 default: 918 default:
921 return -1; 919 return -1;
922 } 920 }
923} 921}
924 922
925int 923int
926ihidev_get_report(struct device *dev, int type, int id, void *data, int len) 924ihidev_get_report(struct device *dev, int type, int id, void *data, int len)
927{ 925{
928 struct ihidev_softc *sc = (struct ihidev_softc *)dev; 926 struct ihidev_softc *sc = (struct ihidev_softc *)dev;
929 struct i2c_hid_report_request rreq; 927 struct i2c_hid_report_request rreq;
930 int ctype; 928 int ctype;
931 929
932 if ((ctype = ihidev_report_type_conv(type)) < 0) 930 if ((ctype = ihidev_report_type_conv(type)) < 0)
933 return (1); 931 return (1);
934 932
935 rreq.type = ctype; 933 rreq.type = ctype;
936 rreq.id = id; 934 rreq.id = id;
937 rreq.data = data; 935 rreq.data = data;
938 rreq.len = len; 936 rreq.len = len;
939 937
940 if (ihidev_hid_command(sc, I2C_HID_CMD_GET_REPORT, &rreq, false)) { 938 if (ihidev_hid_command(sc, I2C_HID_CMD_GET_REPORT, &rreq, false)) {
941 aprint_error_dev(sc->sc_dev, "failed fetching report\n"); 939 aprint_error_dev(sc->sc_dev, "failed fetching report\n");
942 return (1); 940 return (1);
943 } 941 }
944 942
945 return 0; 943 return 0;
946} 944}
947 945
948int 946int
949ihidev_set_report(struct device *dev, int type, int id, void *data, 947ihidev_set_report(struct device *dev, int type, int id, void *data,
950 int len) 948 int len)
951{ 949{
952 struct ihidev_softc *sc = (struct ihidev_softc *)dev; 950 struct ihidev_softc *sc = (struct ihidev_softc *)dev;
953 struct i2c_hid_report_request rreq; 951 struct i2c_hid_report_request rreq;
954 int ctype; 952 int ctype;
955 953
956 if ((ctype = ihidev_report_type_conv(type)) < 0) 954 if ((ctype = ihidev_report_type_conv(type)) < 0)
957 return (1); 955 return (1);
958 956
959 rreq.type = ctype; 957 rreq.type = ctype;
960 rreq.id = id; 958 rreq.id = id;
961 rreq.data = data; 959 rreq.data = data;
962 rreq.len = len; 960 rreq.len = len;
963 961
964 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_REPORT, &rreq, false)) { 962 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_REPORT, &rreq, false)) {
965 aprint_error_dev(sc->sc_dev, "failed setting report\n"); 963 aprint_error_dev(sc->sc_dev, "failed setting report\n");
966 return (1); 964 return (1);
967 } 965 }
968 966
969 return 0; 967 return 0;
970} 968}