Fri Jan 29 04:38:18 2021 UTC ()
hvkbd(4): Don't wait forever.


(nonaka)
diff -r1.6 -r1.7 src/sys/dev/hyperv/hvkbd.c

cvs diff -r1.6 -r1.7 src/sys/dev/hyperv/hvkbd.c (switch to unified diff)

--- src/sys/dev/hyperv/hvkbd.c 2019/11/22 12:40:07 1.6
+++ src/sys/dev/hyperv/hvkbd.c 2021/01/29 04:38:18 1.7
@@ -1,627 +1,628 @@ @@ -1,627 +1,628 @@
1/* $NetBSD: hvkbd.c,v 1.6 2019/11/22 12:40:07 nonaka Exp $ */ 1/* $NetBSD: hvkbd.c,v 1.7 2021/01/29 04:38:18 nonaka Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2017 Microsoft Corp. 4 * Copyright (c) 2017 Microsoft Corp.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following 11 * notice unmodified, this list of conditions, and the following
12 * disclaimer. 12 * disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * 27 *
28 * $FreeBSD: head/sys/dev/hyperv/input/hv_kbd.c 317821 2017-05-05 03:28:30Z sephe $ 28 * $FreeBSD: head/sys/dev/hyperv/input/hv_kbd.c 317821 2017-05-05 03:28:30Z sephe $
29 * $FreeBSD: head/sys/dev/hyperv/input/hv_kbdc.c 320490 2017-06-30 03:01:22Z sephe $ 29 * $FreeBSD: head/sys/dev/hyperv/input/hv_kbdc.c 320490 2017-06-30 03:01:22Z sephe $
30 * $FreeBSD: head/sys/dev/hyperv/input/hv_kbdc.h 316515 2017-04-05 05:01:23Z sephe $ 30 * $FreeBSD: head/sys/dev/hyperv/input/hv_kbdc.h 316515 2017-04-05 05:01:23Z sephe $
31 */ 31 */
32 32
33#ifdef _KERNEL_OPT 33#ifdef _KERNEL_OPT
34#include "opt_pckbd_layout.h" 34#include "opt_pckbd_layout.h"
35#include "opt_wsdisplay_compat.h" 35#include "opt_wsdisplay_compat.h"
36#endif /* _KERNEL_OPT */ 36#endif /* _KERNEL_OPT */
37 37
38#include <sys/cdefs.h> 38#include <sys/cdefs.h>
39__KERNEL_RCSID(0, "$NetBSD: hvkbd.c,v 1.6 2019/11/22 12:40:07 nonaka Exp $"); 39__KERNEL_RCSID(0, "$NetBSD: hvkbd.c,v 1.7 2021/01/29 04:38:18 nonaka Exp $");
40 40
41#include <sys/param.h> 41#include <sys/param.h>
42#include <sys/systm.h> 42#include <sys/systm.h>
43#include <sys/device.h> 43#include <sys/device.h>
44#include <sys/mutex.h> 44#include <sys/mutex.h>
45#include <sys/kernel.h> 45#include <sys/kernel.h>
46#include <sys/kmem.h> 46#include <sys/kmem.h>
47#include <sys/module.h> 47#include <sys/module.h>
48#include <sys/pmf.h> 48#include <sys/pmf.h>
49#include <sys/proc.h> 49#include <sys/proc.h>
50#include <sys/queue.h> 50#include <sys/queue.h>
51 51
52#include <dev/hyperv/vmbusvar.h> 52#include <dev/hyperv/vmbusvar.h>
53#include <dev/hyperv/hvkbdvar.h> 53#include <dev/hyperv/hvkbdvar.h>
54 54
55#include <dev/wscons/wsconsio.h> 55#include <dev/wscons/wsconsio.h>
56#include <dev/wscons/wskbdvar.h> 56#include <dev/wscons/wskbdvar.h>
57#include <dev/wscons/wsksymdef.h> 57#include <dev/wscons/wsksymdef.h>
58#include <dev/wscons/wsksymvar.h> 58#include <dev/wscons/wsksymvar.h>
59#include <dev/pckbport/wskbdmap_mfii.h> 59#include <dev/pckbport/wskbdmap_mfii.h>
60 60
61#define HVKBD_BUFSIZE (4 * PAGE_SIZE) 61#define HVKBD_BUFSIZE (4 * PAGE_SIZE)
62#define HVKBD_TX_RING_SIZE (10 * PAGE_SIZE) 62#define HVKBD_TX_RING_SIZE (10 * PAGE_SIZE)
63#define HVKBD_RX_RING_SIZE (10 * PAGE_SIZE) 63#define HVKBD_RX_RING_SIZE (10 * PAGE_SIZE)
64 64
65#define HVKBD_VER_MAJOR (1) 65#define HVKBD_VER_MAJOR (1)
66#define HVKBD_VER_MINOR (0) 66#define HVKBD_VER_MINOR (0)
67#define HVKBD_VERSION ((HVKBD_VER_MAJOR << 16) | HVKBD_VER_MINOR) 67#define HVKBD_VERSION ((HVKBD_VER_MAJOR << 16) | HVKBD_VER_MINOR)
68 68
69enum hvkbd_msg_type { 69enum hvkbd_msg_type {
70 HVKBD_PROTO_REQUEST = 1, 70 HVKBD_PROTO_REQUEST = 1,
71 HVKBD_PROTO_RESPONSE = 2, 71 HVKBD_PROTO_RESPONSE = 2,
72 HVKBD_PROTO_EVENT = 3, 72 HVKBD_PROTO_EVENT = 3,
73 HVKBD_PROTO_LED_INDICATORS = 4 73 HVKBD_PROTO_LED_INDICATORS = 4
74}; 74};
75 75
76struct hvkbd_msg_hdr { 76struct hvkbd_msg_hdr {
77 uint32_t type; 77 uint32_t type;
78} __packed; 78} __packed;
79 79
80struct hvkbd_proto_req { 80struct hvkbd_proto_req {
81 struct hvkbd_msg_hdr hdr; 81 struct hvkbd_msg_hdr hdr;
82 uint32_t ver; 82 uint32_t ver;
83} __packed; 83} __packed;
84 84
85struct hvkbd_proto_resp { 85struct hvkbd_proto_resp {
86 struct hvkbd_msg_hdr hdr; 86 struct hvkbd_msg_hdr hdr;
87 uint32_t status; 87 uint32_t status;
88#define RESP_STATUS_ACCEPTED __BIT(0) 88#define RESP_STATUS_ACCEPTED __BIT(0)
89} __packed; 89} __packed;
90 90
91struct keystroke { 91struct keystroke {
92 uint16_t makecode; 92 uint16_t makecode;
93 uint16_t pad0; 93 uint16_t pad0;
94 uint32_t info; 94 uint32_t info;
95#define KS_INFO_UNICODE __BIT(0) 95#define KS_INFO_UNICODE __BIT(0)
96#define KS_INFO_BREAK __BIT(1) 96#define KS_INFO_BREAK __BIT(1)
97#define KS_INFO_E0 __BIT(2) 97#define KS_INFO_E0 __BIT(2)
98#define KS_INFO_E1 __BIT(3) 98#define KS_INFO_E1 __BIT(3)
99} __packed; 99} __packed;
100 100
101struct hvkbd_keystroke { 101struct hvkbd_keystroke {
102 struct hvkbd_msg_hdr hdr; 102 struct hvkbd_msg_hdr hdr;
103 struct keystroke ks; 103 struct keystroke ks;
104} __packed; 104} __packed;
105 105
106struct hvkbd_keystroke_info { 106struct hvkbd_keystroke_info {
107 LIST_ENTRY(hvkbd_keystroke_info) link; 107 LIST_ENTRY(hvkbd_keystroke_info) link;
108 STAILQ_ENTRY(hvkbd_keystroke_info) slink; 108 STAILQ_ENTRY(hvkbd_keystroke_info) slink;
109 struct keystroke ks; 109 struct keystroke ks;
110}; 110};
111 111
112#define HVKBD_KEYBUF_SIZE 16 112#define HVKBD_KEYBUF_SIZE 16
113 113
114struct hvkbd_softc { 114struct hvkbd_softc {
115 device_t sc_dev; 115 device_t sc_dev;
116 116
117 struct vmbus_channel *sc_chan; 117 struct vmbus_channel *sc_chan;
118 void *sc_buf; 118 void *sc_buf;
119 119
120 kmutex_t sc_ks_lock; 120 kmutex_t sc_ks_lock;
121 LIST_HEAD(, hvkbd_keystroke_info) sc_ks_free; 121 LIST_HEAD(, hvkbd_keystroke_info) sc_ks_free;
122 STAILQ_HEAD(, hvkbd_keystroke_info) sc_ks_queue; 122 STAILQ_HEAD(, hvkbd_keystroke_info) sc_ks_queue;
123 123
124 int sc_enabled; 124 int sc_enabled;
125 int sc_polling; 125 int sc_polling;
126 int sc_console_keyboard; 126 int sc_console_keyboard;
127#if defined(WSDISPLAY_COMPAT_RAWKBD) 127#if defined(WSDISPLAY_COMPAT_RAWKBD)
128 int sc_rawkbd; 128 int sc_rawkbd;
129#endif 129#endif
130 130
131 int sc_connected; 131 int sc_connected;
132 uint32_t sc_connect_status; 132 uint32_t sc_connect_status;
133 133
134 device_t sc_wskbddev; 134 device_t sc_wskbddev;
135}; 135};
136 136
137static int hvkbd_match(device_t, cfdata_t, void *); 137static int hvkbd_match(device_t, cfdata_t, void *);
138static void hvkbd_attach(device_t, device_t, void *); 138static void hvkbd_attach(device_t, device_t, void *);
139 139
140CFATTACH_DECL_NEW(hvkbd, sizeof(struct hvkbd_softc), 140CFATTACH_DECL_NEW(hvkbd, sizeof(struct hvkbd_softc),
141 hvkbd_match, hvkbd_attach, NULL, NULL); 141 hvkbd_match, hvkbd_attach, NULL, NULL);
142 142
143static int hvkbd_alloc_keybuf(struct hvkbd_softc *); 143static int hvkbd_alloc_keybuf(struct hvkbd_softc *);
144static void hvkbd_free_keybuf(struct hvkbd_softc *); 144static void hvkbd_free_keybuf(struct hvkbd_softc *);
145 145
146static int hvkbd_enable(void *, int); 146static int hvkbd_enable(void *, int);
147static void hvkbd_set_leds(void *, int); 147static void hvkbd_set_leds(void *, int);
148static int hvkbd_ioctl(void *, u_long, void *, int, struct lwp *); 148static int hvkbd_ioctl(void *, u_long, void *, int, struct lwp *);
149 149
150static const struct wskbd_accessops hvkbd_accessops = { 150static const struct wskbd_accessops hvkbd_accessops = {
151 hvkbd_enable, 151 hvkbd_enable,
152 hvkbd_set_leds, 152 hvkbd_set_leds,
153 hvkbd_ioctl, 153 hvkbd_ioctl,
154}; 154};
155 155
156static const struct wskbd_mapdata hvkbd_keymapdata = { 156static const struct wskbd_mapdata hvkbd_keymapdata = {
157 pckbd_keydesctab, 157 pckbd_keydesctab,
158#if defined(PCKBD_LAYOUT) 158#if defined(PCKBD_LAYOUT)
159 PCKBD_LAYOUT, 159 PCKBD_LAYOUT,
160#else 160#else
161 KB_US, 161 KB_US,
162#endif 162#endif
163}; 163};
164 164
165static int hvkbd_connect(struct hvkbd_softc *); 165static int hvkbd_connect(struct hvkbd_softc *);
166static void hvkbd_intr(void *); 166static void hvkbd_intr(void *);
167 167
168static void hvkbd_cngetc(void *, u_int *, int *); 168static void hvkbd_cngetc(void *, u_int *, int *);
169static void hvkbd_cnpollc(void *, int); 169static void hvkbd_cnpollc(void *, int);
170 170
171static const struct wskbd_consops hvkbd_consops = { 171static const struct wskbd_consops hvkbd_consops = {
172 .getc = hvkbd_cngetc, 172 .getc = hvkbd_cngetc,
173 .pollc = hvkbd_cnpollc, 173 .pollc = hvkbd_cnpollc,
174 .bell = NULL, 174 .bell = NULL,
175}; 175};
176 176
177static int hvkbd_is_console; 177static int hvkbd_is_console;
178 178
179static int 179static int
180hvkbd_match(device_t parent, cfdata_t cf, void *aux) 180hvkbd_match(device_t parent, cfdata_t cf, void *aux)
181{ 181{
182 struct vmbus_attach_args *aa = aux; 182 struct vmbus_attach_args *aa = aux;
183 183
184 if (memcmp(aa->aa_type, &hyperv_guid_kbd, sizeof(*aa->aa_type)) != 0) 184 if (memcmp(aa->aa_type, &hyperv_guid_kbd, sizeof(*aa->aa_type)) != 0)
185 return 0; 185 return 0;
186 186
187 /* If hvkbd(4) is not console, we use pckbd(4) in Gen.1 VM. */ 187 /* If hvkbd(4) is not console, we use pckbd(4) in Gen.1 VM. */
188 if (!hvkbd_is_console && hyperv_is_gen1()) 188 if (!hvkbd_is_console && hyperv_is_gen1())
189 return 0; 189 return 0;
190 190
191 return 1; 191 return 1;
192} 192}
193 193
194static void 194static void
195hvkbd_attach(device_t parent, device_t self, void *aux) 195hvkbd_attach(device_t parent, device_t self, void *aux)
196{ 196{
197 struct hvkbd_softc *sc = device_private(self); 197 struct hvkbd_softc *sc = device_private(self);
198 struct vmbus_attach_args *aa = aux; 198 struct vmbus_attach_args *aa = aux;
199 struct wskbddev_attach_args a; 199 struct wskbddev_attach_args a;
200 200
201 sc->sc_dev = self; 201 sc->sc_dev = self;
202 sc->sc_chan = aa->aa_chan; 202 sc->sc_chan = aa->aa_chan;
203 203
204 aprint_naive("\n"); 204 aprint_naive("\n");
205 aprint_normal(": Hyper-V Synthetic Keyboard\n"); 205 aprint_normal(": Hyper-V Synthetic Keyboard\n");
206 206
207 mutex_init(&sc->sc_ks_lock, MUTEX_DEFAULT, IPL_TTY); 207 mutex_init(&sc->sc_ks_lock, MUTEX_DEFAULT, IPL_TTY);
208 LIST_INIT(&sc->sc_ks_free); 208 LIST_INIT(&sc->sc_ks_free);
209 STAILQ_INIT(&sc->sc_ks_queue); 209 STAILQ_INIT(&sc->sc_ks_queue);
210 hvkbd_alloc_keybuf(sc); 210 hvkbd_alloc_keybuf(sc);
211 211
212 sc->sc_buf = kmem_zalloc(HVKBD_BUFSIZE, KM_SLEEP); 212 sc->sc_buf = kmem_zalloc(HVKBD_BUFSIZE, KM_SLEEP);
213 213
214 sc->sc_chan->ch_flags &= ~CHF_BATCHED; 214 sc->sc_chan->ch_flags &= ~CHF_BATCHED;
215 if (vmbus_channel_open(sc->sc_chan, 215 if (vmbus_channel_open(sc->sc_chan,
216 HVKBD_TX_RING_SIZE + HVKBD_RX_RING_SIZE, NULL, 0, hvkbd_intr, sc)) { 216 HVKBD_TX_RING_SIZE + HVKBD_RX_RING_SIZE, NULL, 0, hvkbd_intr, sc)) {
217 aprint_error_dev(self, "failed to open channel\n"); 217 aprint_error_dev(self, "failed to open channel\n");
218 goto free_buf; 218 goto free_buf;
219 } 219 }
220 220
221 if (hvkbd_connect(sc)) 221 if (hvkbd_connect(sc))
222 goto free_buf; 222 goto free_buf;
223 223
224 if (!pmf_device_register(self, NULL, NULL)) 224 if (!pmf_device_register(self, NULL, NULL))
225 aprint_error_dev(self, "couldn't establish power handler\n"); 225 aprint_error_dev(self, "couldn't establish power handler\n");
226 226
227 sc->sc_console_keyboard = hvkbd_is_console; 227 sc->sc_console_keyboard = hvkbd_is_console;
228 if (hvkbd_is_console) 228 if (hvkbd_is_console)
229 hvkbd_is_console = 0; 229 hvkbd_is_console = 0;
230 230
231 if (sc->sc_console_keyboard) { 231 if (sc->sc_console_keyboard) {
232 wskbd_cnattach(&hvkbd_consops, sc, &hvkbd_keymapdata); 232 wskbd_cnattach(&hvkbd_consops, sc, &hvkbd_keymapdata);
233 hvkbd_enable(sc, 1); 233 hvkbd_enable(sc, 1);
234 } 234 }
235 235
236 a.console = sc->sc_console_keyboard; 236 a.console = sc->sc_console_keyboard;
237 a.keymap = &hvkbd_keymapdata; 237 a.keymap = &hvkbd_keymapdata;
238 a.accessops = &hvkbd_accessops; 238 a.accessops = &hvkbd_accessops;
239 a.accesscookie = sc; 239 a.accesscookie = sc;
240 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 240 sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
241 return; 241 return;
242 242
243free_buf: 243free_buf:
244 if (sc->sc_buf != NULL) { 244 if (sc->sc_buf != NULL) {
245 kmem_free(sc->sc_buf, HVKBD_BUFSIZE); 245 kmem_free(sc->sc_buf, HVKBD_BUFSIZE);
246 sc->sc_buf = NULL; 246 sc->sc_buf = NULL;
247 } 247 }
248 hvkbd_free_keybuf(sc); 248 hvkbd_free_keybuf(sc);
249} 249}
250 250
251static int 251static int
252hvkbd_alloc_keybuf(struct hvkbd_softc *sc) 252hvkbd_alloc_keybuf(struct hvkbd_softc *sc)
253{ 253{
254 struct hvkbd_keystroke_info *ksi; 254 struct hvkbd_keystroke_info *ksi;
255 int i; 255 int i;
256 256
257 for (i = 0; i < HVKBD_KEYBUF_SIZE; i++) { 257 for (i = 0; i < HVKBD_KEYBUF_SIZE; i++) {
258 ksi = kmem_zalloc(sizeof(*ksi), KM_SLEEP); 258 ksi = kmem_zalloc(sizeof(*ksi), KM_SLEEP);
259 LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link); 259 LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link);
260 } 260 }
261 261
262 return 0; 262 return 0;
263} 263}
264 264
265static void 265static void
266hvkbd_free_keybuf(struct hvkbd_softc *sc) 266hvkbd_free_keybuf(struct hvkbd_softc *sc)
267{ 267{
268 struct hvkbd_keystroke_info *ksi; 268 struct hvkbd_keystroke_info *ksi;
269 269
270 while ((ksi = STAILQ_FIRST(&sc->sc_ks_queue)) != NULL) { 270 while ((ksi = STAILQ_FIRST(&sc->sc_ks_queue)) != NULL) {
271 STAILQ_REMOVE(&sc->sc_ks_queue, ksi, hvkbd_keystroke_info, 271 STAILQ_REMOVE(&sc->sc_ks_queue, ksi, hvkbd_keystroke_info,
272 slink); 272 slink);
273 kmem_free(ksi, sizeof(*ksi)); 273 kmem_free(ksi, sizeof(*ksi));
274 } 274 }
275 while ((ksi = LIST_FIRST(&sc->sc_ks_free)) != NULL) { 275 while ((ksi = LIST_FIRST(&sc->sc_ks_free)) != NULL) {
276 LIST_REMOVE(ksi, link); 276 LIST_REMOVE(ksi, link);
277 kmem_free(ksi, sizeof(*ksi)); 277 kmem_free(ksi, sizeof(*ksi));
278 } 278 }
279} 279}
280 280
281int 281int
282hvkbd_enable(void *v, int on) 282hvkbd_enable(void *v, int on)
283{ 283{
284 struct hvkbd_softc *sc = v; 284 struct hvkbd_softc *sc = v;
285 285
286 sc->sc_enabled = on; 286 sc->sc_enabled = on;
287 287
288 return 0; 288 return 0;
289} 289}
290 290
291static void 291static void
292hvkbd_set_leds(void *v, int leds) 292hvkbd_set_leds(void *v, int leds)
293{ 293{
294} 294}
295 295
296static int 296static int
297hvkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 297hvkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
298{ 298{
299#if defined(WSDISPLAY_COMPAT_RAWKBD) 299#if defined(WSDISPLAY_COMPAT_RAWKBD)
300 struct hvkbd_softc *sc = v; 300 struct hvkbd_softc *sc = v;
301#endif 301#endif
302 302
303 switch (cmd) { 303 switch (cmd) {
304 case WSKBDIO_GTYPE: 304 case WSKBDIO_GTYPE:
305 *(int *)data = WSKBD_TYPE_HYPERV; 305 *(int *)data = WSKBD_TYPE_HYPERV;
306 return 0; 306 return 0;
307 307
308 case WSKBDIO_SETLEDS: 308 case WSKBDIO_SETLEDS:
309 hvkbd_set_leds(v, *(int *)data); 309 hvkbd_set_leds(v, *(int *)data);
310 return 0; 310 return 0;
311 311
312 case WSKBDIO_GETLEDS: 312 case WSKBDIO_GETLEDS:
313 *(int *)data = 0; 313 *(int *)data = 0;
314 return 0; 314 return 0;
315 315
316#if defined(WSDISPLAY_COMPAT_RAWKBD) 316#if defined(WSDISPLAY_COMPAT_RAWKBD)
317 case WSKBDIO_SETMODE: 317 case WSKBDIO_SETMODE:
318 sc->sc_rawkbd = (*(int *)data == WSKBD_RAW); 318 sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
319 return 0; 319 return 0;
320#endif 320#endif
321 } 321 }
322 322
323 return EPASSTHROUGH; 323 return EPASSTHROUGH;
324} 324}
325 325
326static int 326static int
327hvkbd_connect(struct hvkbd_softc *sc) 327hvkbd_connect(struct hvkbd_softc *sc)
328{ 328{
329 struct hvkbd_proto_req req; 329 struct hvkbd_proto_req req;
330 int timo = 100; 330 int timo = 100;
331 int error, s; 331 int error, s;
332 332
333 sc->sc_connected = 0; 333 sc->sc_connected = 0;
334 334
335 memset(&req, 0, sizeof(req)); 335 memset(&req, 0, sizeof(req));
336 req.hdr.type = HVKBD_PROTO_REQUEST; 336 req.hdr.type = HVKBD_PROTO_REQUEST;
337 req.ver = HVKBD_VERSION; 337 req.ver = HVKBD_VERSION;
338 error = vmbus_channel_send(sc->sc_chan, &req, sizeof(req), 338 error = vmbus_channel_send(sc->sc_chan, &req, sizeof(req),
339 0, VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC); 339 0, VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC);
340 if (error) { 340 if (error) {
341 aprint_error_dev(sc->sc_dev, "failed to send connect: %d\n", 341 aprint_error_dev(sc->sc_dev, "failed to send connect: %d\n",
342 error); 342 error);
343 return error; 343 return error;
344 } 344 }
345 345
346 do { 346 do {
347 if (cold) { 347 if (cold) {
348 delay(1000); 348 delay(1000);
349 s = spltty(); 349 s = spltty();
350 hvkbd_intr(sc); 350 hvkbd_intr(sc);
351 splx(s); 351 splx(s);
352 } else 352 } else
353 tsleep(sc, PRIBIO | PCATCH, "hvkbdcon", mstohz(1)); 353 tsleep(sc, PRIBIO | PCATCH, "hvkbdcon",
 354 uimax(1, mstohz(1)));
354 } while (--timo > 0 && sc->sc_connected == 0); 355 } while (--timo > 0 && sc->sc_connected == 0);
355 356
356 if (timo == 0 && sc->sc_connected == 0) { 357 if (timo == 0 && sc->sc_connected == 0) {
357 aprint_error_dev(sc->sc_dev, "connect timed out\n"); 358 aprint_error_dev(sc->sc_dev, "connect timed out\n");
358 return ETIMEDOUT; 359 return ETIMEDOUT;
359 } 360 }
360 361
361 if (!(sc->sc_connect_status & RESP_STATUS_ACCEPTED)) { 362 if (!(sc->sc_connect_status & RESP_STATUS_ACCEPTED)) {
362 aprint_error_dev(sc->sc_dev, "protocol request failed\n"); 363 aprint_error_dev(sc->sc_dev, "protocol request failed\n");
363 return ENODEV; 364 return ENODEV;
364 } 365 }
365 366
366 return 0; 367 return 0;
367} 368}
368 369
369static int 370static int
370hvkbd_keybuf_add_keystroke(struct hvkbd_softc *sc, const struct keystroke *ks) 371hvkbd_keybuf_add_keystroke(struct hvkbd_softc *sc, const struct keystroke *ks)
371{ 372{
372 struct hvkbd_keystroke_info *ksi; 373 struct hvkbd_keystroke_info *ksi;
373 374
374 mutex_enter(&sc->sc_ks_lock); 375 mutex_enter(&sc->sc_ks_lock);
375 ksi = LIST_FIRST(&sc->sc_ks_free); 376 ksi = LIST_FIRST(&sc->sc_ks_free);
376 if (ksi != NULL) { 377 if (ksi != NULL) {
377 LIST_REMOVE(ksi, link); 378 LIST_REMOVE(ksi, link);
378 ksi->ks = *ks; 379 ksi->ks = *ks;
379 STAILQ_INSERT_TAIL(&sc->sc_ks_queue, ksi, slink); 380 STAILQ_INSERT_TAIL(&sc->sc_ks_queue, ksi, slink);
380 } 381 }
381 mutex_exit(&sc->sc_ks_lock); 382 mutex_exit(&sc->sc_ks_lock);
382 383
383 return (ksi != NULL) ? 0 : 1; 384 return (ksi != NULL) ? 0 : 1;
384} 385}
385 386
386static int 387static int
387hvkbd_decode(struct hvkbd_softc *sc, u_int *type, int *scancode) 388hvkbd_decode(struct hvkbd_softc *sc, u_int *type, int *scancode)
388{ 389{
389 struct hvkbd_keystroke_info *ksi; 390 struct hvkbd_keystroke_info *ksi;
390 struct keystroke ks; 391 struct keystroke ks;
391 392
392 mutex_enter(&sc->sc_ks_lock); 393 mutex_enter(&sc->sc_ks_lock);
393 ksi = STAILQ_FIRST(&sc->sc_ks_queue); 394 ksi = STAILQ_FIRST(&sc->sc_ks_queue);
394 if (ksi != NULL) { 395 if (ksi != NULL) {
395 STAILQ_REMOVE_HEAD(&sc->sc_ks_queue, slink); 396 STAILQ_REMOVE_HEAD(&sc->sc_ks_queue, slink);
396 ks = ksi->ks; 397 ks = ksi->ks;
397 LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link); 398 LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link);
398 } 399 }
399 mutex_exit(&sc->sc_ks_lock); 400 mutex_exit(&sc->sc_ks_lock);
400 401
401 if (ksi == NULL) 402 if (ksi == NULL)
402 return 0; 403 return 0;
403 404
404 /* 405 /*
405 * XXX: Hyper-V host send unicode to VM through 'Type clipboard text', 406 * XXX: Hyper-V host send unicode to VM through 'Type clipboard text',
406 * the mapping from unicode to scancode depends on the keymap. 407 * the mapping from unicode to scancode depends on the keymap.
407 * It is so complicated that we do not plan to support it yet. 408 * It is so complicated that we do not plan to support it yet.
408 */ 409 */
409 if (ks.info & KS_INFO_UNICODE) 410 if (ks.info & KS_INFO_UNICODE)
410 return 0; 411 return 0;
411 412
412 *type = (ks.info & KS_INFO_BREAK) ? 413 *type = (ks.info & KS_INFO_BREAK) ?
413 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 414 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
414 *scancode = ks.makecode; 415 *scancode = ks.makecode;
415 return 1; 416 return 1;
416} 417}
417 418
418#if defined(WSDISPLAY_COMPAT_RAWKBD) 419#if defined(WSDISPLAY_COMPAT_RAWKBD)
419static int 420static int
420hvkbd_encode(struct hvkbd_softc *sc, u_char *buf, int *len) 421hvkbd_encode(struct hvkbd_softc *sc, u_char *buf, int *len)
421{ 422{
422 struct hvkbd_keystroke_info *ksi; 423 struct hvkbd_keystroke_info *ksi;
423 struct keystroke ks; 424 struct keystroke ks;
424 int i; 425 int i;
425 426
426 mutex_enter(&sc->sc_ks_lock); 427 mutex_enter(&sc->sc_ks_lock);
427 ksi = STAILQ_FIRST(&sc->sc_ks_queue); 428 ksi = STAILQ_FIRST(&sc->sc_ks_queue);
428 if (ksi != NULL) { 429 if (ksi != NULL) {
429 STAILQ_REMOVE_HEAD(&sc->sc_ks_queue, slink); 430 STAILQ_REMOVE_HEAD(&sc->sc_ks_queue, slink);
430 ks = ksi->ks; 431 ks = ksi->ks;
431 LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link); 432 LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link);
432 } 433 }
433 mutex_exit(&sc->sc_ks_lock); 434 mutex_exit(&sc->sc_ks_lock);
434 435
435 if (ksi == NULL) 436 if (ksi == NULL)
436 return 0; 437 return 0;
437 438
438 /* 439 /*
439 * XXX: Hyper-V host send unicode to VM through 'Type clipboard text', 440 * XXX: Hyper-V host send unicode to VM through 'Type clipboard text',
440 * the mapping from unicode to scancode depends on the keymap. 441 * the mapping from unicode to scancode depends on the keymap.
441 * It is so complicated that we do not plan to support it yet. 442 * It is so complicated that we do not plan to support it yet.
442 */ 443 */
443 if (ks.info & KS_INFO_UNICODE) 444 if (ks.info & KS_INFO_UNICODE)
444 return 0; 445 return 0;
445 446
446 i = 0; 447 i = 0;
447 if (ks.info & (KS_INFO_E0|KS_INFO_E1)) { 448 if (ks.info & (KS_INFO_E0|KS_INFO_E1)) {
448 if (ks.info & KS_INFO_E0) 449 if (ks.info & KS_INFO_E0)
449 buf[i++] = 0xe0; 450 buf[i++] = 0xe0;
450 else 451 else
451 buf[i++] = 0xe1; 452 buf[i++] = 0xe1;
452 } 453 }
453 if (ks.info & KS_INFO_BREAK) 454 if (ks.info & KS_INFO_BREAK)
454 buf[i++] = (u_char)ks.makecode & 0x80; 455 buf[i++] = (u_char)ks.makecode & 0x80;
455 else 456 else
456 buf[i++] = (u_char)ks.makecode; 457 buf[i++] = (u_char)ks.makecode;
457 458
458 KDASSERT(i <= *len); 459 KDASSERT(i <= *len);
459 *len = i; 460 *len = i;
460 461
461 return 1; 462 return 1;
462} 463}
463#endif 464#endif
464 465
465static void 466static void
466hvkbd_intr(void *xsc) 467hvkbd_intr(void *xsc)
467{ 468{
468 struct hvkbd_softc *sc = xsc; 469 struct hvkbd_softc *sc = xsc;
469 struct vmbus_chanpkt_hdr *cph; 470 struct vmbus_chanpkt_hdr *cph;
470 const struct hvkbd_msg_hdr *hdr; 471 const struct hvkbd_msg_hdr *hdr;
471 const struct hvkbd_proto_resp *rsp; 472 const struct hvkbd_proto_resp *rsp;
472 const struct hvkbd_keystroke *ks; 473 const struct hvkbd_keystroke *ks;
473 uint64_t rid; 474 uint64_t rid;
474 uint32_t rlen; 475 uint32_t rlen;
475 u_int type; 476 u_int type;
476 int key, error; 477 int key, error;
477 478
478 for (;;) { 479 for (;;) {
479 error = vmbus_channel_recv(sc->sc_chan, sc->sc_buf, 480 error = vmbus_channel_recv(sc->sc_chan, sc->sc_buf,
480 HVKBD_BUFSIZE, &rlen, &rid, 1); 481 HVKBD_BUFSIZE, &rlen, &rid, 1);
481 if (error != 0 || rlen == 0) { 482 if (error != 0 || rlen == 0) {
482 if (error != EAGAIN) 483 if (error != EAGAIN)
483 device_printf(sc->sc_dev, 484 device_printf(sc->sc_dev,
484 "failed to receive a reply packet\n"); 485 "failed to receive a reply packet\n");
485 return; 486 return;
486 } 487 }
487 488
488 cph = (struct vmbus_chanpkt_hdr *)sc->sc_buf; 489 cph = (struct vmbus_chanpkt_hdr *)sc->sc_buf;
489 switch (cph->cph_type) { 490 switch (cph->cph_type) {
490 case VMBUS_CHANPKT_TYPE_INBAND: 491 case VMBUS_CHANPKT_TYPE_INBAND:
491 hdr = VMBUS_CHANPKT_CONST_DATA(cph); 492 hdr = VMBUS_CHANPKT_CONST_DATA(cph);
492 if (rlen < sizeof(*hdr)) { 493 if (rlen < sizeof(*hdr)) {
493 device_printf(sc->sc_dev, "Illegal packet\n"); 494 device_printf(sc->sc_dev, "Illegal packet\n");
494 continue; 495 continue;
495 } 496 }
496 497
497 switch (hdr->type) { 498 switch (hdr->type) {
498 case HVKBD_PROTO_RESPONSE: 499 case HVKBD_PROTO_RESPONSE:
499 if (!sc->sc_connected) { 500 if (!sc->sc_connected) {
500 rsp = VMBUS_CHANPKT_CONST_DATA(cph); 501 rsp = VMBUS_CHANPKT_CONST_DATA(cph);
501 if (rlen < sizeof(*rsp)) { 502 if (rlen < sizeof(*rsp)) {
502 device_printf(sc->sc_dev, 503 device_printf(sc->sc_dev,
503 "Illegal resp packet\n"); 504 "Illegal resp packet\n");
504 break; 505 break;
505 } 506 }
506 sc->sc_connect_status = rsp->status; 507 sc->sc_connect_status = rsp->status;
507 sc->sc_connected = 1; 508 sc->sc_connected = 1;
508 wakeup(sc); 509 wakeup(sc);
509 } 510 }
510 break; 511 break;
511 512
512 case HVKBD_PROTO_EVENT: 513 case HVKBD_PROTO_EVENT:
513 if (sc->sc_wskbddev == NULL || !sc->sc_enabled) 514 if (sc->sc_wskbddev == NULL || !sc->sc_enabled)
514 break; 515 break;
515 516
516 ks = VMBUS_CHANPKT_CONST_DATA(cph); 517 ks = VMBUS_CHANPKT_CONST_DATA(cph);
517 hvkbd_keybuf_add_keystroke(sc, &ks->ks); 518 hvkbd_keybuf_add_keystroke(sc, &ks->ks);
518 if (sc->sc_polling) 519 if (sc->sc_polling)
519 break; 520 break;
520 521
521#if defined(WSDISPLAY_COMPAT_RAWKBD) 522#if defined(WSDISPLAY_COMPAT_RAWKBD)
522 if (sc->sc_rawkbd) { 523 if (sc->sc_rawkbd) {
523 u_char buf[2]; 524 u_char buf[2];
524 int len; 525 int len;
525 526
526 len = sizeof(buf); 527 len = sizeof(buf);
527 if (hvkbd_encode(sc, buf, &len)) { 528 if (hvkbd_encode(sc, buf, &len)) {
528 wskbd_rawinput(sc->sc_wskbddev, 529 wskbd_rawinput(sc->sc_wskbddev,
529 buf, len); 530 buf, len);
530 } 531 }
531 break; 532 break;
532 } 533 }
533#endif 534#endif
534 if (hvkbd_decode(sc, &type, &key)) 535 if (hvkbd_decode(sc, &type, &key))
535 wskbd_input(sc->sc_wskbddev, type, key); 536 wskbd_input(sc->sc_wskbddev, type, key);
536 break; 537 break;
537 538
538 case HVKBD_PROTO_REQUEST: 539 case HVKBD_PROTO_REQUEST:
539 case HVKBD_PROTO_LED_INDICATORS: 540 case HVKBD_PROTO_LED_INDICATORS:
540 device_printf(sc->sc_dev, 541 device_printf(sc->sc_dev,
541 "unhandled message: %d\n", hdr->type); 542 "unhandled message: %d\n", hdr->type);
542 break; 543 break;
543 544
544 default: 545 default:
545 device_printf(sc->sc_dev, 546 device_printf(sc->sc_dev,
546 "unknown message: %d\n", hdr->type); 547 "unknown message: %d\n", hdr->type);
547 break; 548 break;
548 } 549 }
549 break; 550 break;
550 551
551 case VMBUS_CHANPKT_TYPE_COMP: 552 case VMBUS_CHANPKT_TYPE_COMP:
552 case VMBUS_CHANPKT_TYPE_RXBUF: 553 case VMBUS_CHANPKT_TYPE_RXBUF:
553 device_printf(sc->sc_dev, "unhandled event: %d\n", 554 device_printf(sc->sc_dev, "unhandled event: %d\n",
554 cph->cph_type); 555 cph->cph_type);
555 break; 556 break;
556 557
557 default: 558 default:
558 device_printf(sc->sc_dev, "unknown event: %d\n", 559 device_printf(sc->sc_dev, "unknown event: %d\n",
559 cph->cph_type); 560 cph->cph_type);
560 break; 561 break;
561 } 562 }
562 } 563 }
563} 564}
564 565
565int 566int
566hvkbd_cnattach(void) 567hvkbd_cnattach(void)
567{ 568{
568 569
569 hvkbd_is_console = 1; 570 hvkbd_is_console = 1;
570 571
571 return 0; 572 return 0;
572} 573}
573 574
574static void 575static void
575hvkbd_cngetc(void *v, u_int *type, int *data) 576hvkbd_cngetc(void *v, u_int *type, int *data)
576{ 577{
577 struct hvkbd_softc *sc = v; 578 struct hvkbd_softc *sc = v;
578 579
579 while (!hvkbd_decode(sc, type, data)) 580 while (!hvkbd_decode(sc, type, data))
580 hvkbd_intr(sc); 581 hvkbd_intr(sc);
581} 582}
582 583
583static void 584static void
584hvkbd_cnpollc(void *v, int on) 585hvkbd_cnpollc(void *v, int on)
585{ 586{
586 struct hvkbd_softc *sc = v; 587 struct hvkbd_softc *sc = v;
587 588
588 sc->sc_polling = on; 589 sc->sc_polling = on;
589} 590}
590 591
591MODULE(MODULE_CLASS_DRIVER, hvkbd, "vmbus"); 592MODULE(MODULE_CLASS_DRIVER, hvkbd, "vmbus");
592 593
593#ifdef _MODULE 594#ifdef _MODULE
594#include "ioconf.c" 595#include "ioconf.c"
595#endif 596#endif
596 597
597static int 598static int
598hvkbd_modcmd(modcmd_t cmd, void *aux) 599hvkbd_modcmd(modcmd_t cmd, void *aux)
599{ 600{
600 int error = 0; 601 int error = 0;
601 602
602 switch (cmd) { 603 switch (cmd) {
603 case MODULE_CMD_INIT: 604 case MODULE_CMD_INIT:
604#ifdef _MODULE 605#ifdef _MODULE
605 error = config_init_component(cfdriver_ioconf_hvkbd, 606 error = config_init_component(cfdriver_ioconf_hvkbd,
606 cfattach_ioconf_hvkbd, cfdata_ioconf_hvkbd); 607 cfattach_ioconf_hvkbd, cfdata_ioconf_hvkbd);
607#endif 608#endif
608 break; 609 break;
609 610
610 case MODULE_CMD_FINI: 611 case MODULE_CMD_FINI:
611#ifdef _MODULE 612#ifdef _MODULE
612 error = config_fini_component(cfdriver_ioconf_hvtkbd, 613 error = config_fini_component(cfdriver_ioconf_hvtkbd,
613 cfattach_ioconf_hvkbd, cfdata_ioconf_hvkbd); 614 cfattach_ioconf_hvkbd, cfdata_ioconf_hvkbd);
614#endif 615#endif
615 break; 616 break;
616 617
617 case MODULE_CMD_AUTOUNLOAD: 618 case MODULE_CMD_AUTOUNLOAD:
618 error = EBUSY; 619 error = EBUSY;
619 break; 620 break;
620 621
621 default: 622 default:
622 error = ENOTTY; 623 error = ENOTTY;
623 break; 624 break;
624 } 625 }
625 626
626 return error; 627 return error;
627} 628}