Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/usb/clients/hid/hid.c
+++ new/usr/src/uts/common/io/usb/clients/hid/hid.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26
27 27 /*
28 28 * Human Interface Device driver (HID)
29 29 *
30 30 * The HID driver is a software driver which acts as a class
31 31 * driver for USB human input devices like keyboard, mouse,
32 32 * joystick etc and provides the class-specific interfaces
33 33 * between these client driver modules and the Universal Serial
34 34 * Bus Driver(USBA).
35 35 *
36 36 * NOTE: This driver is not DDI compliant in that it uses undocumented
37 37 * functions for logging (USB_DPRINTF_L*, usb_alloc_log_hdl, usb_free_log_hdl).
38 38 *
39 39 * Undocumented functions may go away in a future Solaris OS release.
40 40 *
41 41 * Please see the DDK for sample code of these functions, and for the usbskel
42 42 * skeleton template driver which contains scaled-down versions of these
43 43 * functions written in a DDI-compliant way.
44 44 */
45 45
46 46 #define USBDRV_MAJOR_VER 2
47 47 #define USBDRV_MINOR_VER 0
48 48
49 49 #include <sys/usb/usba.h>
50 50 #include <sys/usb/usba/genconsole.h>
51 51 #include <sys/usb/clients/hid/hid.h>
52 52 #include <sys/usb/clients/hid/hid_polled.h>
53 53 #include <sys/usb/clients/hidparser/hidparser.h>
54 54 #include <sys/usb/clients/hid/hidvar.h>
55 55 #include <sys/usb/clients/hid/hidminor.h>
56 56 #include <sys/usb/clients/hidparser/hid_parser_driver.h>
57 57 #include <sys/stropts.h>
58 58 #include <sys/sunddi.h>
59 59 #include <sys/stream.h>
60 60 #include <sys/strsun.h>
61 61
62 62 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
63 63
64 64 /* Debugging support */
65 65 uint_t hid_errmask = (uint_t)PRINT_MASK_ALL;
66 66 uint_t hid_errlevel = USB_LOG_L4;
67 67 uint_t hid_instance_debug = (uint_t)-1;
68 68
69 69 /* tunables */
70 70 int hid_default_pipe_drain_timeout = HID_DEFAULT_PIPE_DRAIN_TIMEOUT;
71 71 int hid_pm_mouse = 1; /* enable remote_wakeup for USB mouse/keyboard */
72 72
73 73 /* soft state structures */
74 74 #define HID_INITIAL_SOFT_SPACE 4
75 75 static void *hid_statep;
76 76
77 77 /* Callbacks */
78 78 static void hid_interrupt_pipe_callback(usb_pipe_handle_t,
79 79 usb_intr_req_t *);
80 80 static void hid_default_pipe_callback(usb_pipe_handle_t, usb_ctrl_req_t *);
81 81 static void hid_interrupt_pipe_exception_callback(usb_pipe_handle_t,
82 82 usb_intr_req_t *);
83 83 static void hid_default_pipe_exception_callback(usb_pipe_handle_t,
84 84 usb_ctrl_req_t *);
85 85 static int hid_restore_state_event_callback(dev_info_t *);
86 86 static int hid_disconnect_event_callback(dev_info_t *);
87 87 static int hid_cpr_suspend(hid_state_t *hidp);
88 88 static void hid_cpr_resume(hid_state_t *hidp);
89 89 static void hid_power_change_callback(void *arg, int rval);
90 90
91 91 /* Supporting routines */
92 92 static size_t hid_parse_hid_descr(usb_hid_descr_t *, size_t,
93 93 usb_alt_if_data_t *, usb_ep_data_t *);
94 94 static int hid_parse_hid_descr_failure(hid_state_t *);
95 95 static int hid_handle_report_descriptor(hid_state_t *, int);
96 96 static void hid_set_idle(hid_state_t *);
97 97 static void hid_set_protocol(hid_state_t *, int);
98 98 static void hid_detach_cleanup(dev_info_t *, hid_state_t *);
99 99
100 100 static int hid_start_intr_polling(hid_state_t *);
101 101 static void hid_close_intr_pipe(hid_state_t *);
102 102 static int hid_mctl_execute_cmd(queue_t *, int, hid_req_t *,
103 103 mblk_t *);
104 104 static int hid_mctl_receive(queue_t *, mblk_t *);
105 105 static int hid_send_async_ctrl_request(hid_default_pipe_arg_t *, hid_req_t *,
106 106 uchar_t, int, ushort_t);
107 107
108 108 static void hid_create_pm_components(dev_info_t *, hid_state_t *);
109 109 static int hid_is_pm_enabled(dev_info_t *);
110 110 static void hid_restore_device_state(dev_info_t *, hid_state_t *);
111 111 static void hid_save_device_state(hid_state_t *);
112 112
113 113 static void hid_qreply_merror(queue_t *, mblk_t *, uchar_t);
114 114 static mblk_t *hid_data2mblk(uchar_t *, int);
115 115 static void hid_flush(queue_t *);
116 116
117 117 static int hid_pwrlvl0(hid_state_t *);
118 118 static int hid_pwrlvl1(hid_state_t *);
119 119 static int hid_pwrlvl2(hid_state_t *);
120 120 static int hid_pwrlvl3(hid_state_t *);
121 121 static void hid_pm_busy_component(hid_state_t *);
122 122 static void hid_pm_idle_component(hid_state_t *);
123 123
124 124 static int hid_polled_read(hid_polled_handle_t, uchar_t **);
125 125 static int hid_polled_input_enter(hid_polled_handle_t);
126 126 static int hid_polled_input_exit(hid_polled_handle_t);
127 127 static int hid_polled_input_init(hid_state_t *);
128 128 static int hid_polled_input_fini(hid_state_t *);
129 129
130 130 /* Streams entry points */
131 131 static int hid_open(queue_t *, dev_t *, int, int, cred_t *);
132 132 static int hid_close(queue_t *, int, cred_t *);
133 133 static int hid_wput(queue_t *, mblk_t *);
134 134 static int hid_wsrv(queue_t *);
135 135
136 136 /* dev_ops entry points */
137 137 static int hid_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
138 138 static int hid_attach(dev_info_t *, ddi_attach_cmd_t);
139 139 static int hid_detach(dev_info_t *, ddi_detach_cmd_t);
140 140 static int hid_power(dev_info_t *, int, int);
141 141
142 142 /*
143 143 * Warlock is not aware of the automatic locking mechanisms for
144 144 * streams drivers. The hid streams enter points are protected by
145 145 * a per module perimeter. If the locking in hid is a bottleneck
146 146 * per queue pair or per queue locking may be used. Since warlock
147 147 * is not aware of the streams perimeters, these notes have been added.
148 148 *
149 149 * Note that the perimeters do not protect the driver from callbacks
150 150 * happening while a streams entry point is executing. So, the hid_mutex
151 151 * has been created to protect the data.
152 152 */
153 153 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
154 154 _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
155 155 _NOTE(SCHEME_PROTECTS_DATA("unique per call", msgb))
156 156 _NOTE(SCHEME_PROTECTS_DATA("unique per call", queue))
157 157 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
158 158 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_intr_req))
159 159
160 160 /* module information */
161 161 static struct module_info hid_mod_info = {
162 162 0x0ffff, /* module id number */
163 163 "hid", /* module name */
164 164 0, /* min packet size accepted */
165 165 INFPSZ, /* max packet size accepted */
166 166 512, /* hi-water mark */
167 167 128 /* lo-water mark */
168 168 };
169 169
170 170 /* read queue information structure */
171 171 static struct qinit rinit = {
172 172 NULL, /* put procedure not needed */
173 173 NULL, /* service procedure not needed */
174 174 hid_open, /* called on startup */
175 175 hid_close, /* called on finish */
176 176 NULL, /* for future use */
177 177 &hid_mod_info, /* module information structure */
178 178 NULL /* module statistics structure */
179 179 };
180 180
181 181 /* write queue information structure */
182 182 static struct qinit winit = {
183 183 hid_wput, /* put procedure */
184 184 hid_wsrv, /* service procedure */
185 185 NULL, /* open not used on write side */
186 186 NULL, /* close not used on write side */
187 187 NULL, /* for future use */
188 188 &hid_mod_info, /* module information structure */
189 189 NULL /* module statistics structure */
190 190 };
191 191
192 192 struct streamtab hid_streamtab = {
193 193 &rinit,
194 194 &winit,
195 195 NULL, /* not a MUX */
196 196 NULL /* not a MUX */
197 197 };
198 198
199 199 struct cb_ops hid_cb_ops = {
200 200 nulldev, /* open */
201 201 nulldev, /* close */
202 202 nulldev, /* strategy */
203 203 nulldev, /* print */
204 204 nulldev, /* dump */
205 205 nulldev, /* read */
206 206 nulldev, /* write */
207 207 nulldev, /* ioctl */
208 208 nulldev, /* devmap */
209 209 nulldev, /* mmap */
210 210 nulldev, /* segmap */
211 211 nochpoll, /* poll */
212 212 ddi_prop_op, /* cb_prop_op */
213 213 &hid_streamtab, /* streamtab */
214 214 D_MP | D_MTPERQ
215 215 };
216 216
217 217
218 218 static struct dev_ops hid_ops = {
219 219 DEVO_REV, /* devo_rev, */
220 220 0, /* refcnt */
221 221 hid_info, /* info */
222 222 nulldev, /* identify */
223 223 nulldev, /* probe */
224 224 hid_attach, /* attach */
225 225 hid_detach, /* detach */
226 226 nodev, /* reset */
227 227 &hid_cb_ops, /* driver operations */
228 228 NULL, /* bus operations */
229 229 hid_power, /* power */
230 230 ddi_quiesce_not_needed, /* quiesce */
↓ open down ↓ |
230 lines elided |
↑ open up ↑ |
231 231 };
232 232
233 233 static struct modldrv hidmodldrv = {
234 234 &mod_driverops,
235 235 "USB HID Client Driver",
236 236 &hid_ops /* driver ops */
237 237 };
238 238
239 239 static struct modlinkage modlinkage = {
240 240 MODREV_1,
241 - &hidmodldrv,
242 - NULL,
241 + { &hidmodldrv, NULL }
243 242 };
244 243
245 244 static usb_event_t hid_events = {
246 245 hid_disconnect_event_callback,
247 246 hid_restore_state_event_callback,
248 247 NULL,
249 248 NULL,
250 249 };
251 250
252 251
253 252 int
254 253 _init(void)
255 254 {
256 255 int rval;
257 256
258 257 if (((rval = ddi_soft_state_init(&hid_statep, sizeof (hid_state_t),
259 258 HID_INITIAL_SOFT_SPACE)) != 0)) {
260 259
261 260 return (rval);
262 261 }
263 262
264 263 if ((rval = mod_install(&modlinkage)) != 0) {
265 264 ddi_soft_state_fini(&hid_statep);
266 265 }
267 266
268 267 return (rval);
269 268 }
270 269
271 270
272 271 int
273 272 _fini(void)
274 273 {
275 274 int rval;
276 275
277 276 if ((rval = mod_remove(&modlinkage)) != 0) {
278 277
279 278 return (rval);
280 279 }
281 280
282 281 ddi_soft_state_fini(&hid_statep);
283 282
284 283 return (rval);
285 284 }
286 285
287 286
288 287 int
289 288 _info(struct modinfo *modinfop)
290 289 {
291 290 return (mod_info(&modlinkage, modinfop));
292 291 }
293 292
294 293
295 294 /*
296 295 * hid_info :
297 296 * Get minor number, soft state structure etc.
298 297 */
299 298 /*ARGSUSED*/
300 299 static int
301 300 hid_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
302 301 void *arg, void **result)
303 302 {
304 303 hid_state_t *hidp = NULL;
305 304 int error = DDI_FAILURE;
306 305 minor_t minor = getminor((dev_t)arg);
307 306 int instance = HID_MINOR_TO_INSTANCE(minor);
308 307
309 308 switch (infocmd) {
310 309 case DDI_INFO_DEVT2DEVINFO:
311 310 if ((hidp = ddi_get_soft_state(hid_statep, instance)) != NULL) {
312 311 *result = hidp->hid_dip;
313 312 if (*result != NULL) {
314 313 error = DDI_SUCCESS;
315 314 }
316 315 } else
317 316 *result = NULL;
318 317 break;
319 318 case DDI_INFO_DEVT2INSTANCE:
320 319 *result = (void *)(uintptr_t)instance;
321 320 error = DDI_SUCCESS;
322 321 break;
323 322 default:
324 323 break;
325 324 }
326 325
327 326 return (error);
328 327 }
329 328
330 329
331 330 /*
332 331 * hid_attach :
333 332 * Gets called at the time of attach. Do allocation,
334 333 * and initialization of the software structure.
335 334 * Get all the descriptors, setup the
336 335 * report descriptor tree by calling hidparser
337 336 * function.
338 337 */
339 338 static int
340 339 hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
341 340 {
342 341
343 342 int instance = ddi_get_instance(dip);
344 343 int parse_hid_descr_error = 0;
345 344 hid_state_t *hidp = NULL;
346 345 uint32_t usage_page;
347 346 uint32_t usage;
348 347 usb_client_dev_data_t *dev_data;
349 348 usb_alt_if_data_t *altif_data;
350 349 char minor_name[HID_MINOR_NAME_LEN];
351 350 usb_ep_data_t *ep_data;
352 351
353 352 switch (cmd) {
354 353 case DDI_ATTACH:
355 354 break;
356 355 case DDI_RESUME:
357 356 hidp = ddi_get_soft_state(hid_statep, instance);
358 357 hid_cpr_resume(hidp);
359 358 return (DDI_SUCCESS);
360 359 default:
361 360
362 361 return (DDI_FAILURE);
363 362 }
364 363
365 364 /*
366 365 * Allocate softstate information and get softstate pointer
367 366 */
368 367 if (ddi_soft_state_zalloc(hid_statep, instance) == DDI_SUCCESS) {
369 368 hidp = ddi_get_soft_state(hid_statep, instance);
370 369 }
371 370 if (hidp == NULL) {
372 371
373 372 goto fail;
374 373 }
375 374
376 375 hidp->hid_log_handle = usb_alloc_log_hdl(dip, NULL, &hid_errlevel,
377 376 &hid_errmask, &hid_instance_debug, 0);
378 377
379 378 hidp->hid_instance = instance;
380 379 hidp->hid_dip = dip;
381 380
382 381 /*
383 382 * Register with USBA. Just retrieve interface descriptor
384 383 */
385 384 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
386 385 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
387 386 "hid_attach: client attach failed");
388 387
389 388 goto fail;
390 389 }
391 390
392 391 if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) !=
393 392 USB_SUCCESS) {
394 393
395 394 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
396 395 "hid_attach: usb_get_dev_data() failed");
397 396
398 397 goto fail;
399 398 }
400 399
401 400 /* initialize mutex */
402 401 mutex_init(&hidp->hid_mutex, NULL, MUTEX_DRIVER,
403 402 dev_data->dev_iblock_cookie);
404 403
405 404 hidp->hid_attach_flags |= HID_LOCK_INIT;
406 405
407 406 /* get interface data for alternate 0 */
408 407 altif_data = &dev_data->dev_curr_cfg->
409 408 cfg_if[dev_data->dev_curr_if].if_alt[0];
410 409
411 410 mutex_enter(&hidp->hid_mutex);
412 411 hidp->hid_dev_data = dev_data;
413 412 hidp->hid_dev_descr = dev_data->dev_descr;
414 413 hidp->hid_interfaceno = dev_data->dev_curr_if;
415 414 hidp->hid_if_descr = altif_data->altif_descr;
416 415 /*
417 416 * Make sure that the bInterfaceProtocol only has meaning to
418 417 * Boot Interface Subclass.
419 418 */
420 419 if (hidp->hid_if_descr.bInterfaceSubClass != BOOT_INTERFACE)
421 420 hidp->hid_if_descr.bInterfaceProtocol = NONE_PROTOCOL;
422 421 mutex_exit(&hidp->hid_mutex);
423 422
424 423 if ((ep_data = usb_lookup_ep_data(dip, dev_data,
425 424 hidp->hid_interfaceno, 0, 0,
426 425 (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) {
427 426
428 427 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
429 428 "no interrupt IN endpoint found");
430 429
431 430 goto fail;
432 431 }
433 432
434 433 mutex_enter(&hidp->hid_mutex);
435 434 hidp->hid_ep_intr_descr = ep_data->ep_descr;
436 435
437 436 /*
438 437 * Attempt to find the hid descriptor, it could be after interface
439 438 * or after endpoint descriptors
440 439 */
441 440 if (hid_parse_hid_descr(&hidp->hid_hid_descr, USB_HID_DESCR_SIZE,
442 441 altif_data, ep_data) != USB_HID_DESCR_SIZE) {
443 442 /*
444 443 * If parsing of hid descriptor failed and
445 444 * the device is a keyboard or mouse, use predefined
446 445 * length and packet size.
447 446 */
448 447 if (hid_parse_hid_descr_failure(hidp) == USB_FAILURE) {
449 448 mutex_exit(&hidp->hid_mutex);
450 449
451 450 goto fail;
452 451 }
453 452
454 453 /*
455 454 * hid descriptor was bad but since
456 455 * the device is a keyboard or mouse,
457 456 * we will use the default length
458 457 * and packet size.
459 458 */
460 459 parse_hid_descr_error = HID_BAD_DESCR;
461 460 } else {
462 461 /* Parse hid descriptor successful */
463 462
464 463 USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
465 464 "Hid descriptor:\n\t"
466 465 "bLength = 0x%x bDescriptorType = 0x%x "
467 466 "bcdHID = 0x%x\n\t"
468 467 "bCountryCode = 0x%x bNumDescriptors = 0x%x\n\t"
469 468 "bReportDescriptorType = 0x%x\n\t"
470 469 "wReportDescriptorLength = 0x%x",
471 470 hidp->hid_hid_descr.bLength,
472 471 hidp->hid_hid_descr.bDescriptorType,
473 472 hidp->hid_hid_descr.bcdHID,
474 473 hidp->hid_hid_descr.bCountryCode,
475 474 hidp->hid_hid_descr.bNumDescriptors,
476 475 hidp->hid_hid_descr.bReportDescriptorType,
477 476 hidp->hid_hid_descr.wReportDescriptorLength);
478 477 }
479 478
480 479 /*
481 480 * Save a copy of the default pipe for easy reference
482 481 */
483 482 hidp->hid_default_pipe = hidp->hid_dev_data->dev_default_ph;
484 483
485 484 /* we copied the descriptors we need, free the dev_data */
486 485 usb_free_dev_data(dip, dev_data);
487 486 hidp->hid_dev_data = NULL;
488 487
489 488 /*
490 489 * Don't get the report descriptor if parsing hid descriptor earlier
491 490 * failed since device probably won't return valid report descriptor
492 491 * either. Though parsing of hid descriptor failed, we have reached
493 492 * this point because the device has been identified as a
494 493 * keyboard or a mouse successfully and the default packet
495 494 * size and layout(in case of keyboard only) will be used, so it
496 495 * is ok to go ahead even if parsing of hid descriptor failed and
497 496 * we will not try to get the report descriptor.
498 497 */
499 498 if (parse_hid_descr_error != HID_BAD_DESCR) {
500 499 /*
501 500 * Sun mouse rev 105 is a bit slow in responding to this
502 501 * request and requires multiple retries
503 502 */
504 503 int retry;
505 504
506 505 /*
507 506 * Get and parse the report descriptor.
508 507 * Set the packet size if parsing is successful.
509 508 * Note that we start retry at 1 to have a delay
510 509 * in the first iteration.
511 510 */
512 511 mutex_exit(&hidp->hid_mutex);
513 512 for (retry = 1; retry < HID_RETRY; retry++) {
514 513 if (hid_handle_report_descriptor(hidp,
515 514 hidp->hid_interfaceno) == USB_SUCCESS) {
516 515 break;
517 516 }
518 517 delay(retry * drv_usectohz(1000));
519 518 }
520 519 if (retry >= HID_RETRY) {
521 520
522 521 goto fail;
523 522 }
524 523 mutex_enter(&hidp->hid_mutex);
525 524
526 525 /*
527 526 * If packet size is zero, but the device is identified
528 527 * as a mouse or a keyboard, use predefined packet
529 528 * size.
530 529 */
531 530 if (hidp->hid_packet_size == 0) {
532 531 if (hidp->hid_if_descr.bInterfaceProtocol ==
533 532 KEYBOARD_PROTOCOL) {
534 533 /* device is a keyboard */
535 534 hidp->hid_packet_size = USBKPSZ;
536 535 } else if (hidp->
537 536 hid_if_descr.bInterfaceProtocol ==
538 537 MOUSE_PROTOCOL) {
539 538 /* device is a mouse */
540 539 hidp->hid_packet_size = USBMSSZ;
541 540 } else {
542 541 USB_DPRINTF_L2(PRINT_MASK_ATTA,
543 542 hidp->hid_log_handle,
544 543 "Failed to find hid packet size");
545 544 mutex_exit(&hidp->hid_mutex);
546 545
547 546 goto fail;
548 547 }
549 548 }
550 549 }
551 550
552 551 /*
553 552 * initialize the pipe policy for the interrupt pipe.
554 553 */
555 554 hidp->hid_intr_pipe_policy.pp_max_async_reqs = 1;
556 555
557 556 /*
558 557 * Make a clas specific request to SET_IDLE
559 558 * In this case send no reports if state has not changed.
560 559 * See HID 7.2.4.
561 560 */
562 561 mutex_exit(&hidp->hid_mutex);
563 562 hid_set_idle(hidp);
564 563
565 564 /* always initialize to report protocol */
566 565 hid_set_protocol(hidp, SET_REPORT_PROTOCOL);
567 566 mutex_enter(&hidp->hid_mutex);
568 567
569 568 /*
570 569 * Create minor node based on information from the
571 570 * descriptors
572 571 */
573 572 switch (hidp->hid_if_descr.bInterfaceProtocol) {
574 573 case KEYBOARD_PROTOCOL:
575 574 (void) strcpy(minor_name, "keyboard");
576 575
577 576 break;
578 577 case MOUSE_PROTOCOL:
579 578 (void) strcpy(minor_name, "mouse");
580 579
581 580 break;
582 581 default:
583 582 /*
584 583 * If the report descriptor has the GD mouse collection in
585 584 * its multiple collection, create a minor node and support it.
586 585 * It is used on some advanced keyboard/mouse set.
587 586 */
588 587 if (hidparser_lookup_usage_collection(
589 588 hidp->hid_report_descr, HID_GENERIC_DESKTOP,
590 589 HID_GD_MOUSE) != HIDPARSER_FAILURE) {
591 590 (void) strcpy(minor_name, "mouse");
592 591
593 592 break;
594 593 }
595 594
596 595 if (hidparser_get_top_level_collection_usage(
597 596 hidp->hid_report_descr, &usage_page, &usage) !=
598 597 HIDPARSER_FAILURE) {
599 598 switch (usage_page) {
600 599 case HID_CONSUMER:
601 600 switch (usage) {
602 601 case HID_CONSUMER_CONTROL:
603 602 (void) strcpy(minor_name,
604 603 "consumer_control");
605 604
606 605 break;
607 606 default:
608 607 (void) sprintf(minor_name,
609 608 "hid_%d_%d", usage_page, usage);
610 609
611 610 break;
612 611 }
613 612
614 613 break;
615 614 case HID_GENERIC_DESKTOP:
616 615 switch (usage) {
617 616 case HID_GD_POINTER:
618 617 (void) strcpy(minor_name,
619 618 "pointer");
620 619
621 620 break;
622 621 case HID_GD_MOUSE:
623 622 (void) strcpy(minor_name,
624 623 "mouse");
625 624
626 625 break;
627 626 case HID_GD_KEYBOARD:
628 627 (void) strcpy(minor_name,
629 628 "keyboard");
630 629
631 630 break;
632 631 default:
633 632 (void) sprintf(minor_name,
634 633 "hid_%d_%d", usage_page, usage);
635 634
636 635 break;
637 636 }
638 637
639 638 break;
640 639 default:
641 640 (void) sprintf(minor_name,
642 641 "hid_%d_%d", usage_page, usage);
643 642
644 643 break;
645 644 }
646 645 } else {
647 646 USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
648 647 "hid_attach: Unsupported HID device");
649 648 mutex_exit(&hidp->hid_mutex);
650 649
651 650 goto fail;
652 651 }
653 652
654 653 break;
655 654 }
656 655
657 656 mutex_exit(&hidp->hid_mutex);
658 657
659 658 if ((ddi_create_minor_node(dip, minor_name, S_IFCHR,
660 659 HID_CONSTRUCT_EXTERNAL_MINOR(instance),
661 660 DDI_PSEUDO, 0)) != DDI_SUCCESS) {
662 661 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
663 662 "hid_attach: Could not create minor node");
664 663
665 664 goto fail;
666 665 }
667 666
668 667 /* create internal path for virtual */
669 668 if (strcmp(minor_name, "mouse") == 0) {
670 669 if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR,
671 670 HID_CONSTRUCT_INTERNAL_MINOR(instance)) != DDI_SUCCESS) {
672 671
673 672 goto fail;
674 673 }
675 674 }
676 675
677 676 if (strcmp(minor_name, "keyboard") == 0) {
678 677 if (ddi_create_internal_pathname(dip, "internal_keyboard",
679 678 S_IFCHR, HID_CONSTRUCT_INTERNAL_MINOR(instance)) !=
680 679 DDI_SUCCESS) {
681 680
682 681 goto fail;
683 682 }
684 683 }
685 684
686 685 mutex_enter(&hidp->hid_mutex);
687 686 hidp->hid_attach_flags |= HID_MINOR_NODES;
688 687 hidp->hid_dev_state = USB_DEV_ONLINE;
689 688 mutex_exit(&hidp->hid_mutex);
690 689
691 690 /* register for all events */
692 691 if (usb_register_event_cbs(dip, &hid_events, 0) != USB_SUCCESS) {
693 692 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
694 693 "usb_register_event_cbs failed");
695 694
696 695 goto fail;
697 696 }
698 697
699 698 /* now create components to power manage this device */
700 699 hid_create_pm_components(dip, hidp);
701 700 hid_pm_busy_component(hidp);
702 701 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
703 702 hid_pm_idle_component(hidp);
704 703
705 704 hidp->hid_internal_rq = hidp->hid_external_rq = NULL;
706 705 hidp->hid_internal_flag = hidp->hid_external_flag = 0;
707 706 hidp->hid_inuse_rq = NULL;
708 707
709 708 /*
710 709 * report device
711 710 */
712 711 ddi_report_dev(dip);
713 712
714 713 USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
715 714 "hid_attach: End");
716 715
717 716 return (DDI_SUCCESS);
718 717
719 718 fail:
720 719 if (hidp) {
721 720 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
722 721 "hid_attach: fail");
723 722 hid_detach_cleanup(dip, hidp);
724 723 }
725 724
726 725 return (DDI_FAILURE);
727 726 }
728 727
729 728
730 729 /*
731 730 * hid_detach :
732 731 * Gets called at the time of detach.
733 732 */
734 733 static int
735 734 hid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
736 735 {
737 736 int instance = ddi_get_instance(dip);
738 737 hid_state_t *hidp;
739 738 int rval = DDI_FAILURE;
740 739
741 740 hidp = ddi_get_soft_state(hid_statep, instance);
742 741
743 742 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle, "hid_detach");
744 743
745 744 switch (cmd) {
746 745 case DDI_DETACH:
747 746 /*
748 747 * Undo what we did in client_attach, freeing resources
749 748 * and removing things we installed. The system
750 749 * framework guarantees we are not active with this devinfo
751 750 * node in any other entry points at this time.
752 751 */
753 752 hid_detach_cleanup(dip, hidp);
754 753
755 754 return (DDI_SUCCESS);
756 755 case DDI_SUSPEND:
757 756 rval = hid_cpr_suspend(hidp);
758 757
759 758 return (rval == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
760 759 default:
761 760 break;
762 761 }
763 762
764 763 return (rval);
765 764 }
766 765
767 766 /*
768 767 * hid_open :
769 768 * Open entry point: Opens the interrupt pipe. Sets up queues.
770 769 */
771 770 /*ARGSUSED*/
772 771 static int
773 772 hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
774 773 {
775 774 int no_of_ep = 0;
776 775 int rval;
777 776 int instance;
778 777 hid_state_t *hidp;
779 778 minor_t minor = getminor(*devp);
780 779
781 780 instance = HID_MINOR_TO_INSTANCE(minor);
782 781
783 782 hidp = ddi_get_soft_state(hid_statep, instance);
784 783 if (hidp == NULL) {
785 784
786 785 return (ENXIO);
787 786 }
788 787
789 788 USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle,
790 789 "hid_open: Begin");
791 790
792 791 if (sflag) {
793 792 /* clone open NOT supported here */
794 793 return (ENXIO);
795 794 }
796 795
797 796 if (!(flag & FREAD)) {
798 797 return (EIO);
799 798 }
800 799
801 800 /*
802 801 * This is a workaround:
803 802 * Currently, if we open an already disconnected device, and send
804 803 * a CONSOPENPOLL ioctl to it, the system will panic, please refer
805 804 * to the processing HID_OPEN_POLLED_INPUT ioctl in the routine
806 805 * hid_mctl_receive().
807 806 * The consconfig_dacf module need this interface to detect if the
808 807 * device is already disconnnected.
809 808 */
810 809 mutex_enter(&hidp->hid_mutex);
811 810 if (HID_IS_INTERNAL_OPEN(minor) &&
812 811 (hidp->hid_dev_state == USB_DEV_DISCONNECTED)) {
813 812 mutex_exit(&hidp->hid_mutex);
814 813 return (ENODEV);
815 814 }
816 815
817 816 if (HID_IS_INTERNAL_OPEN(minor) &&
818 817 (hidp->hid_internal_rq != NULL)) {
819 818 ASSERT(hidp->hid_internal_rq == q);
820 819
821 820 mutex_exit(&hidp->hid_mutex);
822 821 return (0);
823 822 }
824 823
825 824 if ((!HID_IS_INTERNAL_OPEN(minor)) &&
826 825 (hidp->hid_external_rq != NULL)) {
827 826 ASSERT(hidp->hid_external_rq == q);
828 827
829 828 mutex_exit(&hidp->hid_mutex);
830 829 return (0);
831 830 }
832 831
833 832 mutex_exit(&hidp->hid_mutex);
834 833
835 834 q->q_ptr = hidp;
836 835 WR(q)->q_ptr = hidp;
837 836
838 837 mutex_enter(&hidp->hid_mutex);
839 838 if (hidp->hid_inuse_rq != NULL) {
840 839 /* Pipe has already been setup */
841 840
842 841 if (HID_IS_INTERNAL_OPEN(minor)) {
843 842 hidp->hid_internal_flag = HID_STREAMS_OPEN;
844 843 hidp->hid_inuse_rq = hidp->hid_internal_rq = q;
845 844 } else {
846 845 hidp->hid_external_flag = HID_STREAMS_OPEN;
847 846 hidp->hid_inuse_rq = hidp->hid_external_rq = q;
848 847 }
849 848
850 849 mutex_exit(&hidp->hid_mutex);
851 850
852 851 qprocson(q);
853 852
854 853 return (0);
855 854 }
856 855
857 856 /* Pipe only needs to be opened once */
858 857 hidp->hid_interrupt_pipe = NULL;
859 858 no_of_ep = hidp->hid_if_descr.bNumEndpoints;
860 859 mutex_exit(&hidp->hid_mutex);
861 860
862 861 /* Check if interrupt endpoint exists */
863 862 if (no_of_ep > 0) {
864 863 /* Open the interrupt pipe */
865 864 if (usb_pipe_open(hidp->hid_dip,
866 865 &hidp->hid_ep_intr_descr,
867 866 &hidp->hid_intr_pipe_policy, USB_FLAGS_SLEEP,
868 867 &hidp->hid_interrupt_pipe) !=
869 868 USB_SUCCESS) {
870 869
871 870 q->q_ptr = NULL;
872 871 WR(q)->q_ptr = NULL;
873 872 return (EIO);
874 873 }
875 874 }
876 875
877 876 hid_pm_busy_component(hidp);
878 877 (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
879 878
880 879 mutex_enter(&hidp->hid_mutex);
881 880 if (HID_IS_INTERNAL_OPEN(minor)) {
882 881 hidp->hid_internal_flag = HID_STREAMS_OPEN;
883 882 hidp->hid_inuse_rq = hidp->hid_internal_rq = q;
884 883 } else {
885 884 hidp->hid_external_flag = HID_STREAMS_OPEN;
886 885 hidp->hid_inuse_rq = hidp->hid_external_rq = q;
887 886 }
888 887
889 888 mutex_exit(&hidp->hid_mutex);
890 889
891 890 qprocson(q);
892 891
893 892 mutex_enter(&hidp->hid_mutex);
894 893
895 894 if ((rval = hid_start_intr_polling(hidp)) != USB_SUCCESS) {
896 895 USB_DPRINTF_L2(PRINT_MASK_OPEN, hidp->hid_log_handle,
897 896 "unable to start intr pipe polling. rval = %d", rval);
898 897
899 898 if (HID_IS_INTERNAL_OPEN(minor))
900 899 hidp->hid_internal_flag = HID_STREAMS_DISMANTLING;
901 900 else
902 901 hidp->hid_external_flag = HID_STREAMS_DISMANTLING;
903 902 mutex_exit(&hidp->hid_mutex);
904 903
905 904 usb_pipe_close(hidp->hid_dip, hidp->hid_interrupt_pipe,
906 905 USB_FLAGS_SLEEP, NULL, NULL);
907 906
908 907 mutex_enter(&hidp->hid_mutex);
909 908 hidp->hid_interrupt_pipe = NULL;
910 909 mutex_exit(&hidp->hid_mutex);
911 910
912 911 qprocsoff(q);
913 912
914 913 mutex_enter(&hidp->hid_mutex);
915 914 if (HID_IS_INTERNAL_OPEN(minor)) {
916 915 hidp->hid_internal_flag = 0;
917 916 hidp->hid_internal_rq = NULL;
918 917 if (hidp->hid_external_flag == HID_STREAMS_OPEN)
919 918 hidp->hid_inuse_rq = hidp->hid_external_rq;
920 919 else
921 920 hidp->hid_inuse_rq = NULL;
922 921 } else {
923 922 hidp->hid_external_flag = 0;
924 923 hidp->hid_external_rq = NULL;
925 924 if (hidp->hid_internal_flag == HID_STREAMS_OPEN)
926 925 hidp->hid_inuse_rq = hidp->hid_internal_rq;
927 926 else
928 927 hidp->hid_inuse_rq = NULL;
929 928 }
930 929 mutex_exit(&hidp->hid_mutex);
931 930
932 931 q->q_ptr = NULL;
933 932 WR(q)->q_ptr = NULL;
934 933
935 934 hid_pm_idle_component(hidp);
936 935
937 936 return (EIO);
938 937 }
939 938 mutex_exit(&hidp->hid_mutex);
940 939
941 940 USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle, "hid_open: End");
942 941
943 942 /*
944 943 * Keyboard and mouse is Power managed by device activity.
945 944 * All other devices go busy on open and idle on close.
946 945 */
947 946 switch (hidp->hid_pm->hid_pm_strategy) {
948 947 case HID_PM_ACTIVITY:
949 948 hid_pm_idle_component(hidp);
950 949
951 950 break;
952 951 default:
953 952
954 953 break;
955 954 }
956 955
957 956 return (0);
958 957 }
959 958
960 959
961 960 /*
962 961 * hid_close :
963 962 * Close entry point.
964 963 */
965 964 /*ARGSUSED*/
966 965 static int
967 966 hid_close(queue_t *q, int flag, cred_t *credp)
968 967 {
969 968 hid_state_t *hidp = (hid_state_t *)q->q_ptr;
970 969 queue_t *wq;
971 970 mblk_t *mp;
972 971
973 972 USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle, "hid_close:");
974 973
975 974 mutex_enter(&hidp->hid_mutex);
976 975
977 976 ASSERT((hidp->hid_internal_rq == q) ||
978 977 (hidp->hid_external_rq == q));
979 978
980 979 if (hidp->hid_internal_rq == q)
981 980 hidp->hid_internal_flag = HID_STREAMS_DISMANTLING;
982 981 else
983 982 hidp->hid_external_flag = HID_STREAMS_DISMANTLING;
984 983
985 984 mutex_exit(&hidp->hid_mutex);
986 985
987 986 /*
988 987 * In case there are any outstanding requests on
989 988 * the default pipe, wait forever for them to complete.
990 989 */
991 990 (void) usb_pipe_drain_reqs(hidp->hid_dip,
992 991 hidp->hid_default_pipe, 0, USB_FLAGS_SLEEP, NULL, 0);
993 992
994 993 mutex_enter(&hidp->hid_mutex);
995 994 wq = WR(q);
996 995 /* drain any M_CTLS on the WQ */
997 996 while (mp = getq(wq)) {
998 997 hid_qreply_merror(wq, mp, EIO);
999 998 mutex_exit(&hidp->hid_mutex);
1000 999 hid_pm_idle_component(hidp);
1001 1000 mutex_enter(&hidp->hid_mutex);
1002 1001 }
1003 1002 mutex_exit(&hidp->hid_mutex);
1004 1003
1005 1004 qprocsoff(q);
1006 1005
1007 1006 q->q_ptr = NULL;
1008 1007 wq->q_ptr = NULL;
1009 1008
1010 1009 mutex_enter(&hidp->hid_mutex);
1011 1010
1012 1011 if (hidp->hid_internal_rq == q) {
1013 1012 hidp->hid_internal_rq = NULL;
1014 1013 hidp->hid_internal_flag = 0;
1015 1014 if (hidp->hid_inuse_rq == q) {
1016 1015 /* We are closing the active stream */
1017 1016 if (hidp->hid_external_flag == HID_STREAMS_OPEN)
1018 1017 hidp->hid_inuse_rq = hidp->hid_external_rq;
1019 1018 else
1020 1019 hidp->hid_inuse_rq = NULL;
1021 1020 }
1022 1021 } else {
1023 1022 hidp->hid_external_rq = NULL;
1024 1023 hidp->hid_external_flag = 0;
1025 1024 if (hidp->hid_inuse_rq == q) {
1026 1025 /* We are closing the active stream */
1027 1026 if (hidp->hid_internal_flag == HID_STREAMS_OPEN)
1028 1027 hidp->hid_inuse_rq = hidp->hid_internal_rq;
1029 1028 else
1030 1029 hidp->hid_inuse_rq = NULL;
1031 1030 }
1032 1031 }
1033 1032
1034 1033 if (hidp->hid_inuse_rq != NULL) {
1035 1034 mutex_exit(&hidp->hid_mutex);
1036 1035 return (0);
1037 1036 }
1038 1037
1039 1038 /* all queues are closed, close USB pipes */
1040 1039 hid_close_intr_pipe(hidp);
1041 1040 mutex_exit(&hidp->hid_mutex);
1042 1041
1043 1042 /*
1044 1043 * Devices other than keyboard/mouse go idle on close.
1045 1044 */
1046 1045 switch (hidp->hid_pm->hid_pm_strategy) {
1047 1046 case HID_PM_ACTIVITY:
1048 1047
1049 1048 break;
1050 1049 default:
1051 1050 hid_pm_idle_component(hidp);
1052 1051
1053 1052 break;
1054 1053 }
1055 1054 USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
1056 1055 "hid_close: End");
1057 1056
1058 1057 return (0);
1059 1058 }
1060 1059
1061 1060
1062 1061 /*
1063 1062 * hid_wput :
1064 1063 * write put routine for the hid module
1065 1064 */
1066 1065 static int
1067 1066 hid_wput(queue_t *q, mblk_t *mp)
1068 1067 {
1069 1068 hid_state_t *hidp = (hid_state_t *)q->q_ptr;
1070 1069 int error = USB_SUCCESS;
1071 1070 struct iocblk *iocbp;
1072 1071 mblk_t *datap;
1073 1072 int direction;
1074 1073 struct copyresp *crp;
1075 1074 queue_t *tmpq;
1076 1075 int flag;
1077 1076
1078 1077 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1079 1078 "hid_wput: Begin");
1080 1079
1081 1080 /* See if the upper module is passing the right thing */
1082 1081 ASSERT(mp != NULL);
1083 1082 ASSERT(mp->b_datap != NULL);
1084 1083
1085 1084 switch (mp->b_datap->db_type) {
1086 1085 case M_FLUSH: /* Canonical flush handling */
1087 1086 if (*mp->b_rptr & FLUSHW) {
1088 1087 flushq(q, FLUSHDATA);
1089 1088 }
1090 1089
1091 1090 /* read queue not used so just send up */
1092 1091 if (*mp->b_rptr & FLUSHR) {
1093 1092 *mp->b_rptr &= ~FLUSHW;
1094 1093 qreply(q, mp);
1095 1094 } else {
1096 1095 freemsg(mp);
1097 1096 }
1098 1097
1099 1098 break;
1100 1099 case M_IOCTL:
1101 1100 iocbp = (struct iocblk *)mp->b_rptr;
1102 1101
1103 1102 /* Only accept transparent ioctls */
1104 1103 if (iocbp->ioc_count != TRANSPARENT) {
1105 1104 miocnak(q, mp, 0, EINVAL);
1106 1105 break;
1107 1106 }
1108 1107
1109 1108 switch (iocbp->ioc_cmd) {
1110 1109 case HIDIOCKMGDIRECT:
1111 1110
1112 1111 mutex_enter(&hidp->hid_mutex);
1113 1112 ASSERT(hidp->hid_inuse_rq != NULL);
1114 1113 mutex_exit(&hidp->hid_mutex);
1115 1114
1116 1115 if ((datap = allocb(sizeof (int), BPRI_MED)) == NULL) {
1117 1116 miocnak(q, mp, 0, ENOMEM);
1118 1117 break;
1119 1118 }
1120 1119
1121 1120 mutex_enter(&hidp->hid_mutex);
1122 1121 if (hidp->hid_inuse_rq == hidp->hid_internal_rq) {
1123 1122 *(int *)datap->b_wptr = 0;
1124 1123 datap->b_wptr += sizeof (int);
1125 1124 } else {
1126 1125 ASSERT(hidp->hid_inuse_rq ==
1127 1126 hidp->hid_external_rq);
1128 1127 *(int *)datap->b_wptr = 1;
1129 1128 datap->b_wptr += sizeof (int);
1130 1129 }
1131 1130 mutex_exit(&hidp->hid_mutex);
1132 1131
1133 1132 mcopyout(mp, NULL, sizeof (int), NULL, datap);
1134 1133 qreply(q, mp);
1135 1134 break;
1136 1135
1137 1136 case HIDIOCKMSDIRECT:
1138 1137 mcopyin(mp, NULL, sizeof (int), NULL);
1139 1138 qreply(q, mp);
1140 1139 break;
1141 1140
1142 1141 default:
1143 1142 miocnak(q, mp, 0, ENOTTY);
1144 1143 }
1145 1144
1146 1145 break;
1147 1146
1148 1147 case M_IOCDATA:
1149 1148
1150 1149 crp = (void *)mp->b_rptr;
1151 1150
1152 1151 if (crp->cp_rval != 0) {
1153 1152 miocnak(q, mp, 0, EIO);
1154 1153 break;
1155 1154 }
1156 1155
1157 1156 switch (crp->cp_cmd) {
1158 1157 case HIDIOCKMGDIRECT:
1159 1158 miocack(q, mp, 0, 0);
1160 1159 break;
1161 1160
1162 1161 case HIDIOCKMSDIRECT:
1163 1162 direction = *(int *)mp->b_cont->b_rptr;
1164 1163
1165 1164 if ((direction != 0) && (direction != 1)) {
1166 1165 miocnak(q, mp, 0, EINVAL);
1167 1166 break;
1168 1167 }
1169 1168
1170 1169 mutex_enter(&hidp->hid_mutex);
1171 1170
1172 1171 if (direction == 0) {
1173 1172 /* The internal stream is made active */
1174 1173 flag = hidp->hid_internal_flag;
1175 1174 tmpq = hidp->hid_internal_rq;
1176 1175 } else {
1177 1176 /* The external stream is made active */
1178 1177 flag = hidp->hid_external_flag;
1179 1178 tmpq = hidp->hid_external_rq;
1180 1179 }
1181 1180
1182 1181 if (flag != HID_STREAMS_OPEN) {
1183 1182 mutex_exit(&hidp->hid_mutex);
1184 1183 miocnak(q, mp, 0, EIO);
1185 1184 break;
1186 1185 }
1187 1186
1188 1187 hidp->hid_inuse_rq = tmpq;
1189 1188
1190 1189 mutex_exit(&hidp->hid_mutex);
1191 1190 miocack(q, mp, 0, 0);
1192 1191 break;
1193 1192
1194 1193 default:
1195 1194 miocnak(q, mp, 0, ENOTTY);
1196 1195 break;
1197 1196 }
1198 1197
1199 1198 break;
1200 1199
1201 1200 case M_CTL:
1202 1201 /* we are busy now */
1203 1202 hid_pm_busy_component(hidp);
1204 1203
1205 1204 if (q->q_first) {
1206 1205 (void) putq(q, mp);
1207 1206 } else {
1208 1207 error = hid_mctl_receive(q, mp);
1209 1208 switch (error) {
1210 1209 case HID_ENQUEUE:
1211 1210 /*
1212 1211 * put this mblk on the WQ for the wsrv to
1213 1212 * process
1214 1213 */
1215 1214 (void) putq(q, mp);
1216 1215
1217 1216 break;
1218 1217 case HID_INPROGRESS:
1219 1218 /* request has been queued to the device */
1220 1219
1221 1220 break;
1222 1221 case HID_SUCCESS:
1223 1222 /*
1224 1223 * returned by M_CTLS that are processed
1225 1224 * immediately
1226 1225 */
1227 1226
1228 1227 /* FALLTHRU */
1229 1228 case HID_FAILURE:
1230 1229 default:
1231 1230 hid_pm_idle_component(hidp);
1232 1231 break;
1233 1232 }
1234 1233 }
1235 1234 break;
1236 1235 default:
1237 1236 hid_qreply_merror(q, mp, EINVAL);
1238 1237 error = USB_FAILURE;
1239 1238 break;
1240 1239 }
1241 1240
1242 1241 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1243 1242 "hid_wput: End");
1244 1243
1245 1244 return (DDI_SUCCESS);
1246 1245 }
1247 1246
1248 1247
1249 1248 /*
1250 1249 * hid_wsrv :
1251 1250 * Write service routine for hid. When a message arrives through
1252 1251 * hid_wput(), it is kept in write queue to be serviced later.
1253 1252 */
1254 1253 static int
1255 1254 hid_wsrv(queue_t *q)
1256 1255 {
1257 1256 hid_state_t *hidp = (hid_state_t *)q->q_ptr;
1258 1257 int error;
1259 1258 mblk_t *mp;
1260 1259
1261 1260 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1262 1261 "hid_wsrv: Begin");
1263 1262
1264 1263 mutex_enter(&hidp->hid_mutex);
1265 1264 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1266 1265 "hid_wsrv: dev_state: %s",
1267 1266 usb_str_dev_state(hidp->hid_dev_state));
1268 1267
1269 1268 /*
1270 1269 * raise power if we are powered down. It is OK to block here since
1271 1270 * we have a separate thread to process this STREAM
1272 1271 */
1273 1272 if (hidp->hid_dev_state == USB_DEV_PWRED_DOWN) {
1274 1273 mutex_exit(&hidp->hid_mutex);
1275 1274 (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
1276 1275 mutex_enter(&hidp->hid_mutex);
1277 1276 }
1278 1277
1279 1278 /*
1280 1279 * continue servicing all the M_CTL's till the queue is empty
1281 1280 * or the device gets disconnected or till a hid_close()
1282 1281 */
1283 1282 while ((hidp->hid_dev_state == USB_DEV_ONLINE) &&
1284 1283 (HID_STREAMS_FLAG(q, hidp) != HID_STREAMS_DISMANTLING) &&
1285 1284 ((mp = getq(q)) != NULL)) {
1286 1285
1287 1286 /* Send a message down */
1288 1287 mutex_exit(&hidp->hid_mutex);
1289 1288 error = hid_mctl_receive(q, mp);
1290 1289 switch (error) {
1291 1290 case HID_ENQUEUE:
1292 1291 /* put this mblk back on q to preserve order */
1293 1292 (void) putbq(q, mp);
1294 1293
1295 1294 break;
1296 1295 case HID_INPROGRESS:
1297 1296 /* request has been queued to the device */
1298 1297
1299 1298 break;
1300 1299 case HID_SUCCESS:
1301 1300 case HID_FAILURE:
1302 1301 default:
1303 1302 hid_pm_idle_component(hidp);
1304 1303
1305 1304 break;
1306 1305 }
1307 1306 mutex_enter(&hidp->hid_mutex);
1308 1307 }
1309 1308 mutex_exit(&hidp->hid_mutex);
1310 1309 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1311 1310 "hid_wsrv: End");
1312 1311
1313 1312 return (DDI_SUCCESS);
1314 1313 }
1315 1314
1316 1315
1317 1316 /*
1318 1317 * hid_power:
1319 1318 * power entry point
1320 1319 */
1321 1320 static int
1322 1321 hid_power(dev_info_t *dip, int comp, int level)
1323 1322 {
1324 1323 int instance = ddi_get_instance(dip);
1325 1324 hid_state_t *hidp;
1326 1325 hid_power_t *hidpm;
1327 1326 int retval;
1328 1327
1329 1328 hidp = ddi_get_soft_state(hid_statep, instance);
1330 1329
1331 1330 USB_DPRINTF_L3(PRINT_MASK_PM, hidp->hid_log_handle, "hid_power:"
1332 1331 " hid_state: comp=%d level=%d", comp, level);
1333 1332
1334 1333 /* check if we are transitioning to a legal power level */
1335 1334 mutex_enter(&hidp->hid_mutex);
1336 1335 hidpm = hidp->hid_pm;
1337 1336
1338 1337 if (USB_DEV_PWRSTATE_OK(hidpm->hid_pwr_states, level)) {
1339 1338
1340 1339 USB_DPRINTF_L2(PRINT_MASK_PM, hidp->hid_log_handle,
1341 1340 "hid_power: illegal level=%d hid_pwr_states=%d",
1342 1341 level, hidpm->hid_pwr_states);
1343 1342
1344 1343 mutex_exit(&hidp->hid_mutex);
1345 1344
1346 1345 return (DDI_FAILURE);
1347 1346 }
1348 1347
1349 1348 switch (level) {
1350 1349 case USB_DEV_OS_PWR_OFF:
1351 1350 retval = hid_pwrlvl0(hidp);
1352 1351 break;
1353 1352 case USB_DEV_OS_PWR_1:
1354 1353 retval = hid_pwrlvl1(hidp);
1355 1354 break;
1356 1355 case USB_DEV_OS_PWR_2:
1357 1356 retval = hid_pwrlvl2(hidp);
1358 1357 break;
1359 1358 case USB_DEV_OS_FULL_PWR:
1360 1359 retval = hid_pwrlvl3(hidp);
1361 1360 break;
1362 1361 default:
1363 1362 retval = USB_FAILURE;
1364 1363 break;
1365 1364 }
1366 1365
1367 1366 mutex_exit(&hidp->hid_mutex);
1368 1367
1369 1368 return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1370 1369 }
1371 1370
1372 1371
1373 1372 /*
1374 1373 * hid_interrupt_pipe_callback:
1375 1374 * Callback function for the hid intr pipe. This function is called by
1376 1375 * USBA when a buffer has been filled. This driver does not cook the data,
1377 1376 * it just sends the message up.
1378 1377 */
1379 1378 static void
1380 1379 hid_interrupt_pipe_callback(usb_pipe_handle_t pipe, usb_intr_req_t *req)
1381 1380 {
1382 1381 hid_state_t *hidp = (hid_state_t *)req->intr_client_private;
1383 1382 queue_t *q;
1384 1383
1385 1384 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1386 1385 "hid_interrupt_pipe_callback: ph = 0x%p req = 0x%p",
1387 1386 (void *)pipe, (void *)req);
1388 1387
1389 1388 hid_pm_busy_component(hidp);
1390 1389
1391 1390 mutex_enter(&hidp->hid_mutex);
1392 1391
1393 1392 /*
1394 1393 * If hid_close() is in progress, we shouldn't try accessing queue
1395 1394 * Otherwise indicate that a putnext is going to happen, so
1396 1395 * if close after this, that should wait for the putnext to finish.
1397 1396 */
1398 1397 if (HID_STREAMS_FLAG(hidp->hid_inuse_rq, hidp) ==
1399 1398 HID_STREAMS_OPEN) {
1400 1399 /*
1401 1400 * Check if data can be put to the next queue.
1402 1401 */
1403 1402 if (!canputnext(hidp->hid_inuse_rq)) {
1404 1403 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
1405 1404 "Buffer flushed when overflowed.");
1406 1405
1407 1406 /* Flush the queue above */
1408 1407 hid_flush(hidp->hid_inuse_rq);
1409 1408 mutex_exit(&hidp->hid_mutex);
1410 1409 } else {
1411 1410 q = hidp->hid_inuse_rq;
1412 1411 mutex_exit(&hidp->hid_mutex);
1413 1412
1414 1413 /* Put data upstream */
1415 1414 putnext(q, req->intr_data);
1416 1415
1417 1416 /* usb_free_intr_req should not free data */
1418 1417 req->intr_data = NULL;
1419 1418 }
1420 1419 } else {
1421 1420 mutex_exit(&hidp->hid_mutex);
1422 1421 }
1423 1422
1424 1423 /* free request and data */
1425 1424 usb_free_intr_req(req);
1426 1425 hid_pm_idle_component(hidp);
1427 1426 }
1428 1427
1429 1428
1430 1429 /*
1431 1430 * hid_default_pipe_callback :
1432 1431 * Callback routine for the asynchronous control transfer
1433 1432 * Called from hid_send_async_ctrl_request() where we open
1434 1433 * the pipe in exclusive mode
1435 1434 */
1436 1435 static void
1437 1436 hid_default_pipe_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *req)
1438 1437 {
1439 1438 hid_default_pipe_arg_t *hid_default_pipe_arg =
1440 1439 (hid_default_pipe_arg_t *)req->ctrl_client_private;
1441 1440 queue_t *wq = hid_default_pipe_arg->hid_default_pipe_arg_queue;
1442 1441 queue_t *rq = RD(wq);
1443 1442 hid_state_t *hidp = (hid_state_t *)rq->q_ptr;
1444 1443 mblk_t *mctl_mp;
1445 1444 mblk_t *data = NULL;
1446 1445
1447 1446 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1448 1447 "hid_default_pipe_callback: "
1449 1448 "ph = 0x%p, req = 0x%p, data= 0x%p",
1450 1449 (void *)pipe, (void *)req, (void *)data);
1451 1450
1452 1451 ASSERT((req->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0);
1453 1452
1454 1453 if (req->ctrl_data) {
1455 1454 data = req->ctrl_data;
1456 1455 req->ctrl_data = NULL;
1457 1456 }
1458 1457
1459 1458 /*
1460 1459 * Free the b_cont of the original message that was sent down.
1461 1460 */
1462 1461 mctl_mp = hid_default_pipe_arg->hid_default_pipe_arg_mblk;
1463 1462 freemsg(mctl_mp->b_cont);
1464 1463
1465 1464 /* chain the mblk received to the original & send it up */
1466 1465 mctl_mp->b_cont = data;
1467 1466
1468 1467 if (canputnext(rq)) {
1469 1468 putnext(rq, mctl_mp);
1470 1469 } else {
1471 1470 freemsg(mctl_mp); /* avoid leak */
1472 1471 }
1473 1472
1474 1473 /*
1475 1474 * Free the argument for the asynchronous callback
1476 1475 */
1477 1476 kmem_free(hid_default_pipe_arg, sizeof (hid_default_pipe_arg_t));
1478 1477
1479 1478 /*
1480 1479 * Free the control pipe request structure.
1481 1480 */
1482 1481 usb_free_ctrl_req(req);
1483 1482
1484 1483 mutex_enter(&hidp->hid_mutex);
1485 1484 hidp->hid_default_pipe_req--;
1486 1485 ASSERT(hidp->hid_default_pipe_req >= 0);
1487 1486 mutex_exit(&hidp->hid_mutex);
1488 1487
1489 1488 hid_pm_idle_component(hidp);
1490 1489 qenable(wq);
1491 1490 }
1492 1491
1493 1492
1494 1493 /*
1495 1494 * hid_interrupt_pipe_exception_callback:
1496 1495 * Exception callback routine for interrupt pipe. If there is any data,
1497 1496 * destroy it. No threads are waiting for the exception callback.
1498 1497 */
1499 1498 /*ARGSUSED*/
1500 1499 static void
1501 1500 hid_interrupt_pipe_exception_callback(usb_pipe_handle_t pipe,
1502 1501 usb_intr_req_t *req)
1503 1502 {
1504 1503 hid_state_t *hidp = (hid_state_t *)req->intr_client_private;
1505 1504 mblk_t *data = req->intr_data;
1506 1505 usb_cb_flags_t flags = req->intr_cb_flags;
1507 1506 int rval;
1508 1507
1509 1508 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
1510 1509 "hid_interrupt_pipe_exception_callback: "
1511 1510 "completion_reason = 0x%x, data = 0x%p, flag = 0x%x",
1512 1511 req->intr_completion_reason, (void *)data, req->intr_cb_flags);
1513 1512
1514 1513 ASSERT((req->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0);
1515 1514
1516 1515 if (((flags & USB_CB_FUNCTIONAL_STALL) != 0) &&
1517 1516 ((flags & USB_CB_STALL_CLEARED) == 0)) {
1518 1517 USB_DPRINTF_L2(PRINT_MASK_ALL,
1519 1518 hidp->hid_log_handle,
1520 1519 "hid_interrupt_pipe_exception_callback: "
1521 1520 "unable to clear stall. flags = 0x%x",
1522 1521 req->intr_cb_flags);
1523 1522 }
1524 1523
1525 1524 mutex_enter(&hidp->hid_mutex);
1526 1525
1527 1526 switch (req->intr_completion_reason) {
1528 1527 case USB_CR_STOPPED_POLLING:
1529 1528 case USB_CR_PIPE_CLOSING:
1530 1529 default:
1531 1530
1532 1531 break;
1533 1532 case USB_CR_PIPE_RESET:
1534 1533 case USB_CR_NO_RESOURCES:
1535 1534 if ((hidp->hid_dev_state == USB_DEV_ONLINE) &&
1536 1535 ((rval = hid_start_intr_polling(hidp)) !=
1537 1536 USB_SUCCESS)) {
1538 1537 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
1539 1538 "unable to restart interrupt poll. rval = %d",
1540 1539 rval);
1541 1540 }
1542 1541
1543 1542 break;
1544 1543 }
1545 1544
1546 1545 mutex_exit(&hidp->hid_mutex);
1547 1546
1548 1547 usb_free_intr_req(req);
1549 1548 }
1550 1549
1551 1550
1552 1551 /*
1553 1552 * hid_default_pipe_exception_callback:
1554 1553 * Exception callback routine for default pipe.
1555 1554 */
1556 1555 /*ARGSUSED*/
1557 1556 static void
1558 1557 hid_default_pipe_exception_callback(usb_pipe_handle_t pipe,
1559 1558 usb_ctrl_req_t *req)
1560 1559 {
1561 1560 hid_default_pipe_arg_t *hid_default_pipe_arg =
1562 1561 (hid_default_pipe_arg_t *)req->ctrl_client_private;
1563 1562 queue_t *wq = hid_default_pipe_arg->hid_default_pipe_arg_queue;
1564 1563 queue_t *rq = RD(wq);
1565 1564 hid_state_t *hidp = (hid_state_t *)rq->q_ptr;
1566 1565 usb_cr_t ctrl_completion_reason = req->ctrl_completion_reason;
1567 1566 mblk_t *mp, *data = NULL;
1568 1567
1569 1568 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
1570 1569 "hid_default_pipe_exception_callback: "
1571 1570 "completion_reason = 0x%x, data = 0x%p, flag = 0x%x",
1572 1571 ctrl_completion_reason, (void *)data, req->ctrl_cb_flags);
1573 1572
1574 1573 ASSERT((req->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0);
1575 1574
1576 1575 mp = hid_default_pipe_arg->hid_default_pipe_arg_mblk;
1577 1576
1578 1577 /*
1579 1578 * Pass an error message up. Reuse existing mblk.
1580 1579 */
1581 1580 if (canputnext(rq)) {
1582 1581 mp->b_datap->db_type = M_ERROR;
1583 1582 mp->b_rptr = mp->b_datap->db_base;
1584 1583 mp->b_wptr = mp->b_rptr + sizeof (char);
1585 1584 *mp->b_rptr = EIO;
1586 1585 putnext(rq, mp);
1587 1586 } else {
1588 1587 freemsg(mp);
1589 1588 }
1590 1589
1591 1590 kmem_free(hid_default_pipe_arg, sizeof (hid_default_pipe_arg_t));
1592 1591
1593 1592 mutex_enter(&hidp->hid_mutex);
1594 1593 hidp->hid_default_pipe_req--;
1595 1594 ASSERT(hidp->hid_default_pipe_req >= 0);
1596 1595 mutex_exit(&hidp->hid_mutex);
1597 1596
1598 1597 qenable(wq);
1599 1598 usb_free_ctrl_req(req);
1600 1599 hid_pm_idle_component(hidp);
1601 1600 }
1602 1601
1603 1602
1604 1603 /*
1605 1604 * event handling:
1606 1605 *
1607 1606 * hid_reconnect_event_callback:
1608 1607 * the device was disconnected but this instance not detached, probably
1609 1608 * because the device was busy
1610 1609 *
1611 1610 * If the same device, continue with restoring state
1612 1611 */
1613 1612 static int
1614 1613 hid_restore_state_event_callback(dev_info_t *dip)
1615 1614 {
1616 1615 hid_state_t *hidp = (hid_state_t *)ddi_get_soft_state(hid_statep,
1617 1616 ddi_get_instance(dip));
1618 1617
1619 1618 ASSERT(hidp != NULL);
1620 1619
1621 1620 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1622 1621 "hid_restore_state_event_callback: dip=0x%p", (void *)dip);
1623 1622
1624 1623 hid_restore_device_state(dip, hidp);
1625 1624
1626 1625 return (USB_SUCCESS);
1627 1626 }
1628 1627
1629 1628
1630 1629 /*
1631 1630 * hid_cpr_suspend
1632 1631 * Fail suspend if we can't finish outstanding i/o activity.
1633 1632 */
1634 1633 static int
1635 1634 hid_cpr_suspend(hid_state_t *hidp)
1636 1635 {
1637 1636 int rval, prev_state;
1638 1637 int retval = USB_FAILURE;
1639 1638
1640 1639 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1641 1640 "hid_cpr_suspend: dip=0x%p", (void *)hidp->hid_dip);
1642 1641
1643 1642 mutex_enter(&hidp->hid_mutex);
1644 1643 switch (hidp->hid_dev_state) {
1645 1644 case USB_DEV_ONLINE:
1646 1645 case USB_DEV_PWRED_DOWN:
1647 1646 prev_state = hidp->hid_dev_state;
1648 1647 hidp->hid_dev_state = USB_DEV_SUSPENDED;
1649 1648 mutex_exit(&hidp->hid_mutex);
1650 1649
1651 1650 /* drain all request outstanding on the default control pipe */
1652 1651 rval = usb_pipe_drain_reqs(hidp->hid_dip,
1653 1652 hidp->hid_default_pipe, hid_default_pipe_drain_timeout,
1654 1653 USB_FLAGS_SLEEP, NULL, 0);
1655 1654
1656 1655 /* fail checkpoint if we haven't finished the job yet */
1657 1656 mutex_enter(&hidp->hid_mutex);
1658 1657 if ((rval != USB_SUCCESS) || (hidp->hid_default_pipe_req > 0)) {
1659 1658 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1660 1659 "hid_cpr_suspend: "
1661 1660 "device busy - can't checkpoint");
1662 1661
1663 1662 /* fall back to previous state */
1664 1663 hidp->hid_dev_state = prev_state;
1665 1664 } else {
1666 1665 retval = USB_SUCCESS;
1667 1666 hid_save_device_state(hidp);
1668 1667 }
1669 1668
1670 1669 break;
1671 1670 case USB_DEV_DISCONNECTED:
1672 1671 hidp->hid_dev_state = USB_DEV_SUSPENDED;
1673 1672 hid_save_device_state(hidp);
1674 1673 retval = USB_SUCCESS;
1675 1674 break;
1676 1675 case USB_DEV_SUSPENDED:
1677 1676 default:
1678 1677 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1679 1678 "hid_cpr_suspend: Illegal dev state: %d",
1680 1679 hidp->hid_dev_state);
1681 1680
1682 1681 break;
1683 1682 }
1684 1683 mutex_exit(&hidp->hid_mutex);
1685 1684
1686 1685 return (retval);
1687 1686 }
1688 1687
1689 1688
1690 1689 static void
1691 1690 hid_cpr_resume(hid_state_t *hidp)
1692 1691 {
1693 1692 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1694 1693 "hid_cpr_resume: dip=0x%p", (void *)hidp->hid_dip);
1695 1694
1696 1695 hid_restore_device_state(hidp->hid_dip, hidp);
1697 1696 }
1698 1697
1699 1698
1700 1699 /*
1701 1700 * hid_disconnect_event_callback:
1702 1701 * The device has been disconnected. We either wait for
1703 1702 * detach or a reconnect event. Close all pipes and timeouts.
1704 1703 */
1705 1704 static int
1706 1705 hid_disconnect_event_callback(dev_info_t *dip)
1707 1706 {
1708 1707 hid_state_t *hidp;
1709 1708 mblk_t *mp;
1710 1709
1711 1710 hidp = (hid_state_t *)ddi_get_soft_state(hid_statep,
1712 1711 ddi_get_instance(dip));
1713 1712 ASSERT(hidp != NULL);
1714 1713
1715 1714 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1716 1715 "hid_disconnect_event_callback: dip=0x%p", (void *)dip);
1717 1716
1718 1717 mutex_enter(&hidp->hid_mutex);
1719 1718 switch (hidp->hid_dev_state) {
1720 1719 case USB_DEV_ONLINE:
1721 1720 case USB_DEV_PWRED_DOWN:
1722 1721 hidp->hid_dev_state = USB_DEV_DISCONNECTED;
1723 1722 if (HID_IS_OPEN(hidp)) {
1724 1723
1725 1724 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1726 1725 "busy device has been disconnected");
1727 1726 }
1728 1727 hid_save_device_state(hidp);
1729 1728
1730 1729 /*
1731 1730 * Notify applications about device removal, this only
1732 1731 * applies to an external (aka. physical) open. For an
1733 1732 * internal open, consconfig_dacf closes the queue.
1734 1733 */
1735 1734 if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
1736 1735 queue_t *q = hidp->hid_external_rq;
1737 1736 mutex_exit(&hidp->hid_mutex);
1738 1737 mp = allocb(sizeof (uchar_t), BPRI_HI);
1739 1738 if (mp != NULL) {
1740 1739 mp->b_datap->db_type = M_ERROR;
1741 1740 mp->b_rptr = mp->b_datap->db_base;
1742 1741 mp->b_wptr = mp->b_rptr + sizeof (char);
1743 1742 *mp->b_rptr = ENODEV;
1744 1743 putnext(q, mp);
1745 1744 }
1746 1745 mutex_enter(&hidp->hid_mutex);
1747 1746 }
1748 1747
1749 1748 break;
1750 1749 case USB_DEV_SUSPENDED:
1751 1750 /* we remain suspended */
1752 1751
1753 1752 break;
1754 1753 default:
1755 1754 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1756 1755 "hid_disconnect_event_callback: Illegal dev state: %d",
1757 1756 hidp->hid_dev_state);
1758 1757
1759 1758 break;
1760 1759 }
1761 1760 mutex_exit(&hidp->hid_mutex);
1762 1761
1763 1762 return (USB_SUCCESS);
1764 1763 }
1765 1764
1766 1765
1767 1766 /*
1768 1767 * hid_power_change_callback:
1769 1768 * Async callback function to notify pm_raise_power completion
1770 1769 * after hid_power entry point is called.
1771 1770 */
1772 1771 static void
1773 1772 hid_power_change_callback(void *arg, int rval)
1774 1773 {
1775 1774 hid_state_t *hidp;
1776 1775 queue_t *wq;
1777 1776
1778 1777 hidp = (hid_state_t *)arg;
1779 1778
1780 1779 USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
1781 1780 "hid_power_change_callback - rval: %d", rval);
1782 1781
1783 1782 mutex_enter(&hidp->hid_mutex);
1784 1783 hidp->hid_pm->hid_raise_power = B_FALSE;
1785 1784
1786 1785 if (hidp->hid_dev_state == USB_DEV_ONLINE) {
1787 1786 wq = WR(hidp->hid_inuse_rq);
1788 1787 mutex_exit(&hidp->hid_mutex);
1789 1788
1790 1789 qenable(wq);
1791 1790
1792 1791 } else {
1793 1792 mutex_exit(&hidp->hid_mutex);
1794 1793 }
1795 1794 }
1796 1795
1797 1796
1798 1797 /*
1799 1798 * hid_parse_hid_descr:
1800 1799 * Parse the hid descriptor, check after interface and after
1801 1800 * endpoint descriptor
1802 1801 */
1803 1802 static size_t
1804 1803 hid_parse_hid_descr(
1805 1804 usb_hid_descr_t *ret_descr,
1806 1805 size_t ret_buf_len,
1807 1806 usb_alt_if_data_t *altif_data,
1808 1807 usb_ep_data_t *ep_data)
1809 1808 {
1810 1809 usb_cvs_data_t *cvs;
1811 1810 int which_cvs;
1812 1811
1813 1812 for (which_cvs = 0; which_cvs < altif_data->altif_n_cvs; which_cvs++) {
1814 1813 cvs = &altif_data->altif_cvs[which_cvs];
1815 1814 if (cvs->cvs_buf == NULL) {
1816 1815 continue;
1817 1816 }
1818 1817 if (cvs->cvs_buf[1] == USB_DESCR_TYPE_HID) {
1819 1818 return (usb_parse_data("ccscccs",
1820 1819 cvs->cvs_buf, cvs->cvs_buf_len,
1821 1820 (void *)ret_descr,
1822 1821 (size_t)ret_buf_len));
1823 1822 }
1824 1823 }
1825 1824
1826 1825 /* now try after endpoint */
1827 1826 for (which_cvs = 0; which_cvs < ep_data->ep_n_cvs; which_cvs++) {
1828 1827 cvs = &ep_data->ep_cvs[which_cvs];
1829 1828 if (cvs->cvs_buf == NULL) {
1830 1829 continue;
1831 1830 }
1832 1831 if (cvs->cvs_buf[1] == USB_DESCR_TYPE_HID) {
1833 1832 return (usb_parse_data("ccscccs",
1834 1833 cvs->cvs_buf, cvs->cvs_buf_len,
1835 1834 (void *)ret_descr,
1836 1835 (size_t)ret_buf_len));
1837 1836 }
1838 1837 }
1839 1838
1840 1839 return (USB_PARSE_ERROR);
1841 1840 }
1842 1841
1843 1842
1844 1843 /*
1845 1844 * hid_parse_hid_descr_failure:
1846 1845 * If parsing of hid descriptor failed and the device is
1847 1846 * a keyboard or mouse, use predefined length and packet size.
1848 1847 */
1849 1848 static int
1850 1849 hid_parse_hid_descr_failure(hid_state_t *hidp)
1851 1850 {
1852 1851 /*
1853 1852 * Parsing hid descriptor failed, probably because the
1854 1853 * device did not return a valid hid descriptor. Check to
1855 1854 * see if this is a keyboard or mouse. If so, use the
1856 1855 * predefined hid descriptor length and packet size.
1857 1856 * Otherwise, detach and return failure.
1858 1857 */
1859 1858 USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
1860 1859 "Parsing of hid descriptor failed");
1861 1860
1862 1861 if (hidp->hid_if_descr.bInterfaceProtocol == KEYBOARD_PROTOCOL) {
1863 1862 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
1864 1863 "Set hid descriptor length to predefined "
1865 1864 "USB_KB_HID_DESCR_LENGTH for keyboard.");
1866 1865
1867 1866 /* device is a keyboard */
1868 1867 hidp->hid_hid_descr.wReportDescriptorLength =
1869 1868 USB_KB_HID_DESCR_LENGTH;
1870 1869
1871 1870 hidp->hid_packet_size = USBKPSZ;
1872 1871
1873 1872 } else if (hidp->hid_if_descr.bInterfaceProtocol ==
1874 1873 MOUSE_PROTOCOL) {
1875 1874 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
1876 1875 "Set hid descriptor length to predefined "
1877 1876 "USB_MS_HID_DESCR_LENGTH for mouse.");
1878 1877
1879 1878 /* device is a mouse */
1880 1879 hidp->hid_hid_descr.wReportDescriptorLength =
1881 1880 USB_MS_HID_DESCR_LENGTH;
1882 1881
1883 1882 hidp->hid_packet_size = USBMSSZ;
1884 1883 } else {
1885 1884
1886 1885 return (USB_FAILURE);
1887 1886 }
1888 1887
1889 1888 return (USB_SUCCESS);
1890 1889 }
1891 1890
1892 1891
1893 1892 /*
1894 1893 * hid_handle_report_descriptor:
1895 1894 * Get the report descriptor, call hidparser routine to parse
1896 1895 * it and query the hidparser tree to get the packet size
1897 1896 */
1898 1897 static int
1899 1898 hid_handle_report_descriptor(hid_state_t *hidp,
1900 1899 int interface)
1901 1900 {
1902 1901 usb_cr_t completion_reason;
1903 1902 usb_cb_flags_t cb_flags;
1904 1903 mblk_t *data = NULL;
1905 1904 hidparser_packet_info_t hpack;
1906 1905 int i;
1907 1906 usb_ctrl_setup_t setup = {
1908 1907 USB_DEV_REQ_DEV_TO_HOST | /* bmRequestType */
1909 1908 USB_DEV_REQ_RCPT_IF,
1910 1909 USB_REQ_GET_DESCR, /* bRequest */
1911 1910 USB_CLASS_DESCR_TYPE_REPORT, /* wValue */
1912 1911 0, /* wIndex: interface, fill in later */
1913 1912 0, /* wLength, fill in later */
1914 1913 0 /* attributes */
1915 1914 };
1916 1915
1917 1916 /*
1918 1917 * Parsing hid desciptor was successful earlier.
1919 1918 * Get Report Descriptor
1920 1919 */
1921 1920 setup.wIndex = (uint16_t)interface;
1922 1921 setup.wLength = hidp->hid_hid_descr.wReportDescriptorLength;
1923 1922 if (usb_pipe_ctrl_xfer_wait(hidp->hid_default_pipe,
1924 1923 &setup,
1925 1924 &data, /* data */
1926 1925 &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
1927 1926
1928 1927 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
1929 1928 "Failed to receive the Report Descriptor");
1930 1929 freemsg(data);
1931 1930
1932 1931 return (USB_FAILURE);
1933 1932
1934 1933 } else {
1935 1934 int n = hidp->hid_hid_descr.wReportDescriptorLength;
1936 1935
1937 1936 ASSERT(data);
1938 1937
1939 1938 /* Print the report descriptor */
1940 1939 for (i = 0; i < n; i++) {
1941 1940 USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
1942 1941 "Index = %d\tvalue =0x%x", i,
1943 1942 (int)(data->b_rptr[i]));
1944 1943 }
1945 1944
1946 1945 /* Get Report Descriptor was successful */
1947 1946 if (hidparser_parse_report_descriptor(
1948 1947 data->b_rptr,
1949 1948 hidp->hid_hid_descr.wReportDescriptorLength,
1950 1949 &hidp->hid_hid_descr,
1951 1950 &hidp->hid_report_descr) == HIDPARSER_SUCCESS) {
1952 1951
1953 1952 /* find max intr-in xfer length */
1954 1953 hidparser_find_max_packet_size_from_report_descriptor(
1955 1954 hidp->hid_report_descr, &hpack);
1956 1955 /* round up to the nearest byte */
1957 1956 hidp->hid_packet_size = (hpack.max_packet_size + 7) / 8;
1958 1957
1959 1958 /* if report id is used, add more more byte for it */
1960 1959 if (hpack.report_id != HID_REPORT_ID_UNDEFINED) {
1961 1960 hidp->hid_packet_size++;
1962 1961 }
1963 1962 } else {
1964 1963 USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
1965 1964 "Invalid Report Descriptor");
1966 1965 freemsg(data);
1967 1966
1968 1967 return (USB_FAILURE);
1969 1968 }
1970 1969
1971 1970 freemsg(data);
1972 1971
1973 1972 return (USB_SUCCESS);
1974 1973 }
1975 1974 }
1976 1975
1977 1976
1978 1977 /*
1979 1978 * hid_set_idle:
1980 1979 * Make a clas specific request to SET_IDLE.
1981 1980 * In this case send no reports if state has not changed.
1982 1981 * See HID 7.2.4.
1983 1982 */
1984 1983 /*ARGSUSED*/
1985 1984 static void
1986 1985 hid_set_idle(hid_state_t *hidp)
1987 1986 {
1988 1987 usb_cr_t completion_reason;
1989 1988 usb_cb_flags_t cb_flags;
1990 1989 usb_ctrl_setup_t setup = {
1991 1990 USB_DEV_REQ_HOST_TO_DEV | /* bmRequestType */
1992 1991 USB_DEV_REQ_TYPE_CLASS |
1993 1992 USB_DEV_REQ_RCPT_IF,
1994 1993 SET_IDLE, /* bRequest */
1995 1994 DURATION, /* wValue */
1996 1995 0, /* wIndex: interface, fill in later */
1997 1996 0, /* wLength */
1998 1997 0 /* attributes */
1999 1998 };
2000 1999
2001 2000 USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2002 2001 "hid_set_idle: Begin");
2003 2002
2004 2003 setup.wIndex = hidp->hid_if_descr.bInterfaceNumber;
2005 2004 if (usb_pipe_ctrl_xfer_wait(
2006 2005 hidp->hid_default_pipe,
2007 2006 &setup,
2008 2007 NULL, /* no data to send. */
2009 2008 &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
2010 2009
2011 2010 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
2012 2011 "Failed while trying to set idle,"
2013 2012 "cr = %d, cb_flags = 0x%x\n",
2014 2013 completion_reason, cb_flags);
2015 2014 }
2016 2015 USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2017 2016 "hid_set_idle: End");
2018 2017 }
2019 2018
2020 2019
2021 2020 /*
2022 2021 * hid_set_protocol:
2023 2022 * Initialize the device to set the preferred protocol
2024 2023 */
2025 2024 /*ARGSUSED*/
2026 2025 static void
2027 2026 hid_set_protocol(hid_state_t *hidp, int protocol)
2028 2027 {
2029 2028 usb_cr_t completion_reason;
2030 2029 usb_cb_flags_t cb_flags;
2031 2030 usb_ctrl_setup_t setup;
2032 2031
2033 2032 USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2034 2033 "hid_set_protocol(%d): Begin", protocol);
2035 2034
2036 2035 /* initialize the setup request */
2037 2036 setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
2038 2037 USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
2039 2038 setup.bRequest = SET_PROTOCOL;
2040 2039 setup.wValue = (uint16_t)protocol;
2041 2040 setup.wIndex = hidp->hid_if_descr.bInterfaceNumber;
2042 2041 setup.wLength = 0;
2043 2042 setup.attrs = 0;
2044 2043 if (usb_pipe_ctrl_xfer_wait(
2045 2044 hidp->hid_default_pipe, /* bmRequestType */
2046 2045 &setup,
2047 2046 NULL, /* no data to send */
2048 2047 &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
2049 2048 /*
2050 2049 * Some devices fail to follow the specification
2051 2050 * and instead of STALLing, they continously
2052 2051 * NAK the SET_IDLE command. We need to reset
2053 2052 * the pipe then, so that ohci doesn't panic.
2054 2053 */
2055 2054 USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
2056 2055 "Failed while trying to set protocol:%d,"
2057 2056 "cr = %d cb_flags = 0x%x\n",
2058 2057 completion_reason, cb_flags, protocol);
2059 2058 }
2060 2059
2061 2060 USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2062 2061 "hid_set_protocol: End");
2063 2062 }
2064 2063
2065 2064
2066 2065 /*
2067 2066 * hid_detach_cleanup:
2068 2067 * called by attach and detach for cleanup.
2069 2068 */
2070 2069 static void
2071 2070 hid_detach_cleanup(dev_info_t *dip, hid_state_t *hidp)
2072 2071 {
2073 2072 int flags = hidp->hid_attach_flags;
2074 2073 int rval;
2075 2074 hid_power_t *hidpm;
2076 2075
2077 2076 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
2078 2077 "hid_detach_cleanup: Begin");
2079 2078
2080 2079 if ((hidp->hid_attach_flags & HID_LOCK_INIT) == 0) {
2081 2080
2082 2081 goto done;
2083 2082 }
2084 2083
2085 2084 /*
2086 2085 * Disable the event callbacks first, after this point, event
2087 2086 * callbacks will never get called. Note we shouldn't hold
2088 2087 * mutex while unregistering events because there may be a
2089 2088 * competing event callback thread. Event callbacks are done
2090 2089 * with ndi mutex held and this can cause a potential deadlock.
2091 2090 */
2092 2091 usb_unregister_event_cbs(dip, &hid_events);
2093 2092
2094 2093 mutex_enter(&hidp->hid_mutex);
2095 2094
2096 2095 hidpm = hidp->hid_pm;
2097 2096
2098 2097 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
2099 2098 "hid_detach_cleanup: hidpm=0x%p", (void *)hidpm);
2100 2099
2101 2100 if (hidpm && (hidp->hid_dev_state != USB_DEV_DISCONNECTED)) {
2102 2101
2103 2102 mutex_exit(&hidp->hid_mutex);
2104 2103 hid_pm_busy_component(hidp);
2105 2104 if (hid_is_pm_enabled(dip) == USB_SUCCESS) {
2106 2105
2107 2106 if (hidpm->hid_wakeup_enabled) {
2108 2107
2109 2108 /* First bring the device to full power */
2110 2109 (void) pm_raise_power(dip, 0,
2111 2110 USB_DEV_OS_FULL_PWR);
2112 2111
2113 2112 /* Disable remote wakeup */
2114 2113 rval = usb_handle_remote_wakeup(dip,
2115 2114 USB_REMOTE_WAKEUP_DISABLE);
2116 2115
2117 2116 if (rval != DDI_SUCCESS) {
2118 2117 USB_DPRINTF_L2(PRINT_MASK_ALL,
2119 2118 hidp->hid_log_handle,
2120 2119 "hid_detach_cleanup: "
2121 2120 "disble remote wakeup failed, "
2122 2121 "rval= %d", rval);
2123 2122 }
2124 2123 }
2125 2124
2126 2125 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
2127 2126 }
2128 2127 hid_pm_idle_component(hidp);
2129 2128 mutex_enter(&hidp->hid_mutex);
2130 2129 }
2131 2130
2132 2131 if (hidpm) {
2133 2132 freemsg(hidpm->hid_pm_pwrup);
2134 2133 kmem_free(hidpm, sizeof (hid_power_t));
2135 2134 hidp->hid_pm = NULL;
2136 2135 }
2137 2136
2138 2137 mutex_exit(&hidp->hid_mutex);
2139 2138
2140 2139 if (hidp->hid_report_descr != NULL) {
2141 2140 (void) hidparser_free_report_descriptor_handle(
2142 2141 hidp->hid_report_descr);
2143 2142 }
2144 2143
2145 2144 if (flags & HID_MINOR_NODES) {
2146 2145 ddi_remove_minor_node(dip, NULL);
2147 2146 }
2148 2147
2149 2148 mutex_destroy(&hidp->hid_mutex);
2150 2149
2151 2150 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
2152 2151 "hid_detach_cleanup: End");
2153 2152
2154 2153 done:
2155 2154 usb_client_detach(dip, hidp->hid_dev_data);
2156 2155 usb_free_log_hdl(hidp->hid_log_handle);
2157 2156 ddi_soft_state_free(hid_statep, hidp->hid_instance);
2158 2157
2159 2158 ddi_prop_remove_all(dip);
2160 2159 }
2161 2160
2162 2161
2163 2162 /*
2164 2163 * hid_start_intr_polling:
2165 2164 * Allocate an interrupt request structure, initialize,
2166 2165 * and start interrupt transfers.
2167 2166 */
2168 2167 static int
2169 2168 hid_start_intr_polling(hid_state_t *hidp)
2170 2169 {
2171 2170 usb_intr_req_t *req;
2172 2171 int rval = USB_SUCCESS;
2173 2172
2174 2173 USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
2175 2174 "hid_start_intr_polling: "
2176 2175 "dev_state=%s internal_str_flag=%d external_str_flag=%d ph=0x%p",
2177 2176 usb_str_dev_state(hidp->hid_dev_state), hidp->hid_internal_flag,
2178 2177 hidp->hid_external_flag, (void *)hidp->hid_interrupt_pipe);
2179 2178
2180 2179 if (HID_IS_OPEN(hidp) && (hidp->hid_interrupt_pipe != NULL)) {
2181 2180 /*
2182 2181 * initialize interrupt pipe request structure
2183 2182 */
2184 2183 req = usb_alloc_intr_req(hidp->hid_dip, 0, USB_FLAGS_SLEEP);
2185 2184 req->intr_client_private = (usb_opaque_t)hidp;
2186 2185 req->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
2187 2186 USB_ATTRS_AUTOCLEARING;
2188 2187 req->intr_len = hidp->hid_packet_size;
2189 2188 req->intr_cb = hid_interrupt_pipe_callback;
2190 2189 req->intr_exc_cb = hid_interrupt_pipe_exception_callback;
2191 2190
2192 2191 /*
2193 2192 * Start polling on the interrupt pipe.
2194 2193 */
2195 2194 mutex_exit(&hidp->hid_mutex);
2196 2195
2197 2196 if ((rval = usb_pipe_intr_xfer(hidp->hid_interrupt_pipe, req,
2198 2197 USB_FLAGS_SLEEP)) != USB_SUCCESS) {
2199 2198 USB_DPRINTF_L2(PRINT_MASK_PM, hidp->hid_log_handle,
2200 2199 "hid_start_intr_polling failed: rval = %d",
2201 2200 rval);
2202 2201 usb_free_intr_req(req);
2203 2202 }
2204 2203
2205 2204 mutex_enter(&hidp->hid_mutex);
2206 2205 }
2207 2206
2208 2207 USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
2209 2208 "hid_start_intr_polling: done, rval = %d", rval);
2210 2209
2211 2210 return (rval);
2212 2211 }
2213 2212
2214 2213
2215 2214 /*
2216 2215 * hid_close_intr_pipe:
2217 2216 * close the interrupt pipe after draining all callbacks
2218 2217 */
2219 2218 static void
2220 2219 hid_close_intr_pipe(hid_state_t *hidp)
2221 2220 {
2222 2221 USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
2223 2222 "hid_close_intr_pipe: Begin");
2224 2223
2225 2224 if (hidp->hid_interrupt_pipe) {
2226 2225 /*
2227 2226 * Close the interrupt pipe
2228 2227 */
2229 2228 mutex_exit(&hidp->hid_mutex);
2230 2229 usb_pipe_close(hidp->hid_dip, hidp->hid_interrupt_pipe,
2231 2230 USB_FLAGS_SLEEP, NULL, NULL);
2232 2231 mutex_enter(&hidp->hid_mutex);
2233 2232 hidp->hid_interrupt_pipe = NULL;
2234 2233 }
2235 2234 USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
2236 2235 "hid_close_intr_pipe: End");
2237 2236 }
2238 2237
2239 2238
2240 2239 /*
2241 2240 * hid_mctl_receive:
2242 2241 * Handle M_CTL messages from upper stream. If
2243 2242 * we don't understand the command, free message.
2244 2243 */
2245 2244 static int
2246 2245 hid_mctl_receive(register queue_t *q, register mblk_t *mp)
2247 2246 {
2248 2247 hid_state_t *hidp = (hid_state_t *)q->q_ptr;
2249 2248 struct iocblk *iocp;
2250 2249 int error = HID_FAILURE;
2251 2250 uchar_t request_type;
2252 2251 hid_req_t *hid_req_data = NULL;
2253 2252 hid_polled_input_callback_t hid_polled_input;
2254 2253 hid_vid_pid_t hid_vid_pid;
2255 2254
2256 2255 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
2257 2256 "hid_mctl_receive");
2258 2257
2259 2258 iocp = (struct iocblk *)mp->b_rptr;
2260 2259
2261 2260 switch (iocp->ioc_cmd) {
2262 2261 case HID_SET_REPORT:
2263 2262 /* FALLTHRU */
2264 2263 case HID_SET_IDLE:
2265 2264 /* FALLTHRU */
2266 2265 case HID_SET_PROTOCOL:
2267 2266 request_type = USB_DEV_REQ_HOST_TO_DEV |
2268 2267 USB_DEV_REQ_RCPT_IF | USB_DEV_REQ_TYPE_CLASS;
2269 2268
2270 2269 break;
2271 2270 case HID_GET_REPORT:
2272 2271 /* FALLTHRU */
2273 2272 case HID_GET_IDLE:
2274 2273 /* FALLTHRU */
2275 2274 case HID_GET_PROTOCOL:
2276 2275 request_type = USB_DEV_REQ_DEV_TO_HOST |
2277 2276 USB_DEV_REQ_RCPT_IF | USB_DEV_REQ_TYPE_CLASS;
2278 2277
2279 2278 break;
2280 2279 case HID_GET_PARSER_HANDLE:
2281 2280 if (canputnext(RD(q))) {
2282 2281 freemsg(mp->b_cont);
2283 2282 mp->b_cont = hid_data2mblk(
2284 2283 (uchar_t *)&hidp->hid_report_descr,
2285 2284 sizeof (hidp->hid_report_descr));
2286 2285 if (mp->b_cont == NULL) {
2287 2286 /*
2288 2287 * can't allocate mblk, indicate
2289 2288 * that nothing is returned
2290 2289 */
2291 2290 iocp->ioc_count = 0;
2292 2291 } else {
2293 2292 iocp->ioc_count =
2294 2293 sizeof (hidp->hid_report_descr);
2295 2294 }
2296 2295 qreply(q, mp);
2297 2296
2298 2297 return (HID_SUCCESS);
2299 2298 } else {
2300 2299
2301 2300 /* retry */
2302 2301 return (HID_ENQUEUE);
2303 2302 }
2304 2303 case HID_GET_VID_PID:
2305 2304 if (canputnext(RD(q))) {
2306 2305 freemsg(mp->b_cont);
2307 2306
2308 2307 hid_vid_pid.VendorId =
2309 2308 hidp->hid_dev_descr->idVendor;
2310 2309 hid_vid_pid.ProductId =
2311 2310 hidp->hid_dev_descr->idProduct;
2312 2311
2313 2312 mp->b_cont = hid_data2mblk(
2314 2313 (uchar_t *)&hid_vid_pid, sizeof (hid_vid_pid_t));
2315 2314 if (mp->b_cont == NULL) {
2316 2315 /*
2317 2316 * can't allocate mblk, indicate that nothing
2318 2317 * is being returned.
2319 2318 */
2320 2319 iocp->ioc_count = 0;
2321 2320 } else {
2322 2321 iocp->ioc_count =
2323 2322 sizeof (hid_vid_pid_t);
2324 2323 }
2325 2324 qreply(q, mp);
2326 2325
2327 2326 return (HID_SUCCESS);
2328 2327 } else {
2329 2328
2330 2329 /* retry */
2331 2330 return (HID_ENQUEUE);
2332 2331 }
2333 2332 case HID_OPEN_POLLED_INPUT:
2334 2333 if (canputnext(RD(q))) {
2335 2334 freemsg(mp->b_cont);
2336 2335
2337 2336 /* Initialize the structure */
2338 2337 hid_polled_input.hid_polled_version =
2339 2338 HID_POLLED_INPUT_V0;
2340 2339 hid_polled_input.hid_polled_read = hid_polled_read;
2341 2340 hid_polled_input.hid_polled_input_enter =
2342 2341 hid_polled_input_enter;
2343 2342 hid_polled_input.hid_polled_input_exit =
2344 2343 hid_polled_input_exit;
2345 2344 hid_polled_input.hid_polled_input_handle =
2346 2345 (hid_polled_handle_t)hidp;
2347 2346
2348 2347 mp->b_cont = hid_data2mblk(
2349 2348 (uchar_t *)&hid_polled_input,
2350 2349 sizeof (hid_polled_input_callback_t));
2351 2350 if (mp->b_cont == NULL) {
2352 2351 /*
2353 2352 * can't allocate mblk, indicate that nothing
2354 2353 * is being returned.
2355 2354 */
2356 2355 iocp->ioc_count = 0;
2357 2356 } else {
2358 2357 /* Call down into USBA */
2359 2358 (void) hid_polled_input_init(hidp);
2360 2359
2361 2360 iocp->ioc_count =
2362 2361 sizeof (hid_polled_input_callback_t);
2363 2362 }
2364 2363 qreply(q, mp);
2365 2364
2366 2365 return (HID_SUCCESS);
2367 2366 } else {
2368 2367
2369 2368 /* retry */
2370 2369 return (HID_ENQUEUE);
2371 2370 }
2372 2371 case HID_CLOSE_POLLED_INPUT:
2373 2372 /* Call down into USBA */
2374 2373 (void) hid_polled_input_fini(hidp);
2375 2374
2376 2375 iocp->ioc_count = 0;
2377 2376 qreply(q, mp);
2378 2377
2379 2378 return (HID_SUCCESS);
2380 2379 default:
2381 2380 hid_qreply_merror(q, mp, EINVAL);
2382 2381
2383 2382 return (HID_FAILURE);
2384 2383 }
2385 2384
2386 2385 /*
2387 2386 * These (device executable) commands require a hid_req_t.
2388 2387 * Make sure one is present
2389 2388 */
2390 2389 if (mp->b_cont == NULL) {
2391 2390 hid_qreply_merror(q, mp, EINVAL);
2392 2391
2393 2392 return (error);
2394 2393 } else {
2395 2394 hid_req_data = (hid_req_t *)mp->b_cont->b_rptr;
2396 2395 if ((iocp->ioc_cmd == HID_SET_REPORT) &&
2397 2396 (hid_req_data->hid_req_wLength == 0)) {
2398 2397 hid_qreply_merror(q, mp, EINVAL);
2399 2398
2400 2399 return (error);
2401 2400 }
2402 2401 }
2403 2402
2404 2403 /*
2405 2404 * Check is version no. is correct. This
2406 2405 * is coming from the user
2407 2406 */
2408 2407 if (hid_req_data->hid_req_version_no != HID_VERSION_V_0) {
2409 2408 hid_qreply_merror(q, mp, EINVAL);
2410 2409
2411 2410 return (error);
2412 2411 }
2413 2412
2414 2413 mutex_enter(&hidp->hid_mutex);
2415 2414 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
2416 2415 "hid_mctl_receive: dev_state=%s",
2417 2416 usb_str_dev_state(hidp->hid_dev_state));
2418 2417
2419 2418 switch (hidp->hid_dev_state) {
2420 2419 case USB_DEV_PWRED_DOWN:
2421 2420 /*
2422 2421 * get the device full powered. We get a callback
2423 2422 * which enables the WQ and kicks off IO
2424 2423 */
2425 2424 hidp->hid_dev_state = USB_DEV_HID_POWER_CHANGE;
2426 2425 mutex_exit(&hidp->hid_mutex);
2427 2426 if (usb_req_raise_power(hidp->hid_dip, 0,
2428 2427 USB_DEV_OS_FULL_PWR, hid_power_change_callback,
2429 2428 hidp, 0) != USB_SUCCESS) {
2430 2429 /* we retry raising power in wsrv */
2431 2430 mutex_enter(&hidp->hid_mutex);
2432 2431 hidp->hid_dev_state = USB_DEV_PWRED_DOWN;
2433 2432 mutex_exit(&hidp->hid_mutex);
2434 2433 }
2435 2434 error = HID_ENQUEUE;
2436 2435
2437 2436 break;
2438 2437 case USB_DEV_HID_POWER_CHANGE:
2439 2438 mutex_exit(&hidp->hid_mutex);
2440 2439 error = HID_ENQUEUE;
2441 2440
2442 2441 break;
2443 2442 case USB_DEV_ONLINE:
2444 2443 if (HID_STREAMS_FLAG(q, hidp) != HID_STREAMS_DISMANTLING) {
2445 2444 /* Send a message down */
2446 2445 mutex_exit(&hidp->hid_mutex);
2447 2446 error = hid_mctl_execute_cmd(q, request_type,
2448 2447 hid_req_data, mp);
2449 2448 if (error == HID_FAILURE) {
2450 2449 hid_qreply_merror(q, mp, EIO);
2451 2450 }
2452 2451 } else {
2453 2452 mutex_exit(&hidp->hid_mutex);
2454 2453 hid_qreply_merror(q, mp, EIO);
2455 2454 }
2456 2455
2457 2456 break;
2458 2457 default:
2459 2458 mutex_exit(&hidp->hid_mutex);
2460 2459 hid_qreply_merror(q, mp, EIO);
2461 2460
2462 2461 break;
2463 2462 }
2464 2463
2465 2464 return (error);
2466 2465 }
2467 2466
2468 2467
2469 2468 /*
2470 2469 * hid_mctl_execute_cmd:
2471 2470 * Send the command to the device.
2472 2471 */
2473 2472 static int
2474 2473 hid_mctl_execute_cmd(queue_t *q, int request_type, hid_req_t *hid_req_data,
2475 2474 mblk_t *mp)
2476 2475 {
2477 2476 int request_index;
2478 2477 struct iocblk *iocp;
2479 2478 hid_default_pipe_arg_t *def_pipe_arg;
2480 2479 hid_state_t *hidp = (hid_state_t *)q->q_ptr;
2481 2480
2482 2481 iocp = (struct iocblk *)mp->b_rptr;
2483 2482 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
2484 2483 "hid_mctl_execute_cmd: iocp=0x%p", (void *)iocp);
2485 2484
2486 2485 request_index = hidp->hid_if_descr.bInterfaceNumber;
2487 2486
2488 2487 /*
2489 2488 * Set up the argument to be passed back to hid
2490 2489 * when the asynchronous control callback is
2491 2490 * executed.
2492 2491 */
2493 2492 def_pipe_arg = kmem_zalloc(sizeof (hid_default_pipe_arg_t), 0);
2494 2493
2495 2494 if (def_pipe_arg == NULL) {
2496 2495
2497 2496 return (HID_FAILURE);
2498 2497 }
2499 2498
2500 2499 def_pipe_arg->hid_default_pipe_arg_queue = q;
2501 2500 def_pipe_arg->hid_default_pipe_arg_mctlmsg.ioc_cmd = iocp->ioc_cmd;
2502 2501 def_pipe_arg->hid_default_pipe_arg_mctlmsg.ioc_count = 0;
2503 2502 def_pipe_arg->hid_default_pipe_arg_mblk = mp;
2504 2503
2505 2504 /*
2506 2505 * Send the command down to USBA through default
2507 2506 * pipe.
2508 2507 */
2509 2508 if (hid_send_async_ctrl_request(def_pipe_arg, hid_req_data,
2510 2509 request_type, iocp->ioc_cmd, request_index) != USB_SUCCESS) {
2511 2510
2512 2511 kmem_free(def_pipe_arg, sizeof (hid_default_pipe_arg_t));
2513 2512
2514 2513 return (HID_FAILURE);
2515 2514 }
2516 2515
2517 2516 return (HID_INPROGRESS);
2518 2517 }
2519 2518
2520 2519
2521 2520 /*
2522 2521 * hid_send_async_ctrl_request:
2523 2522 * Send an asynchronous control request to USBA. Since hid is a STREAMS
2524 2523 * driver, it is not allowed to wait in its entry points except for the
2525 2524 * open and close entry points. Therefore, hid must use the asynchronous
2526 2525 * USBA calls.
2527 2526 */
2528 2527 static int
2529 2528 hid_send_async_ctrl_request(hid_default_pipe_arg_t *hid_default_pipe_arg,
2530 2529 hid_req_t *hid_request,
2531 2530 uchar_t request_type, int request_request,
2532 2531 ushort_t request_index)
2533 2532 {
2534 2533 queue_t *q = hid_default_pipe_arg->hid_default_pipe_arg_queue;
2535 2534 hid_state_t *hidp = (hid_state_t *)q->q_ptr;
2536 2535 usb_ctrl_req_t *ctrl_req;
2537 2536 int rval;
2538 2537 size_t length = 0;
2539 2538
2540 2539 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
2541 2540 "hid_send_async_ctrl_request: "
2542 2541 "rq_type=%d rq_rq=%d index=%d",
2543 2542 request_type, request_request, request_index);
2544 2543
2545 2544 mutex_enter(&hidp->hid_mutex);
2546 2545 hidp->hid_default_pipe_req++;
2547 2546 mutex_exit(&hidp->hid_mutex);
2548 2547
2549 2548 /*
2550 2549 * Note that ctrl_req->ctrl_data should be allocated by usba
2551 2550 * only for IN requests. OUT request(e.g SET_REPORT) can have a
2552 2551 * non-zero wLength value but ctrl_data would be allocated by
2553 2552 * client for them.
2554 2553 */
2555 2554 if (hid_request->hid_req_wLength >= MAX_REPORT_DATA) {
2556 2555 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
2557 2556 "hid_req_wLength is exceeded");
2558 2557 return (USB_FAILURE);
2559 2558 }
2560 2559 if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_DEV_TO_HOST) {
2561 2560 length = hid_request->hid_req_wLength;
2562 2561 }
2563 2562
2564 2563 if ((ctrl_req = usb_alloc_ctrl_req(hidp->hid_dip, length, 0)) == NULL) {
2565 2564 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
2566 2565 "unable to alloc ctrl req. async trans failed");
2567 2566 mutex_enter(&hidp->hid_mutex);
2568 2567 hidp->hid_default_pipe_req--;
2569 2568 ASSERT(hidp->hid_default_pipe_req >= 0);
2570 2569 mutex_exit(&hidp->hid_mutex);
2571 2570
2572 2571 return (USB_FAILURE);
2573 2572 }
2574 2573
2575 2574 if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_HOST_TO_DEV) {
2576 2575 ASSERT((length == 0) && (ctrl_req->ctrl_data == NULL));
2577 2576 }
2578 2577
2579 2578 ctrl_req->ctrl_bmRequestType = request_type;
2580 2579 ctrl_req->ctrl_bRequest = (uint8_t)request_request;
2581 2580 ctrl_req->ctrl_wValue = hid_request->hid_req_wValue;
2582 2581 ctrl_req->ctrl_wIndex = request_index;
2583 2582 ctrl_req->ctrl_wLength = hid_request->hid_req_wLength;
2584 2583 /* host to device: create a msg from hid_req_data */
2585 2584 if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_HOST_TO_DEV) {
2586 2585 mblk_t *pblk = allocb(hid_request->hid_req_wLength, BPRI_HI);
2587 2586 if (pblk == NULL) {
2588 2587 usb_free_ctrl_req(ctrl_req);
2589 2588 return (USB_FAILURE);
2590 2589 }
2591 2590 bcopy(hid_request->hid_req_data, pblk->b_wptr,
2592 2591 hid_request->hid_req_wLength);
2593 2592 pblk->b_wptr += hid_request->hid_req_wLength;
2594 2593 ctrl_req->ctrl_data = pblk;
2595 2594 }
2596 2595 ctrl_req->ctrl_attributes = USB_ATTRS_AUTOCLEARING;
2597 2596 ctrl_req->ctrl_client_private = (usb_opaque_t)hid_default_pipe_arg;
2598 2597 ctrl_req->ctrl_cb = hid_default_pipe_callback;
2599 2598 ctrl_req->ctrl_exc_cb = hid_default_pipe_exception_callback;
2600 2599
2601 2600 if ((rval = usb_pipe_ctrl_xfer(hidp->hid_default_pipe,
2602 2601 ctrl_req, 0)) != USB_SUCCESS) {
2603 2602 mutex_enter(&hidp->hid_mutex);
2604 2603 hidp->hid_default_pipe_req--;
2605 2604 ASSERT(hidp->hid_default_pipe_req >= 0);
2606 2605 mutex_exit(&hidp->hid_mutex);
2607 2606
2608 2607 usb_free_ctrl_req(ctrl_req);
2609 2608 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
2610 2609 "usb_pipe_ctrl_xfer() failed. rval = %d", rval);
2611 2610
2612 2611 return (USB_FAILURE);
2613 2612 }
2614 2613
2615 2614 return (USB_SUCCESS);
2616 2615 }
2617 2616
2618 2617 /*
2619 2618 * hid_create_pm_components:
2620 2619 * Create the pm components required for power management.
2621 2620 * For keyboard/mouse, the components is created only if the device
2622 2621 * supports a remote wakeup.
2623 2622 * For other hid devices they are created unconditionally.
2624 2623 */
2625 2624 static void
2626 2625 hid_create_pm_components(dev_info_t *dip, hid_state_t *hidp)
2627 2626 {
2628 2627 hid_power_t *hidpm;
2629 2628 uint_t pwr_states;
2630 2629
2631 2630 USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
2632 2631 "hid_create_pm_components: Begin");
2633 2632
2634 2633 /* Allocate the state structure */
2635 2634 hidpm = kmem_zalloc(sizeof (hid_power_t), KM_SLEEP);
2636 2635 hidp->hid_pm = hidpm;
2637 2636 hidpm->hid_state = hidp;
2638 2637 hidpm->hid_raise_power = B_FALSE;
2639 2638 hidpm->hid_pm_capabilities = 0;
2640 2639 hidpm->hid_current_power = USB_DEV_OS_FULL_PWR;
2641 2640
2642 2641 switch (hidp->hid_if_descr.bInterfaceProtocol) {
2643 2642 case KEYBOARD_PROTOCOL:
2644 2643 case MOUSE_PROTOCOL:
2645 2644 hidpm->hid_pm_strategy = HID_PM_ACTIVITY;
2646 2645 if ((hid_is_pm_enabled(dip) == USB_SUCCESS) &&
2647 2646 (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
2648 2647 USB_SUCCESS)) {
2649 2648
2650 2649 USB_DPRINTF_L3(PRINT_MASK_PM, hidp->hid_log_handle,
2651 2650 "hid_create_pm_components: Remote Wakeup Enabled");
2652 2651
2653 2652 if (usb_create_pm_components(dip, &pwr_states) ==
2654 2653 USB_SUCCESS) {
2655 2654 hidpm->hid_wakeup_enabled = 1;
2656 2655 hidpm->hid_pwr_states = (uint8_t)pwr_states;
2657 2656 }
2658 2657 }
2659 2658
2660 2659 break;
2661 2660 default:
2662 2661 hidpm->hid_pm_strategy = HID_PM_OPEN_CLOSE;
2663 2662 if ((hid_is_pm_enabled(dip) == USB_SUCCESS) &&
2664 2663 (usb_create_pm_components(dip, &pwr_states) ==
2665 2664 USB_SUCCESS)) {
2666 2665 hidpm->hid_wakeup_enabled = 0;
2667 2666 hidpm->hid_pwr_states = (uint8_t)pwr_states;
2668 2667 }
2669 2668
2670 2669 break;
2671 2670 }
2672 2671
2673 2672 USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
2674 2673 "hid_create_pm_components: END");
2675 2674 }
2676 2675
2677 2676
2678 2677 /*
2679 2678 * hid_is_pm_enabled
2680 2679 * Check if the device is pm enabled. Always enable
2681 2680 * pm on the new SUN mouse
2682 2681 */
2683 2682 static int
2684 2683 hid_is_pm_enabled(dev_info_t *dip)
2685 2684 {
2686 2685 hid_state_t *hidp = ddi_get_soft_state(hid_statep,
2687 2686 ddi_get_instance(dip));
2688 2687
2689 2688 if (strcmp(ddi_node_name(dip), "mouse") == 0) {
2690 2689 /* check for overrides first */
2691 2690 if (hid_pm_mouse ||
2692 2691 (ddi_prop_exists(DDI_DEV_T_ANY, dip,
2693 2692 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2694 2693 "hid-mouse-pm-enable") == 1)) {
2695 2694
2696 2695 return (USB_SUCCESS);
2697 2696 }
2698 2697
2699 2698 /*
2700 2699 * Always enable PM for 1.05 or greater SUN mouse
2701 2700 * hidp->hid_dev_descr won't be NULL.
2702 2701 */
2703 2702 if ((hidp->hid_dev_descr->idVendor ==
2704 2703 HID_SUN_MOUSE_VENDOR_ID) &&
2705 2704 (hidp->hid_dev_descr->idProduct ==
2706 2705 HID_SUN_MOUSE_PROD_ID) &&
2707 2706 (hidp->hid_dev_descr->bcdDevice >=
2708 2707 HID_SUN_MOUSE_BCDDEVICE)) {
2709 2708
2710 2709 return (USB_SUCCESS);
2711 2710 }
2712 2711 } else {
2713 2712
2714 2713 return (USB_SUCCESS);
2715 2714 }
2716 2715
2717 2716 return (USB_FAILURE);
2718 2717 }
2719 2718
2720 2719
2721 2720 /*
2722 2721 * hid_save_device_state
2723 2722 * Save the current device/driver state.
2724 2723 */
2725 2724 static void
2726 2725 hid_save_device_state(hid_state_t *hidp)
2727 2726 {
2728 2727 struct iocblk *mctlmsg;
2729 2728 mblk_t *mp;
2730 2729 queue_t *q;
2731 2730
2732 2731 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
2733 2732 "hid_save_device_state");
2734 2733
2735 2734 if (!(HID_IS_OPEN(hidp)))
2736 2735 return;
2737 2736
2738 2737 if (hidp->hid_internal_flag == HID_STREAMS_OPEN) {
2739 2738 /*
2740 2739 * Send MCTLs up indicating that the device
2741 2740 * will loose its state
2742 2741 */
2743 2742 q = hidp->hid_internal_rq;
2744 2743
2745 2744 mutex_exit(&hidp->hid_mutex);
2746 2745 if (canputnext(q)) {
2747 2746 mp = allocb(sizeof (struct iocblk), BPRI_HI);
2748 2747 if (mp != NULL) {
2749 2748 mp->b_datap->db_type = M_CTL;
2750 2749 mctlmsg = (struct iocblk *)
2751 2750 mp->b_datap->db_base;
2752 2751 mctlmsg->ioc_cmd = HID_DISCONNECT_EVENT;
2753 2752 mctlmsg->ioc_count = 0;
2754 2753 putnext(q, mp);
2755 2754 }
2756 2755 }
2757 2756 mutex_enter(&hidp->hid_mutex);
2758 2757 }
2759 2758
2760 2759 if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
2761 2760 /*
2762 2761 * Send MCTLs up indicating that the device
2763 2762 * will loose its state
2764 2763 */
2765 2764 q = hidp->hid_external_rq;
2766 2765
2767 2766 mutex_exit(&hidp->hid_mutex);
2768 2767 if (canputnext(q)) {
2769 2768 mp = allocb(sizeof (struct iocblk), BPRI_HI);
2770 2769 if (mp != NULL) {
2771 2770 mp->b_datap->db_type = M_CTL;
2772 2771 mctlmsg = (struct iocblk *)
2773 2772 mp->b_datap->db_base;
2774 2773 mctlmsg->ioc_cmd = HID_DISCONNECT_EVENT;
2775 2774 mctlmsg->ioc_count = 0;
2776 2775 putnext(q, mp);
2777 2776 }
2778 2777 }
2779 2778 mutex_enter(&hidp->hid_mutex);
2780 2779 }
2781 2780
2782 2781 mutex_exit(&hidp->hid_mutex);
2783 2782 /* stop polling on the intr pipe */
2784 2783 usb_pipe_stop_intr_polling(hidp->hid_interrupt_pipe, USB_FLAGS_SLEEP);
2785 2784 mutex_enter(&hidp->hid_mutex);
2786 2785 }
2787 2786
2788 2787
2789 2788 /*
2790 2789 * hid_restore_device_state:
2791 2790 * Set original configuration of the device.
2792 2791 * Reopen intr pipe.
2793 2792 * Enable wrq - this starts new transactions on the control pipe.
2794 2793 */
2795 2794 static void
2796 2795 hid_restore_device_state(dev_info_t *dip, hid_state_t *hidp)
2797 2796 {
2798 2797 int rval;
2799 2798 hid_power_t *hidpm;
2800 2799 struct iocblk *mctlmsg;
2801 2800 mblk_t *mp;
2802 2801 queue_t *q;
2803 2802
2804 2803 hid_pm_busy_component(hidp);
2805 2804 mutex_enter(&hidp->hid_mutex);
2806 2805
2807 2806 USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2808 2807 "hid_restore_device_state: %s",
2809 2808 usb_str_dev_state(hidp->hid_dev_state));
2810 2809
2811 2810 hidpm = hidp->hid_pm;
2812 2811 mutex_exit(&hidp->hid_mutex);
2813 2812
2814 2813 /* First bring the device to full power */
2815 2814 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2816 2815
2817 2816 mutex_enter(&hidp->hid_mutex);
2818 2817 if (hidp->hid_dev_state == USB_DEV_ONLINE) {
2819 2818 /*
2820 2819 * We failed the checkpoint, there is no need to restore
2821 2820 * the device state
2822 2821 */
2823 2822 mutex_exit(&hidp->hid_mutex);
2824 2823 hid_pm_idle_component(hidp);
2825 2824
2826 2825 return;
2827 2826 }
2828 2827 mutex_exit(&hidp->hid_mutex);
2829 2828
2830 2829
2831 2830 /* Check if we are talking to the same device */
2832 2831 if (usb_check_same_device(dip, hidp->hid_log_handle, USB_LOG_L2,
2833 2832 PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
2834 2833
2835 2834 /* change the device state from suspended to disconnected */
2836 2835 mutex_enter(&hidp->hid_mutex);
2837 2836 hidp->hid_dev_state = USB_DEV_DISCONNECTED;
2838 2837 mutex_exit(&hidp->hid_mutex);
2839 2838 hid_pm_idle_component(hidp);
2840 2839 goto nodev;
2841 2840 }
2842 2841
2843 2842 hid_set_idle(hidp);
2844 2843 hid_set_protocol(hidp, SET_REPORT_PROTOCOL);
2845 2844
2846 2845 mutex_enter(&hidp->hid_mutex);
2847 2846 /* if the device had remote wakeup earlier, enable it again */
2848 2847 if (hidpm->hid_wakeup_enabled) {
2849 2848 mutex_exit(&hidp->hid_mutex);
2850 2849
2851 2850 if ((rval = usb_handle_remote_wakeup(hidp->hid_dip,
2852 2851 USB_REMOTE_WAKEUP_ENABLE)) != USB_SUCCESS) {
2853 2852 USB_DPRINTF_L2(PRINT_MASK_ATTA,
2854 2853 hidp->hid_log_handle,
2855 2854 "usb_handle_remote_wakeup failed (%d)", rval);
2856 2855 }
2857 2856
2858 2857 mutex_enter(&hidp->hid_mutex);
2859 2858 }
2860 2859
2861 2860 /*
2862 2861 * restart polling on the interrupt pipe only if the device
2863 2862 * was previously operational (open)
2864 2863 */
2865 2864 if (HID_IS_OPEN(hidp)) {
2866 2865 if ((rval = hid_start_intr_polling(hidp)) != USB_SUCCESS) {
2867 2866 USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
2868 2867 "hid_restore_device_state:"
2869 2868 "unable to restart intr pipe poll"
2870 2869 " rval = %d ", rval);
2871 2870 /*
2872 2871 * change the device state from
2873 2872 * suspended to disconnected
2874 2873 */
2875 2874 hidp->hid_dev_state = USB_DEV_DISCONNECTED;
2876 2875 mutex_exit(&hidp->hid_mutex);
2877 2876 hid_pm_idle_component(hidp);
2878 2877 goto nodev;
2879 2878 }
2880 2879
2881 2880 if (hidp->hid_dev_state == USB_DEV_DISCONNECTED) {
2882 2881 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
2883 2882 "device is being re-connected");
2884 2883 }
2885 2884
2886 2885 /* set the device state ONLINE */
2887 2886 hidp->hid_dev_state = USB_DEV_ONLINE;
2888 2887
2889 2888 /* inform upstream modules that the device is back */
2890 2889 if (hidp->hid_internal_flag == HID_STREAMS_OPEN) {
2891 2890 q = hidp->hid_internal_rq;
2892 2891
2893 2892 mutex_exit(&hidp->hid_mutex);
2894 2893 if (canputnext(q)) {
2895 2894 mp = allocb(sizeof (struct iocblk), BPRI_HI);
2896 2895 if (mp != NULL) {
2897 2896 mp->b_datap->db_type = M_CTL;
2898 2897 mctlmsg = (struct iocblk *)
2899 2898 mp->b_datap->db_base;
2900 2899 mctlmsg->ioc_cmd = HID_CONNECT_EVENT;
2901 2900 mctlmsg->ioc_count = 0;
2902 2901 putnext(q, mp);
2903 2902 }
2904 2903 }
2905 2904 /* enable write side q */
2906 2905 qenable(WR(q));
2907 2906 mutex_enter(&hidp->hid_mutex);
2908 2907 }
2909 2908
2910 2909 if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
2911 2910 q = hidp->hid_external_rq;
2912 2911
2913 2912 mutex_exit(&hidp->hid_mutex);
2914 2913 if (canputnext(q)) {
2915 2914 mp = allocb(sizeof (struct iocblk), BPRI_HI);
2916 2915 if (mp != NULL) {
2917 2916 mp->b_datap->db_type = M_CTL;
2918 2917 mctlmsg = (struct iocblk *)
2919 2918 mp->b_datap->db_base;
2920 2919 mctlmsg->ioc_cmd = HID_CONNECT_EVENT;
2921 2920 mctlmsg->ioc_count = 0;
2922 2921 putnext(q, mp);
2923 2922 }
2924 2923 }
2925 2924 /* enable write side q */
2926 2925 qenable(WR(q));
2927 2926 mutex_enter(&hidp->hid_mutex);
2928 2927 }
2929 2928 } else {
2930 2929 /* set the device state ONLINE */
2931 2930 hidp->hid_dev_state = USB_DEV_ONLINE;
2932 2931 }
2933 2932
2934 2933 mutex_exit(&hidp->hid_mutex);
2935 2934 hid_pm_idle_component(hidp);
2936 2935 return;
2937 2936
2938 2937 nodev:
2939 2938 /*
2940 2939 * Notify applications about device removal. This only
2941 2940 * applies to an external (aka. physical) open. Not sure how to
2942 2941 * notify consconfig to close the internal minor node.
2943 2942 */
2944 2943 mutex_enter(&hidp->hid_mutex);
2945 2944
2946 2945 if ((q = hidp->hid_external_rq) == NULL) {
2947 2946 mutex_exit(&hidp->hid_mutex);
2948 2947 return;
2949 2948 }
2950 2949
2951 2950 mutex_exit(&hidp->hid_mutex);
2952 2951 mp = allocb(sizeof (uchar_t), BPRI_HI);
2953 2952 if (mp != NULL) {
2954 2953 mp->b_datap->db_type = M_ERROR;
2955 2954 mp->b_rptr = mp->b_datap->db_base;
2956 2955 mp->b_wptr = mp->b_rptr + sizeof (char);
2957 2956 *mp->b_rptr = ENODEV;
2958 2957 putnext(q, mp);
2959 2958 }
2960 2959 }
2961 2960
2962 2961
2963 2962 /*
2964 2963 * hid_qreply_merror:
2965 2964 * Pass an error message up.
2966 2965 */
2967 2966 static void
2968 2967 hid_qreply_merror(queue_t *q, mblk_t *mp, uchar_t errval)
2969 2968 {
2970 2969 mp->b_datap->db_type = M_ERROR;
2971 2970 if (mp->b_cont) {
2972 2971 freemsg(mp->b_cont);
2973 2972 mp->b_cont = NULL;
2974 2973 }
2975 2974 mp->b_rptr = mp->b_datap->db_base;
2976 2975 mp->b_wptr = mp->b_rptr + sizeof (char);
2977 2976 *mp->b_rptr = errval;
2978 2977
2979 2978 qreply(q, mp);
2980 2979 }
2981 2980
2982 2981
2983 2982 /*
2984 2983 * hid_data2mblk:
2985 2984 * Form an mblk from the given data
2986 2985 */
2987 2986 static mblk_t *
2988 2987 hid_data2mblk(uchar_t *buf, int len)
2989 2988 {
2990 2989 mblk_t *mp = NULL;
2991 2990
2992 2991 if (len >= 0) {
2993 2992 mp = allocb(len, BPRI_HI);
2994 2993 if (mp) {
2995 2994 bcopy(buf, mp->b_datap->db_base, len);
2996 2995 mp->b_wptr += len;
2997 2996 }
2998 2997 }
2999 2998
3000 2999 return (mp);
3001 3000 }
3002 3001
3003 3002
3004 3003 /*
3005 3004 * hid_flush :
3006 3005 * Flush data already sent upstreams to client module.
3007 3006 */
3008 3007 static void
3009 3008 hid_flush(queue_t *q)
3010 3009 {
3011 3010 /*
3012 3011 * Flush pending data already sent upstream
3013 3012 */
3014 3013 if ((q != NULL) && (q->q_next != NULL)) {
3015 3014 (void) putnextctl1(q, M_FLUSH, FLUSHR);
3016 3015 }
3017 3016 }
3018 3017
3019 3018
3020 3019 static void
3021 3020 hid_pm_busy_component(hid_state_t *hid_statep)
3022 3021 {
3023 3022 ASSERT(!mutex_owned(&hid_statep->hid_mutex));
3024 3023
3025 3024 if (hid_statep->hid_pm != NULL) {
3026 3025 mutex_enter(&hid_statep->hid_mutex);
3027 3026 hid_statep->hid_pm->hid_pm_busy++;
3028 3027
3029 3028 USB_DPRINTF_L4(PRINT_MASK_PM, hid_statep->hid_log_handle,
3030 3029 "hid_pm_busy_component: %d",
3031 3030 hid_statep->hid_pm->hid_pm_busy);
3032 3031
3033 3032 mutex_exit(&hid_statep->hid_mutex);
3034 3033 if (pm_busy_component(hid_statep->hid_dip, 0) != DDI_SUCCESS) {
3035 3034 mutex_enter(&hid_statep->hid_mutex);
3036 3035 hid_statep->hid_pm->hid_pm_busy--;
3037 3036
3038 3037 USB_DPRINTF_L2(PRINT_MASK_PM,
3039 3038 hid_statep->hid_log_handle,
3040 3039 "hid_pm_busy_component failed: %d",
3041 3040 hid_statep->hid_pm->hid_pm_busy);
3042 3041
3043 3042 mutex_exit(&hid_statep->hid_mutex);
3044 3043 }
3045 3044
3046 3045 }
3047 3046 }
3048 3047
3049 3048
3050 3049 static void
3051 3050 hid_pm_idle_component(hid_state_t *hid_statep)
3052 3051 {
3053 3052 ASSERT(!mutex_owned(&hid_statep->hid_mutex));
3054 3053
3055 3054 if (hid_statep->hid_pm != NULL) {
3056 3055 if (pm_idle_component(hid_statep->hid_dip, 0) == DDI_SUCCESS) {
3057 3056 mutex_enter(&hid_statep->hid_mutex);
3058 3057 ASSERT(hid_statep->hid_pm->hid_pm_busy > 0);
3059 3058 hid_statep->hid_pm->hid_pm_busy--;
3060 3059
3061 3060 USB_DPRINTF_L4(PRINT_MASK_PM,
3062 3061 hid_statep->hid_log_handle,
3063 3062 "hid_pm_idle_component: %d",
3064 3063 hid_statep->hid_pm->hid_pm_busy);
3065 3064
3066 3065 mutex_exit(&hid_statep->hid_mutex);
3067 3066 }
3068 3067 }
3069 3068 }
3070 3069
3071 3070
3072 3071 /*
3073 3072 * hid_pwrlvl0:
3074 3073 * Functions to handle power transition for various levels
3075 3074 * These functions act as place holders to issue USB commands
3076 3075 * to the devices to change their power levels
3077 3076 */
3078 3077 static int
3079 3078 hid_pwrlvl0(hid_state_t *hidp)
3080 3079 {
3081 3080 hid_power_t *hidpm;
3082 3081 int rval;
3083 3082 struct iocblk *mctlmsg;
3084 3083 mblk_t *mp_lowpwr, *mp_fullpwr;
3085 3084 queue_t *q;
3086 3085
3087 3086 hidpm = hidp->hid_pm;
3088 3087
3089 3088 switch (hidp->hid_dev_state) {
3090 3089 case USB_DEV_ONLINE:
3091 3090 /* Deny the powerdown request if the device is busy */
3092 3091 if (hidpm->hid_pm_busy != 0) {
3093 3092
3094 3093 return (USB_FAILURE);
3095 3094 }
3096 3095
3097 3096 if (HID_IS_OPEN(hidp)) {
3098 3097 q = hidp->hid_inuse_rq;
3099 3098 mutex_exit(&hidp->hid_mutex);
3100 3099 if (canputnext(q)) {
3101 3100 /* try to preallocate mblks */
3102 3101 mp_lowpwr = allocb(
3103 3102 (int)sizeof (struct iocblk), BPRI_HI);
3104 3103 mp_fullpwr = allocb(
3105 3104 (int)sizeof (struct iocblk), BPRI_HI);
3106 3105 if ((mp_lowpwr != NULL) &&
3107 3106 (mp_fullpwr != NULL)) {
3108 3107 /* stop polling */
3109 3108 usb_pipe_stop_intr_polling(
3110 3109 hidp->hid_interrupt_pipe,
3111 3110 USB_FLAGS_SLEEP);
3112 3111
3113 3112 /*
3114 3113 * Send an MCTL up indicating that
3115 3114 * we are powering off
3116 3115 */
3117 3116 mp_lowpwr->b_datap->db_type = M_CTL;
3118 3117 mctlmsg = (struct iocblk *)
3119 3118 mp_lowpwr->b_datap->db_base;
3120 3119 mctlmsg->ioc_cmd = HID_POWER_OFF;
3121 3120 mctlmsg->ioc_count = 0;
3122 3121 putnext(q, mp_lowpwr);
3123 3122
3124 3123 /* save the full powr mblk */
3125 3124 mutex_enter(&hidp->hid_mutex);
3126 3125 hidpm->hid_pm_pwrup = mp_fullpwr;
3127 3126 } else {
3128 3127 /*
3129 3128 * Since we failed to allocate one
3130 3129 * or more mblks, we fail attempt
3131 3130 * to go into low power this time
3132 3131 */
3133 3132 freemsg(mp_lowpwr);
3134 3133 freemsg(mp_fullpwr);
3135 3134 mutex_enter(&hidp->hid_mutex);
3136 3135
3137 3136 return (USB_FAILURE);
3138 3137 }
3139 3138 } else {
3140 3139 /*
3141 3140 * Since we can't send an mblk up,
3142 3141 * we fail this attempt to go to low power
3143 3142 */
3144 3143 mutex_enter(&hidp->hid_mutex);
3145 3144
3146 3145 return (USB_FAILURE);
3147 3146 }
3148 3147 }
3149 3148
3150 3149 mutex_exit(&hidp->hid_mutex);
3151 3150 /* Issue USB D3 command to the device here */
3152 3151 rval = usb_set_device_pwrlvl3(hidp->hid_dip);
3153 3152 ASSERT(rval == USB_SUCCESS);
3154 3153
3155 3154 mutex_enter(&hidp->hid_mutex);
3156 3155 hidp->hid_dev_state = USB_DEV_PWRED_DOWN;
3157 3156 hidpm->hid_current_power = USB_DEV_OS_PWR_OFF;
3158 3157
3159 3158 /* FALLTHRU */
3160 3159 case USB_DEV_DISCONNECTED:
3161 3160 case USB_DEV_SUSPENDED:
3162 3161 case USB_DEV_PWRED_DOWN:
3163 3162 default:
3164 3163 break;
3165 3164 }
3166 3165
3167 3166 return (USB_SUCCESS);
3168 3167 }
3169 3168
3170 3169
3171 3170 /* ARGSUSED */
3172 3171 static int
3173 3172 hid_pwrlvl1(hid_state_t *hidp)
3174 3173 {
3175 3174 int rval;
3176 3175
3177 3176 /* Issue USB D2 command to the device here */
3178 3177 rval = usb_set_device_pwrlvl2(hidp->hid_dip);
3179 3178 ASSERT(rval == USB_SUCCESS);
3180 3179
3181 3180 return (USB_FAILURE);
3182 3181 }
3183 3182
3184 3183
3185 3184 /* ARGSUSED */
3186 3185 static int
3187 3186 hid_pwrlvl2(hid_state_t *hidp)
3188 3187 {
3189 3188 int rval;
3190 3189
3191 3190 rval = usb_set_device_pwrlvl1(hidp->hid_dip);
3192 3191 ASSERT(rval == USB_SUCCESS);
3193 3192
3194 3193 return (USB_FAILURE);
3195 3194 }
3196 3195
3197 3196
3198 3197 static int
3199 3198 hid_pwrlvl3(hid_state_t *hidp)
3200 3199 {
3201 3200 hid_power_t *hidpm;
3202 3201 int rval;
3203 3202 struct iocblk *mctlmsg;
3204 3203 mblk_t *mp;
3205 3204 queue_t *q;
3206 3205
3207 3206 hidpm = hidp->hid_pm;
3208 3207
3209 3208 switch (hidp->hid_dev_state) {
3210 3209 case USB_DEV_HID_POWER_CHANGE:
3211 3210 case USB_DEV_PWRED_DOWN:
3212 3211 /* Issue USB D0 command to the device here */
3213 3212 rval = usb_set_device_pwrlvl0(hidp->hid_dip);
3214 3213 ASSERT(rval == USB_SUCCESS);
3215 3214
3216 3215 if (HID_IS_OPEN(hidp)) {
3217 3216 /* restart polling on intr pipe */
3218 3217 rval = hid_start_intr_polling(hidp);
3219 3218 if (rval != USB_SUCCESS) {
3220 3219 USB_DPRINTF_L2(PRINT_MASK_EVENTS,
3221 3220 hidp->hid_log_handle,
3222 3221 "unable to restart intr polling rval = %d",
3223 3222 rval);
3224 3223
3225 3224 return (USB_FAILURE);
3226 3225 }
3227 3226
3228 3227 /* Send an MCTL up indicating device in full power */
3229 3228 q = hidp->hid_inuse_rq;
3230 3229 mp = hidpm->hid_pm_pwrup;
3231 3230 hidpm->hid_pm_pwrup = NULL;
3232 3231 mutex_exit(&hidp->hid_mutex);
3233 3232 if (canputnext(q)) {
3234 3233 mp->b_datap->db_type = M_CTL;
3235 3234 mctlmsg = (struct iocblk *)
3236 3235 mp->b_datap->db_base;
3237 3236 mctlmsg->ioc_cmd = HID_FULL_POWER;
3238 3237 mctlmsg->ioc_count = 0;
3239 3238 putnext(q, mp);
3240 3239 } else {
3241 3240 freemsg(mp);
3242 3241 }
3243 3242 mutex_enter(&hidp->hid_mutex);
3244 3243 }
3245 3244
3246 3245 hidp->hid_dev_state = USB_DEV_ONLINE;
3247 3246 hidpm->hid_current_power = USB_DEV_OS_FULL_PWR;
3248 3247
3249 3248 /* FALLTHRU */
3250 3249 case USB_DEV_DISCONNECTED:
3251 3250 case USB_DEV_SUSPENDED:
3252 3251 case USB_DEV_ONLINE:
3253 3252
3254 3253 return (USB_SUCCESS);
3255 3254 default:
3256 3255 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
3257 3256 "hid_pwrlvl3: Improper State");
3258 3257
3259 3258 return (USB_FAILURE);
3260 3259 }
3261 3260 }
3262 3261
3263 3262
3264 3263 /*
3265 3264 * hid_polled_input_init :
3266 3265 * This routine calls down to the lower layers to initialize any state
3267 3266 * information. This routine initializes the lower layers for input.
3268 3267 */
3269 3268 static int
3270 3269 hid_polled_input_init(hid_state_t *hidp)
3271 3270 {
3272 3271 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
3273 3272 "hid_polled_input_init");
3274 3273
3275 3274 /*
3276 3275 * Call the lower layers to intialize any state information
3277 3276 * that they will need to provide the polled characters.
3278 3277 */
3279 3278 if (usb_console_input_init(hidp->hid_dip, hidp->hid_interrupt_pipe,
3280 3279 &hidp->hid_polled_raw_buf,
3281 3280 &hidp->hid_polled_console_info) != USB_SUCCESS) {
3282 3281 /*
3283 3282 * If for some reason the lower layers cannot initialized, then
3284 3283 * bail.
3285 3284 */
3286 3285 (void) hid_polled_input_fini(hidp);
3287 3286
3288 3287 return (USB_FAILURE);
3289 3288 }
3290 3289
3291 3290 return (USB_SUCCESS);
3292 3291 }
3293 3292
3294 3293
3295 3294 /*
3296 3295 * hid_polled_input_fini:
3297 3296 * This routine is called when we are done using this device as an input
3298 3297 * device.
3299 3298 */
3300 3299 static int
3301 3300 hid_polled_input_fini(hid_state_t *hidp)
3302 3301 {
3303 3302 USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
3304 3303 "hid_polled_input_fini");
3305 3304
3306 3305 /*
3307 3306 * Call the lower layers to free any state information
3308 3307 * only if polled input has been initialised.
3309 3308 */
3310 3309 if ((hidp->hid_polled_console_info) &&
3311 3310 (usb_console_input_fini(hidp->hid_polled_console_info) !=
3312 3311 USB_SUCCESS)) {
3313 3312
3314 3313 return (USB_FAILURE);
3315 3314 }
3316 3315 hidp->hid_polled_console_info = NULL;
3317 3316
3318 3317 return (USB_SUCCESS);
3319 3318 }
3320 3319
3321 3320
3322 3321 /*
3323 3322 * hid_polled_input_enter:
3324 3323 * This is the routine that is called in polled mode to save the USB
3325 3324 * state information before using the USB keyboard as an input device.
3326 3325 * This routine, and all of the routines that it calls, are responsible
3327 3326 * for saving any state information so that it can be restored when
3328 3327 * polling mode is over.
3329 3328 */
3330 3329 static int
3331 3330 /* ARGSUSED */
3332 3331 hid_polled_input_enter(hid_polled_handle_t hid_polled_inputp)
3333 3332 {
3334 3333 hid_state_t *hidp = (hid_state_t *)hid_polled_inputp;
3335 3334
3336 3335 /*
3337 3336 * Call the lower layers to tell them to save any state information.
3338 3337 */
3339 3338 (void) usb_console_input_enter(hidp->hid_polled_console_info);
3340 3339
3341 3340 return (USB_SUCCESS);
3342 3341 }
3343 3342
3344 3343
3345 3344 /*
3346 3345 * hid_polled_read :
3347 3346 * This is the routine that is called in polled mode when it wants to read
3348 3347 * a character. We will call to the lower layers to see if there is any
3349 3348 * input data available. If there is USB scancodes available, we will
3350 3349 * give them back.
3351 3350 */
3352 3351 static int
3353 3352 hid_polled_read(hid_polled_handle_t hid_polled_input, uchar_t **buffer)
3354 3353 {
3355 3354 hid_state_t *hidp = (hid_state_t *)hid_polled_input;
3356 3355 uint_t num_bytes;
3357 3356
3358 3357 /*
3359 3358 * Call the lower layers to get the character from the controller.
3360 3359 * The lower layers will return the number of characters that
3361 3360 * were put in the raw buffer. The address of the raw buffer
3362 3361 * was passed down to the lower layers during hid_polled_init.
3363 3362 */
3364 3363 if (usb_console_read(hidp->hid_polled_console_info,
3365 3364 &num_bytes) != USB_SUCCESS) {
3366 3365
3367 3366 return (0);
3368 3367 }
3369 3368
3370 3369 _NOTE(NO_COMPETING_THREADS_NOW);
3371 3370
3372 3371 *buffer = hidp->hid_polled_raw_buf;
3373 3372
3374 3373 _NOTE(COMPETING_THREADS_NOW);
3375 3374
3376 3375 /*
3377 3376 * Return the number of characters that were copied into the
3378 3377 * polled buffer.
3379 3378 */
3380 3379 return (num_bytes);
3381 3380 }
3382 3381
3383 3382
3384 3383 /*
3385 3384 * hid_polled_input_exit :
3386 3385 * This is the routine that is called in polled mode when it is giving up
3387 3386 * control of the USB keyboard. This routine, and the lower layer routines
3388 3387 * that it calls, are responsible for restoring the controller state to the
3389 3388 * state it was in before polled mode.
3390 3389 */
3391 3390 static int
3392 3391 hid_polled_input_exit(hid_polled_handle_t hid_polled_inputp)
3393 3392 {
3394 3393 hid_state_t *hidp = (hid_state_t *)hid_polled_inputp;
3395 3394
3396 3395 /*
3397 3396 * Call the lower layers to restore any state information.
3398 3397 */
3399 3398 (void) usb_console_input_exit(hidp->hid_polled_console_info);
3400 3399
3401 3400 return (0);
3402 3401 }
↓ open down ↓ |
3150 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX