17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5f3b88bd2Scg * Common Development and Distribution License (the "License").
6f3b88bd2Scg * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21f3b88bd2Scg
227c478bd9Sstevel@tonic-gate /*
23f67c0a39Sfei feng - Sun Microsystems - Beijing China * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24*cfe80fe3SAlex Wilson * Copyright 2017 Joyent, Inc.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate * Human Interface Device driver (HID)
307c478bd9Sstevel@tonic-gate *
317c478bd9Sstevel@tonic-gate * The HID driver is a software driver which acts as a class
327c478bd9Sstevel@tonic-gate * driver for USB human input devices like keyboard, mouse,
337c478bd9Sstevel@tonic-gate * joystick etc and provides the class-specific interfaces
347c478bd9Sstevel@tonic-gate * between these client driver modules and the Universal Serial
357c478bd9Sstevel@tonic-gate * Bus Driver(USBA).
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * NOTE: This driver is not DDI compliant in that it uses undocumented
387c478bd9Sstevel@tonic-gate * functions for logging (USB_DPRINTF_L*, usb_alloc_log_hdl, usb_free_log_hdl).
397c478bd9Sstevel@tonic-gate *
407c478bd9Sstevel@tonic-gate * Undocumented functions may go away in a future Solaris OS release.
417c478bd9Sstevel@tonic-gate *
427c478bd9Sstevel@tonic-gate * Please see the DDK for sample code of these functions, and for the usbskel
437c478bd9Sstevel@tonic-gate * skeleton template driver which contains scaled-down versions of these
447c478bd9Sstevel@tonic-gate * functions written in a DDI-compliant way.
457c478bd9Sstevel@tonic-gate */
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate #define USBDRV_MAJOR_VER 2
487c478bd9Sstevel@tonic-gate #define USBDRV_MINOR_VER 0
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
517c478bd9Sstevel@tonic-gate #include <sys/usb/usba/genconsole.h>
527c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hid.h>
537c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hid_polled.h>
547c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hidparser.h>
557c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hidvar.h>
567c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hidminor.h>
577c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hid_parser_driver.h>
587c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
59f3b88bd2Scg #include <sys/sunddi.h>
60ddee57faSrui zang - Sun Microsystems - Beijing China #include <sys/stream.h>
61ddee57faSrui zang - Sun Microsystems - Beijing China #include <sys/strsun.h>
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
64f3b88bd2Scg
657c478bd9Sstevel@tonic-gate /* Debugging support */
664610e4a0Sfrits uint_t hid_errmask = (uint_t)PRINT_MASK_ALL;
674610e4a0Sfrits uint_t hid_errlevel = USB_LOG_L4;
684610e4a0Sfrits uint_t hid_instance_debug = (uint_t)-1;
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate /* tunables */
717c478bd9Sstevel@tonic-gate int hid_default_pipe_drain_timeout = HID_DEFAULT_PIPE_DRAIN_TIMEOUT;
726f6c7d2bSVincent Wang int hid_pm_mouse = 1; /* enable remote_wakeup for USB mouse/keyboard */
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate /* soft state structures */
757c478bd9Sstevel@tonic-gate #define HID_INITIAL_SOFT_SPACE 4
767c478bd9Sstevel@tonic-gate static void *hid_statep;
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /* Callbacks */
797c478bd9Sstevel@tonic-gate static void hid_interrupt_pipe_callback(usb_pipe_handle_t,
807c478bd9Sstevel@tonic-gate usb_intr_req_t *);
817c478bd9Sstevel@tonic-gate static void hid_default_pipe_callback(usb_pipe_handle_t, usb_ctrl_req_t *);
827c478bd9Sstevel@tonic-gate static void hid_interrupt_pipe_exception_callback(usb_pipe_handle_t,
837c478bd9Sstevel@tonic-gate usb_intr_req_t *);
847c478bd9Sstevel@tonic-gate static void hid_default_pipe_exception_callback(usb_pipe_handle_t,
857c478bd9Sstevel@tonic-gate usb_ctrl_req_t *);
867c478bd9Sstevel@tonic-gate static int hid_restore_state_event_callback(dev_info_t *);
877c478bd9Sstevel@tonic-gate static int hid_disconnect_event_callback(dev_info_t *);
887c478bd9Sstevel@tonic-gate static int hid_cpr_suspend(hid_state_t *hidp);
897c478bd9Sstevel@tonic-gate static void hid_cpr_resume(hid_state_t *hidp);
907c478bd9Sstevel@tonic-gate static void hid_power_change_callback(void *arg, int rval);
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate /* Supporting routines */
937c478bd9Sstevel@tonic-gate static size_t hid_parse_hid_descr(usb_hid_descr_t *, size_t,
947c478bd9Sstevel@tonic-gate usb_alt_if_data_t *, usb_ep_data_t *);
957c478bd9Sstevel@tonic-gate static int hid_parse_hid_descr_failure(hid_state_t *);
967c478bd9Sstevel@tonic-gate static int hid_handle_report_descriptor(hid_state_t *, int);
977c478bd9Sstevel@tonic-gate static void hid_set_idle(hid_state_t *);
987c478bd9Sstevel@tonic-gate static void hid_set_protocol(hid_state_t *, int);
997c478bd9Sstevel@tonic-gate static void hid_detach_cleanup(dev_info_t *, hid_state_t *);
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate static int hid_start_intr_polling(hid_state_t *);
1027c478bd9Sstevel@tonic-gate static void hid_close_intr_pipe(hid_state_t *);
103ac9468f8Spengcheng chen - Sun Microsystems - Beijing China static int hid_mctl_execute_cmd(queue_t *, int, hid_req_t *,
104ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mblk_t *);
1057c478bd9Sstevel@tonic-gate static int hid_mctl_receive(queue_t *, mblk_t *);
106ac9468f8Spengcheng chen - Sun Microsystems - Beijing China static int hid_send_async_ctrl_request(hid_default_pipe_arg_t *, hid_req_t *,
107ac9468f8Spengcheng chen - Sun Microsystems - Beijing China uchar_t, int, ushort_t);
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate static void hid_create_pm_components(dev_info_t *, hid_state_t *);
1107c478bd9Sstevel@tonic-gate static int hid_is_pm_enabled(dev_info_t *);
1117c478bd9Sstevel@tonic-gate static void hid_restore_device_state(dev_info_t *, hid_state_t *);
1127c478bd9Sstevel@tonic-gate static void hid_save_device_state(hid_state_t *);
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate static void hid_qreply_merror(queue_t *, mblk_t *, uchar_t);
1157c478bd9Sstevel@tonic-gate static mblk_t *hid_data2mblk(uchar_t *, int);
1167c478bd9Sstevel@tonic-gate static void hid_flush(queue_t *);
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate static int hid_pwrlvl0(hid_state_t *);
1197c478bd9Sstevel@tonic-gate static int hid_pwrlvl1(hid_state_t *);
1207c478bd9Sstevel@tonic-gate static int hid_pwrlvl2(hid_state_t *);
1217c478bd9Sstevel@tonic-gate static int hid_pwrlvl3(hid_state_t *);
1227c478bd9Sstevel@tonic-gate static void hid_pm_busy_component(hid_state_t *);
1237c478bd9Sstevel@tonic-gate static void hid_pm_idle_component(hid_state_t *);
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate static int hid_polled_read(hid_polled_handle_t, uchar_t **);
1267c478bd9Sstevel@tonic-gate static int hid_polled_input_enter(hid_polled_handle_t);
1277c478bd9Sstevel@tonic-gate static int hid_polled_input_exit(hid_polled_handle_t);
1287c478bd9Sstevel@tonic-gate static int hid_polled_input_init(hid_state_t *);
1297c478bd9Sstevel@tonic-gate static int hid_polled_input_fini(hid_state_t *);
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate /* Streams entry points */
1327c478bd9Sstevel@tonic-gate static int hid_open(queue_t *, dev_t *, int, int, cred_t *);
1337c478bd9Sstevel@tonic-gate static int hid_close(queue_t *, int, cred_t *);
1347c478bd9Sstevel@tonic-gate static int hid_wput(queue_t *, mblk_t *);
1357c478bd9Sstevel@tonic-gate static int hid_wsrv(queue_t *);
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate /* dev_ops entry points */
1387c478bd9Sstevel@tonic-gate static int hid_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1397c478bd9Sstevel@tonic-gate static int hid_attach(dev_info_t *, ddi_attach_cmd_t);
1407c478bd9Sstevel@tonic-gate static int hid_detach(dev_info_t *, ddi_detach_cmd_t);
1417c478bd9Sstevel@tonic-gate static int hid_power(dev_info_t *, int, int);
142*cfe80fe3SAlex Wilson /* These are to enable ugen support: */
143*cfe80fe3SAlex Wilson static int hid_chropen(dev_t *, int, int, cred_t *);
144*cfe80fe3SAlex Wilson static int hid_chrclose(dev_t, int, int, cred_t *);
145*cfe80fe3SAlex Wilson static int hid_read(dev_t, struct uio *, cred_t *);
146*cfe80fe3SAlex Wilson static int hid_write(dev_t, struct uio *, cred_t *);
147*cfe80fe3SAlex Wilson static int hid_poll(dev_t, short, int, short *, struct pollhead **);
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate * Warlock is not aware of the automatic locking mechanisms for
1517c478bd9Sstevel@tonic-gate * streams drivers. The hid streams enter points are protected by
1527c478bd9Sstevel@tonic-gate * a per module perimeter. If the locking in hid is a bottleneck
1537c478bd9Sstevel@tonic-gate * per queue pair or per queue locking may be used. Since warlock
1547c478bd9Sstevel@tonic-gate * is not aware of the streams perimeters, these notes have been added.
1557c478bd9Sstevel@tonic-gate *
1567c478bd9Sstevel@tonic-gate * Note that the perimeters do not protect the driver from callbacks
1577c478bd9Sstevel@tonic-gate * happening while a streams entry point is executing. So, the hid_mutex
1587c478bd9Sstevel@tonic-gate * has been created to protect the data.
1597c478bd9Sstevel@tonic-gate */
1607c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
1617c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
1627c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", msgb))
1637c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", queue))
1647c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
1657c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_intr_req))
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate /* module information */
1687c478bd9Sstevel@tonic-gate static struct module_info hid_mod_info = {
1697c478bd9Sstevel@tonic-gate 0x0ffff, /* module id number */
1707c478bd9Sstevel@tonic-gate "hid", /* module name */
1717c478bd9Sstevel@tonic-gate 0, /* min packet size accepted */
1727c478bd9Sstevel@tonic-gate INFPSZ, /* max packet size accepted */
1737c478bd9Sstevel@tonic-gate 512, /* hi-water mark */
1747c478bd9Sstevel@tonic-gate 128 /* lo-water mark */
1757c478bd9Sstevel@tonic-gate };
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate /* read queue information structure */
1787c478bd9Sstevel@tonic-gate static struct qinit rinit = {
1797c478bd9Sstevel@tonic-gate NULL, /* put procedure not needed */
1807c478bd9Sstevel@tonic-gate NULL, /* service procedure not needed */
1817c478bd9Sstevel@tonic-gate hid_open, /* called on startup */
1827c478bd9Sstevel@tonic-gate hid_close, /* called on finish */
1837c478bd9Sstevel@tonic-gate NULL, /* for future use */
1847c478bd9Sstevel@tonic-gate &hid_mod_info, /* module information structure */
1857c478bd9Sstevel@tonic-gate NULL /* module statistics structure */
1867c478bd9Sstevel@tonic-gate };
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate /* write queue information structure */
1897c478bd9Sstevel@tonic-gate static struct qinit winit = {
1907c478bd9Sstevel@tonic-gate hid_wput, /* put procedure */
1917c478bd9Sstevel@tonic-gate hid_wsrv, /* service procedure */
1927c478bd9Sstevel@tonic-gate NULL, /* open not used on write side */
1937c478bd9Sstevel@tonic-gate NULL, /* close not used on write side */
1947c478bd9Sstevel@tonic-gate NULL, /* for future use */
1957c478bd9Sstevel@tonic-gate &hid_mod_info, /* module information structure */
1967c478bd9Sstevel@tonic-gate NULL /* module statistics structure */
1977c478bd9Sstevel@tonic-gate };
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate struct streamtab hid_streamtab = {
2007c478bd9Sstevel@tonic-gate &rinit,
2017c478bd9Sstevel@tonic-gate &winit,
2027c478bd9Sstevel@tonic-gate NULL, /* not a MUX */
2037c478bd9Sstevel@tonic-gate NULL /* not a MUX */
2047c478bd9Sstevel@tonic-gate };
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate struct cb_ops hid_cb_ops = {
207*cfe80fe3SAlex Wilson hid_chropen, /* open */
208*cfe80fe3SAlex Wilson hid_chrclose, /* close */
2097c478bd9Sstevel@tonic-gate nulldev, /* strategy */
2107c478bd9Sstevel@tonic-gate nulldev, /* print */
2117c478bd9Sstevel@tonic-gate nulldev, /* dump */
212*cfe80fe3SAlex Wilson hid_read, /* read */
213*cfe80fe3SAlex Wilson hid_write, /* write */
2147c478bd9Sstevel@tonic-gate nulldev, /* ioctl */
2157c478bd9Sstevel@tonic-gate nulldev, /* devmap */
2167c478bd9Sstevel@tonic-gate nulldev, /* mmap */
2177c478bd9Sstevel@tonic-gate nulldev, /* segmap */
218*cfe80fe3SAlex Wilson hid_poll, /* poll */
2197c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
2207c478bd9Sstevel@tonic-gate &hid_streamtab, /* streamtab */
2217c478bd9Sstevel@tonic-gate D_MP | D_MTPERQ
2227c478bd9Sstevel@tonic-gate };
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate static struct dev_ops hid_ops = {
2267c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */
2277c478bd9Sstevel@tonic-gate 0, /* refcnt */
2287c478bd9Sstevel@tonic-gate hid_info, /* info */
2297c478bd9Sstevel@tonic-gate nulldev, /* identify */
2307c478bd9Sstevel@tonic-gate nulldev, /* probe */
2317c478bd9Sstevel@tonic-gate hid_attach, /* attach */
2327c478bd9Sstevel@tonic-gate hid_detach, /* detach */
2337c478bd9Sstevel@tonic-gate nodev, /* reset */
2347c478bd9Sstevel@tonic-gate &hid_cb_ops, /* driver operations */
2357c478bd9Sstevel@tonic-gate NULL, /* bus operations */
23619397407SSherry Moore hid_power, /* power */
23719397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */
2387c478bd9Sstevel@tonic-gate };
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate static struct modldrv hidmodldrv = {
2417c478bd9Sstevel@tonic-gate &mod_driverops,
24277e51571Sgongtian zhao - Sun Microsystems - Beijing China "USB HID Client Driver",
2437c478bd9Sstevel@tonic-gate &hid_ops /* driver ops */
2447c478bd9Sstevel@tonic-gate };
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
2477c478bd9Sstevel@tonic-gate MODREV_1,
2487c478bd9Sstevel@tonic-gate &hidmodldrv,
2497c478bd9Sstevel@tonic-gate NULL,
2507c478bd9Sstevel@tonic-gate };
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate static usb_event_t hid_events = {
2537c478bd9Sstevel@tonic-gate hid_disconnect_event_callback,
2547c478bd9Sstevel@tonic-gate hid_restore_state_event_callback,
2557c478bd9Sstevel@tonic-gate NULL,
2567c478bd9Sstevel@tonic-gate NULL,
2577c478bd9Sstevel@tonic-gate };
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate int
_init(void)2617c478bd9Sstevel@tonic-gate _init(void)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate int rval;
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate if (((rval = ddi_soft_state_init(&hid_statep, sizeof (hid_state_t),
2667c478bd9Sstevel@tonic-gate HID_INITIAL_SOFT_SPACE)) != 0)) {
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate return (rval);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) {
2727c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&hid_statep);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate return (rval);
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate int
_fini(void)2807c478bd9Sstevel@tonic-gate _fini(void)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate int rval;
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate if ((rval = mod_remove(&modlinkage)) != 0) {
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate return (rval);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&hid_statep);
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate return (rval);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2967c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate * hid_info :
3047c478bd9Sstevel@tonic-gate * Get minor number, soft state structure etc.
3057c478bd9Sstevel@tonic-gate */
3067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3077c478bd9Sstevel@tonic-gate static int
hid_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)308993e3fafSRobert Mustacchi hid_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate hid_state_t *hidp = NULL;
3117c478bd9Sstevel@tonic-gate int error = DDI_FAILURE;
3127c478bd9Sstevel@tonic-gate minor_t minor = getminor((dev_t)arg);
3137c478bd9Sstevel@tonic-gate int instance = HID_MINOR_TO_INSTANCE(minor);
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate switch (infocmd) {
3167c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
3177c478bd9Sstevel@tonic-gate if ((hidp = ddi_get_soft_state(hid_statep, instance)) != NULL) {
3187c478bd9Sstevel@tonic-gate *result = hidp->hid_dip;
3197c478bd9Sstevel@tonic-gate if (*result != NULL) {
3207c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate } else
3237c478bd9Sstevel@tonic-gate *result = NULL;
3247c478bd9Sstevel@tonic-gate break;
3257c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
3267c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance;
3277c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
3287c478bd9Sstevel@tonic-gate break;
3297c478bd9Sstevel@tonic-gate default:
3307c478bd9Sstevel@tonic-gate break;
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate return (error);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate * hid_attach :
3397c478bd9Sstevel@tonic-gate * Gets called at the time of attach. Do allocation,
3407c478bd9Sstevel@tonic-gate * and initialization of the software structure.
3417c478bd9Sstevel@tonic-gate * Get all the descriptors, setup the
3427c478bd9Sstevel@tonic-gate * report descriptor tree by calling hidparser
3437c478bd9Sstevel@tonic-gate * function.
3447c478bd9Sstevel@tonic-gate */
3457c478bd9Sstevel@tonic-gate static int
hid_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3467c478bd9Sstevel@tonic-gate hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
3507c478bd9Sstevel@tonic-gate int parse_hid_descr_error = 0;
3517c478bd9Sstevel@tonic-gate hid_state_t *hidp = NULL;
3527c478bd9Sstevel@tonic-gate uint32_t usage_page;
3537c478bd9Sstevel@tonic-gate uint32_t usage;
3547c478bd9Sstevel@tonic-gate usb_client_dev_data_t *dev_data;
3557c478bd9Sstevel@tonic-gate usb_alt_if_data_t *altif_data;
3567c478bd9Sstevel@tonic-gate char minor_name[HID_MINOR_NAME_LEN];
3577c478bd9Sstevel@tonic-gate usb_ep_data_t *ep_data;
358*cfe80fe3SAlex Wilson usb_ugen_info_t usb_ugen_info;
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate switch (cmd) {
3617c478bd9Sstevel@tonic-gate case DDI_ATTACH:
3627c478bd9Sstevel@tonic-gate break;
3637c478bd9Sstevel@tonic-gate case DDI_RESUME:
3647c478bd9Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
3657c478bd9Sstevel@tonic-gate hid_cpr_resume(hidp);
3667c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
3677c478bd9Sstevel@tonic-gate default:
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate /*
3737c478bd9Sstevel@tonic-gate * Allocate softstate information and get softstate pointer
3747c478bd9Sstevel@tonic-gate */
3757c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(hid_statep, instance) == DDI_SUCCESS) {
3767c478bd9Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate if (hidp == NULL) {
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate goto fail;
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate hidp->hid_log_handle = usb_alloc_log_hdl(dip, NULL, &hid_errlevel,
384112116d8Sfb &hid_errmask, &hid_instance_debug, 0);
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate hidp->hid_instance = instance;
3877c478bd9Sstevel@tonic-gate hidp->hid_dip = dip;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate * Register with USBA. Just retrieve interface descriptor
3917c478bd9Sstevel@tonic-gate */
3927c478bd9Sstevel@tonic-gate if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
3937c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
3947c478bd9Sstevel@tonic-gate "hid_attach: client attach failed");
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate goto fail;
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) !=
4007c478bd9Sstevel@tonic-gate USB_SUCCESS) {
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
4037c478bd9Sstevel@tonic-gate "hid_attach: usb_get_dev_data() failed");
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate goto fail;
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate /* initialize mutex */
4097c478bd9Sstevel@tonic-gate mutex_init(&hidp->hid_mutex, NULL, MUTEX_DRIVER,
410112116d8Sfb dev_data->dev_iblock_cookie);
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate hidp->hid_attach_flags |= HID_LOCK_INIT;
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate /* get interface data for alternate 0 */
4157c478bd9Sstevel@tonic-gate altif_data = &dev_data->dev_curr_cfg->
416112116d8Sfb cfg_if[dev_data->dev_curr_if].if_alt[0];
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
4197c478bd9Sstevel@tonic-gate hidp->hid_dev_data = dev_data;
4207c478bd9Sstevel@tonic-gate hidp->hid_dev_descr = dev_data->dev_descr;
4217c478bd9Sstevel@tonic-gate hidp->hid_interfaceno = dev_data->dev_curr_if;
4227c478bd9Sstevel@tonic-gate hidp->hid_if_descr = altif_data->altif_descr;
4230fc2d926Sqz /*
4240fc2d926Sqz * Make sure that the bInterfaceProtocol only has meaning to
4250fc2d926Sqz * Boot Interface Subclass.
4260fc2d926Sqz */
4270fc2d926Sqz if (hidp->hid_if_descr.bInterfaceSubClass != BOOT_INTERFACE)
4280fc2d926Sqz hidp->hid_if_descr.bInterfaceProtocol = NONE_PROTOCOL;
4297c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate if ((ep_data = usb_lookup_ep_data(dip, dev_data,
4327c478bd9Sstevel@tonic-gate hidp->hid_interfaceno, 0, 0,
4337c478bd9Sstevel@tonic-gate (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) {
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
4367c478bd9Sstevel@tonic-gate "no interrupt IN endpoint found");
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate goto fail;
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
442993e3fafSRobert Mustacchi if (usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION, dip, ep_data,
443993e3fafSRobert Mustacchi &hidp->hid_ep_intr_xdescr) != USB_SUCCESS) {
444db1c88f6SSebastian Wiedenroth mutex_exit(&hidp->hid_mutex);
445993e3fafSRobert Mustacchi
446993e3fafSRobert Mustacchi goto fail;
447993e3fafSRobert Mustacchi }
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate /*
4507c478bd9Sstevel@tonic-gate * Attempt to find the hid descriptor, it could be after interface
4517c478bd9Sstevel@tonic-gate * or after endpoint descriptors
4527c478bd9Sstevel@tonic-gate */
4537c478bd9Sstevel@tonic-gate if (hid_parse_hid_descr(&hidp->hid_hid_descr, USB_HID_DESCR_SIZE,
4547c478bd9Sstevel@tonic-gate altif_data, ep_data) != USB_HID_DESCR_SIZE) {
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate * If parsing of hid descriptor failed and
4577c478bd9Sstevel@tonic-gate * the device is a keyboard or mouse, use predefined
4587c478bd9Sstevel@tonic-gate * length and packet size.
4597c478bd9Sstevel@tonic-gate */
4607c478bd9Sstevel@tonic-gate if (hid_parse_hid_descr_failure(hidp) == USB_FAILURE) {
4617c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate goto fail;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate * hid descriptor was bad but since
4687c478bd9Sstevel@tonic-gate * the device is a keyboard or mouse,
4697c478bd9Sstevel@tonic-gate * we will use the default length
4707c478bd9Sstevel@tonic-gate * and packet size.
4717c478bd9Sstevel@tonic-gate */
4727c478bd9Sstevel@tonic-gate parse_hid_descr_error = HID_BAD_DESCR;
4737c478bd9Sstevel@tonic-gate } else {
4747c478bd9Sstevel@tonic-gate /* Parse hid descriptor successful */
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
4777c478bd9Sstevel@tonic-gate "Hid descriptor:\n\t"
4787c478bd9Sstevel@tonic-gate "bLength = 0x%x bDescriptorType = 0x%x "
4797c478bd9Sstevel@tonic-gate "bcdHID = 0x%x\n\t"
4807c478bd9Sstevel@tonic-gate "bCountryCode = 0x%x bNumDescriptors = 0x%x\n\t"
4817c478bd9Sstevel@tonic-gate "bReportDescriptorType = 0x%x\n\t"
4827c478bd9Sstevel@tonic-gate "wReportDescriptorLength = 0x%x",
4837c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.bLength,
4847c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.bDescriptorType,
4857c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.bcdHID,
4867c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.bCountryCode,
4877c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.bNumDescriptors,
4887c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.bReportDescriptorType,
4897c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.wReportDescriptorLength);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate * Save a copy of the default pipe for easy reference
4947c478bd9Sstevel@tonic-gate */
4957c478bd9Sstevel@tonic-gate hidp->hid_default_pipe = hidp->hid_dev_data->dev_default_ph;
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate /* we copied the descriptors we need, free the dev_data */
4987c478bd9Sstevel@tonic-gate usb_free_dev_data(dip, dev_data);
4997c478bd9Sstevel@tonic-gate hidp->hid_dev_data = NULL;
5007c478bd9Sstevel@tonic-gate
501*cfe80fe3SAlex Wilson if (usb_owns_device(dip)) {
502*cfe80fe3SAlex Wilson /* Get a ugen handle. */
503*cfe80fe3SAlex Wilson bzero(&usb_ugen_info, sizeof (usb_ugen_info));
504*cfe80fe3SAlex Wilson
505*cfe80fe3SAlex Wilson usb_ugen_info.usb_ugen_flags = 0;
506*cfe80fe3SAlex Wilson usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
507*cfe80fe3SAlex Wilson (dev_t)HID_MINOR_UGEN_BITS_MASK;
508*cfe80fe3SAlex Wilson usb_ugen_info.usb_ugen_minor_node_instance_mask =
509*cfe80fe3SAlex Wilson (dev_t)HID_MINOR_INSTANCE_MASK;
510*cfe80fe3SAlex Wilson hidp->hid_ugen_hdl = usb_ugen_get_hdl(dip, &usb_ugen_info);
511*cfe80fe3SAlex Wilson
512*cfe80fe3SAlex Wilson if (usb_ugen_attach(hidp->hid_ugen_hdl, cmd) !=
513*cfe80fe3SAlex Wilson USB_SUCCESS) {
514*cfe80fe3SAlex Wilson USB_DPRINTF_L2(PRINT_MASK_ATTA,
515*cfe80fe3SAlex Wilson hidp->hid_log_handle,
516*cfe80fe3SAlex Wilson "usb_ugen_attach failed");
517*cfe80fe3SAlex Wilson
518*cfe80fe3SAlex Wilson usb_ugen_release_hdl(hidp->hid_ugen_hdl);
519*cfe80fe3SAlex Wilson hidp->hid_ugen_hdl = NULL;
520*cfe80fe3SAlex Wilson }
521*cfe80fe3SAlex Wilson }
522*cfe80fe3SAlex Wilson
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate * Don't get the report descriptor if parsing hid descriptor earlier
5257c478bd9Sstevel@tonic-gate * failed since device probably won't return valid report descriptor
5267c478bd9Sstevel@tonic-gate * either. Though parsing of hid descriptor failed, we have reached
5277c478bd9Sstevel@tonic-gate * this point because the device has been identified as a
5287c478bd9Sstevel@tonic-gate * keyboard or a mouse successfully and the default packet
5297c478bd9Sstevel@tonic-gate * size and layout(in case of keyboard only) will be used, so it
5307c478bd9Sstevel@tonic-gate * is ok to go ahead even if parsing of hid descriptor failed and
5317c478bd9Sstevel@tonic-gate * we will not try to get the report descriptor.
5327c478bd9Sstevel@tonic-gate */
5337c478bd9Sstevel@tonic-gate if (parse_hid_descr_error != HID_BAD_DESCR) {
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate * Sun mouse rev 105 is a bit slow in responding to this
5367c478bd9Sstevel@tonic-gate * request and requires multiple retries
5377c478bd9Sstevel@tonic-gate */
5387c478bd9Sstevel@tonic-gate int retry;
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate * Get and parse the report descriptor.
5427c478bd9Sstevel@tonic-gate * Set the packet size if parsing is successful.
5437c478bd9Sstevel@tonic-gate * Note that we start retry at 1 to have a delay
5447c478bd9Sstevel@tonic-gate * in the first iteration.
5457c478bd9Sstevel@tonic-gate */
5467c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
5477c478bd9Sstevel@tonic-gate for (retry = 1; retry < HID_RETRY; retry++) {
5487c478bd9Sstevel@tonic-gate if (hid_handle_report_descriptor(hidp,
5497c478bd9Sstevel@tonic-gate hidp->hid_interfaceno) == USB_SUCCESS) {
5507c478bd9Sstevel@tonic-gate break;
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate delay(retry * drv_usectohz(1000));
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate if (retry >= HID_RETRY) {
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate goto fail;
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate /*
5617c478bd9Sstevel@tonic-gate * If packet size is zero, but the device is identified
5627c478bd9Sstevel@tonic-gate * as a mouse or a keyboard, use predefined packet
5637c478bd9Sstevel@tonic-gate * size.
5647c478bd9Sstevel@tonic-gate */
5657c478bd9Sstevel@tonic-gate if (hidp->hid_packet_size == 0) {
5667c478bd9Sstevel@tonic-gate if (hidp->hid_if_descr.bInterfaceProtocol ==
5677c478bd9Sstevel@tonic-gate KEYBOARD_PROTOCOL) {
5687c478bd9Sstevel@tonic-gate /* device is a keyboard */
5697c478bd9Sstevel@tonic-gate hidp->hid_packet_size = USBKPSZ;
5707c478bd9Sstevel@tonic-gate } else if (hidp->
5717c478bd9Sstevel@tonic-gate hid_if_descr.bInterfaceProtocol ==
5727c478bd9Sstevel@tonic-gate MOUSE_PROTOCOL) {
5737c478bd9Sstevel@tonic-gate /* device is a mouse */
5747c478bd9Sstevel@tonic-gate hidp->hid_packet_size = USBMSSZ;
5757c478bd9Sstevel@tonic-gate } else {
5767c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
5777c478bd9Sstevel@tonic-gate hidp->hid_log_handle,
5787c478bd9Sstevel@tonic-gate "Failed to find hid packet size");
5797c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate goto fail;
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate * initialize the pipe policy for the interrupt pipe.
5887c478bd9Sstevel@tonic-gate */
5897c478bd9Sstevel@tonic-gate hidp->hid_intr_pipe_policy.pp_max_async_reqs = 1;
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate /*
5927c478bd9Sstevel@tonic-gate * Make a clas specific request to SET_IDLE
5937c478bd9Sstevel@tonic-gate * In this case send no reports if state has not changed.
5947c478bd9Sstevel@tonic-gate * See HID 7.2.4.
5957c478bd9Sstevel@tonic-gate */
5967c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
5977c478bd9Sstevel@tonic-gate hid_set_idle(hidp);
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate /* always initialize to report protocol */
6007c478bd9Sstevel@tonic-gate hid_set_protocol(hidp, SET_REPORT_PROTOCOL);
6017c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate /*
6047c478bd9Sstevel@tonic-gate * Create minor node based on information from the
6057c478bd9Sstevel@tonic-gate * descriptors
6067c478bd9Sstevel@tonic-gate */
6077c478bd9Sstevel@tonic-gate switch (hidp->hid_if_descr.bInterfaceProtocol) {
6087c478bd9Sstevel@tonic-gate case KEYBOARD_PROTOCOL:
6097c478bd9Sstevel@tonic-gate (void) strcpy(minor_name, "keyboard");
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate break;
6127c478bd9Sstevel@tonic-gate case MOUSE_PROTOCOL:
6137c478bd9Sstevel@tonic-gate (void) strcpy(minor_name, "mouse");
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate break;
6167c478bd9Sstevel@tonic-gate default:
617827f5d6bSStrony Zhang - Solaris China Team /*
618827f5d6bSStrony Zhang - Solaris China Team * If the report descriptor has the GD mouse collection in
619827f5d6bSStrony Zhang - Solaris China Team * its multiple collection, create a minor node and support it.
620827f5d6bSStrony Zhang - Solaris China Team * It is used on some advanced keyboard/mouse set.
621827f5d6bSStrony Zhang - Solaris China Team */
622827f5d6bSStrony Zhang - Solaris China Team if (hidparser_lookup_usage_collection(
623827f5d6bSStrony Zhang - Solaris China Team hidp->hid_report_descr, HID_GENERIC_DESKTOP,
624827f5d6bSStrony Zhang - Solaris China Team HID_GD_MOUSE) != HIDPARSER_FAILURE) {
625827f5d6bSStrony Zhang - Solaris China Team (void) strcpy(minor_name, "mouse");
626827f5d6bSStrony Zhang - Solaris China Team
627827f5d6bSStrony Zhang - Solaris China Team break;
628827f5d6bSStrony Zhang - Solaris China Team }
629827f5d6bSStrony Zhang - Solaris China Team
6307c478bd9Sstevel@tonic-gate if (hidparser_get_top_level_collection_usage(
6317c478bd9Sstevel@tonic-gate hidp->hid_report_descr, &usage_page, &usage) !=
6327c478bd9Sstevel@tonic-gate HIDPARSER_FAILURE) {
6337c478bd9Sstevel@tonic-gate switch (usage_page) {
6347c478bd9Sstevel@tonic-gate case HID_CONSUMER:
6357c478bd9Sstevel@tonic-gate switch (usage) {
6367c478bd9Sstevel@tonic-gate case HID_CONSUMER_CONTROL:
6377c478bd9Sstevel@tonic-gate (void) strcpy(minor_name,
6387c478bd9Sstevel@tonic-gate "consumer_control");
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate break;
6417c478bd9Sstevel@tonic-gate default:
6427c478bd9Sstevel@tonic-gate (void) sprintf(minor_name,
6437c478bd9Sstevel@tonic-gate "hid_%d_%d", usage_page, usage);
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate break;
6467c478bd9Sstevel@tonic-gate }
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate break;
6497c478bd9Sstevel@tonic-gate case HID_GENERIC_DESKTOP:
6507c478bd9Sstevel@tonic-gate switch (usage) {
6517c478bd9Sstevel@tonic-gate case HID_GD_POINTER:
6527c478bd9Sstevel@tonic-gate (void) strcpy(minor_name,
6537c478bd9Sstevel@tonic-gate "pointer");
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate break;
6567c478bd9Sstevel@tonic-gate case HID_GD_MOUSE:
6577c478bd9Sstevel@tonic-gate (void) strcpy(minor_name,
6587c478bd9Sstevel@tonic-gate "mouse");
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate break;
6617c478bd9Sstevel@tonic-gate case HID_GD_KEYBOARD:
6627c478bd9Sstevel@tonic-gate (void) strcpy(minor_name,
6637c478bd9Sstevel@tonic-gate "keyboard");
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate break;
6667c478bd9Sstevel@tonic-gate default:
6677c478bd9Sstevel@tonic-gate (void) sprintf(minor_name,
6687c478bd9Sstevel@tonic-gate "hid_%d_%d", usage_page, usage);
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate break;
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate break;
6747c478bd9Sstevel@tonic-gate default:
6757c478bd9Sstevel@tonic-gate (void) sprintf(minor_name,
6767c478bd9Sstevel@tonic-gate "hid_%d_%d", usage_page, usage);
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate break;
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate } else {
6817c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
6827c478bd9Sstevel@tonic-gate "hid_attach: Unsupported HID device");
6837c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate goto fail;
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate break;
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
6927c478bd9Sstevel@tonic-gate
6937c478bd9Sstevel@tonic-gate if ((ddi_create_minor_node(dip, minor_name, S_IFCHR,
6947c478bd9Sstevel@tonic-gate HID_CONSTRUCT_EXTERNAL_MINOR(instance),
6957c478bd9Sstevel@tonic-gate DDI_PSEUDO, 0)) != DDI_SUCCESS) {
696d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
6977c478bd9Sstevel@tonic-gate "hid_attach: Could not create minor node");
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate goto fail;
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate /* create internal path for virtual */
7037c478bd9Sstevel@tonic-gate if (strcmp(minor_name, "mouse") == 0) {
7047c478bd9Sstevel@tonic-gate if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR,
7057c478bd9Sstevel@tonic-gate HID_CONSTRUCT_INTERNAL_MINOR(instance)) != DDI_SUCCESS) {
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate goto fail;
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate if (strcmp(minor_name, "keyboard") == 0) {
7127c478bd9Sstevel@tonic-gate if (ddi_create_internal_pathname(dip, "internal_keyboard",
7137c478bd9Sstevel@tonic-gate S_IFCHR, HID_CONSTRUCT_INTERNAL_MINOR(instance)) !=
7147c478bd9Sstevel@tonic-gate DDI_SUCCESS) {
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate goto fail;
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
7217c478bd9Sstevel@tonic-gate hidp->hid_attach_flags |= HID_MINOR_NODES;
7227c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_ONLINE;
7237c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate /* register for all events */
7267c478bd9Sstevel@tonic-gate if (usb_register_event_cbs(dip, &hid_events, 0) != USB_SUCCESS) {
727d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
7287c478bd9Sstevel@tonic-gate "usb_register_event_cbs failed");
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate goto fail;
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate /* now create components to power manage this device */
7347c478bd9Sstevel@tonic-gate hid_create_pm_components(dip, hidp);
7357c478bd9Sstevel@tonic-gate hid_pm_busy_component(hidp);
7367c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
7377c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
7387c478bd9Sstevel@tonic-gate
739ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_rq = hidp->hid_external_rq = NULL;
740ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_flag = hidp->hid_external_flag = 0;
741ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = NULL;
742ddee57faSrui zang - Sun Microsystems - Beijing China
7437c478bd9Sstevel@tonic-gate /*
7447c478bd9Sstevel@tonic-gate * report device
7457c478bd9Sstevel@tonic-gate */
7467c478bd9Sstevel@tonic-gate ddi_report_dev(dip);
7477c478bd9Sstevel@tonic-gate
7487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
7497c478bd9Sstevel@tonic-gate "hid_attach: End");
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate fail:
7547c478bd9Sstevel@tonic-gate if (hidp) {
7557c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
7567c478bd9Sstevel@tonic-gate "hid_attach: fail");
7577c478bd9Sstevel@tonic-gate hid_detach_cleanup(dip, hidp);
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate /*
7657c478bd9Sstevel@tonic-gate * hid_detach :
7667c478bd9Sstevel@tonic-gate * Gets called at the time of detach.
7677c478bd9Sstevel@tonic-gate */
7687c478bd9Sstevel@tonic-gate static int
hid_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)769993e3fafSRobert Mustacchi hid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
7727c478bd9Sstevel@tonic-gate hid_state_t *hidp;
7737c478bd9Sstevel@tonic-gate int rval = DDI_FAILURE;
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle, "hid_detach");
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate switch (cmd) {
7807c478bd9Sstevel@tonic-gate case DDI_DETACH:
7817c478bd9Sstevel@tonic-gate /*
7827c478bd9Sstevel@tonic-gate * Undo what we did in client_attach, freeing resources
7837c478bd9Sstevel@tonic-gate * and removing things we installed. The system
7847c478bd9Sstevel@tonic-gate * framework guarantees we are not active with this devinfo
7857c478bd9Sstevel@tonic-gate * node in any other entry points at this time.
7867c478bd9Sstevel@tonic-gate */
7877c478bd9Sstevel@tonic-gate hid_detach_cleanup(dip, hidp);
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
7907c478bd9Sstevel@tonic-gate case DDI_SUSPEND:
7917c478bd9Sstevel@tonic-gate rval = hid_cpr_suspend(hidp);
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate return (rval == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
7947c478bd9Sstevel@tonic-gate default:
7957c478bd9Sstevel@tonic-gate break;
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate
7987c478bd9Sstevel@tonic-gate return (rval);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate
801*cfe80fe3SAlex Wilson static int
hid_chropen(dev_t * devp,int flag,int sflag,cred_t * credp)802*cfe80fe3SAlex Wilson hid_chropen(dev_t *devp, int flag, int sflag, cred_t *credp)
803*cfe80fe3SAlex Wilson {
804*cfe80fe3SAlex Wilson int rval;
805*cfe80fe3SAlex Wilson minor_t minor = getminor(*devp);
806*cfe80fe3SAlex Wilson int instance;
807*cfe80fe3SAlex Wilson hid_state_t *hidp;
808*cfe80fe3SAlex Wilson
809*cfe80fe3SAlex Wilson instance = HID_MINOR_TO_INSTANCE(minor);
810*cfe80fe3SAlex Wilson
811*cfe80fe3SAlex Wilson hidp = ddi_get_soft_state(hid_statep, instance);
812*cfe80fe3SAlex Wilson if (hidp == NULL) {
813*cfe80fe3SAlex Wilson return (ENXIO);
814*cfe80fe3SAlex Wilson }
815*cfe80fe3SAlex Wilson
816*cfe80fe3SAlex Wilson if (!HID_IS_UGEN_OPEN(minor)) {
817*cfe80fe3SAlex Wilson return (ENXIO);
818*cfe80fe3SAlex Wilson }
819*cfe80fe3SAlex Wilson
820*cfe80fe3SAlex Wilson hid_pm_busy_component(hidp);
821*cfe80fe3SAlex Wilson (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
822*cfe80fe3SAlex Wilson
823*cfe80fe3SAlex Wilson mutex_enter(&hidp->hid_mutex);
824*cfe80fe3SAlex Wilson
825*cfe80fe3SAlex Wilson rval = usb_ugen_open(hidp->hid_ugen_hdl, devp, flag,
826*cfe80fe3SAlex Wilson sflag, credp);
827*cfe80fe3SAlex Wilson
828*cfe80fe3SAlex Wilson mutex_exit(&hidp->hid_mutex);
829*cfe80fe3SAlex Wilson
830*cfe80fe3SAlex Wilson if (rval != 0) {
831*cfe80fe3SAlex Wilson hid_pm_idle_component(hidp);
832*cfe80fe3SAlex Wilson }
833*cfe80fe3SAlex Wilson
834*cfe80fe3SAlex Wilson return (rval);
835*cfe80fe3SAlex Wilson }
836*cfe80fe3SAlex Wilson
837*cfe80fe3SAlex Wilson static int
hid_chrclose(dev_t dev,int flag,int otyp,cred_t * credp)838*cfe80fe3SAlex Wilson hid_chrclose(dev_t dev, int flag, int otyp, cred_t *credp)
839*cfe80fe3SAlex Wilson {
840*cfe80fe3SAlex Wilson int rval;
841*cfe80fe3SAlex Wilson minor_t minor = getminor(dev);
842*cfe80fe3SAlex Wilson int instance;
843*cfe80fe3SAlex Wilson hid_state_t *hidp;
844*cfe80fe3SAlex Wilson
845*cfe80fe3SAlex Wilson instance = HID_MINOR_TO_INSTANCE(minor);
846*cfe80fe3SAlex Wilson
847*cfe80fe3SAlex Wilson hidp = ddi_get_soft_state(hid_statep, instance);
848*cfe80fe3SAlex Wilson if (hidp == NULL) {
849*cfe80fe3SAlex Wilson return (ENXIO);
850*cfe80fe3SAlex Wilson }
851*cfe80fe3SAlex Wilson
852*cfe80fe3SAlex Wilson if (!HID_IS_UGEN_OPEN(minor)) {
853*cfe80fe3SAlex Wilson return (ENXIO);
854*cfe80fe3SAlex Wilson }
855*cfe80fe3SAlex Wilson
856*cfe80fe3SAlex Wilson mutex_enter(&hidp->hid_mutex);
857*cfe80fe3SAlex Wilson
858*cfe80fe3SAlex Wilson rval = usb_ugen_close(hidp->hid_ugen_hdl, dev, flag,
859*cfe80fe3SAlex Wilson otyp, credp);
860*cfe80fe3SAlex Wilson
861*cfe80fe3SAlex Wilson mutex_exit(&hidp->hid_mutex);
862*cfe80fe3SAlex Wilson
863*cfe80fe3SAlex Wilson if (rval == 0) {
864*cfe80fe3SAlex Wilson hid_pm_idle_component(hidp);
865*cfe80fe3SAlex Wilson }
866*cfe80fe3SAlex Wilson
867*cfe80fe3SAlex Wilson return (rval);
868*cfe80fe3SAlex Wilson }
869*cfe80fe3SAlex Wilson
870*cfe80fe3SAlex Wilson static int
hid_read(dev_t dev,struct uio * uiop,cred_t * credp)871*cfe80fe3SAlex Wilson hid_read(dev_t dev, struct uio *uiop, cred_t *credp)
872*cfe80fe3SAlex Wilson {
873*cfe80fe3SAlex Wilson int rval;
874*cfe80fe3SAlex Wilson minor_t minor = getminor(dev);
875*cfe80fe3SAlex Wilson int instance;
876*cfe80fe3SAlex Wilson hid_state_t *hidp;
877*cfe80fe3SAlex Wilson
878*cfe80fe3SAlex Wilson instance = HID_MINOR_TO_INSTANCE(minor);
879*cfe80fe3SAlex Wilson
880*cfe80fe3SAlex Wilson hidp = ddi_get_soft_state(hid_statep, instance);
881*cfe80fe3SAlex Wilson if (hidp == NULL) {
882*cfe80fe3SAlex Wilson return (ENXIO);
883*cfe80fe3SAlex Wilson }
884*cfe80fe3SAlex Wilson
885*cfe80fe3SAlex Wilson if (!HID_IS_UGEN_OPEN(minor)) {
886*cfe80fe3SAlex Wilson return (ENXIO);
887*cfe80fe3SAlex Wilson }
888*cfe80fe3SAlex Wilson
889*cfe80fe3SAlex Wilson rval = usb_ugen_read(hidp->hid_ugen_hdl, dev, uiop, credp);
890*cfe80fe3SAlex Wilson
891*cfe80fe3SAlex Wilson return (rval);
892*cfe80fe3SAlex Wilson }
893*cfe80fe3SAlex Wilson
894*cfe80fe3SAlex Wilson static int
hid_write(dev_t dev,struct uio * uiop,cred_t * credp)895*cfe80fe3SAlex Wilson hid_write(dev_t dev, struct uio *uiop, cred_t *credp)
896*cfe80fe3SAlex Wilson {
897*cfe80fe3SAlex Wilson int rval;
898*cfe80fe3SAlex Wilson minor_t minor = getminor(dev);
899*cfe80fe3SAlex Wilson int instance;
900*cfe80fe3SAlex Wilson hid_state_t *hidp;
901*cfe80fe3SAlex Wilson
902*cfe80fe3SAlex Wilson instance = HID_MINOR_TO_INSTANCE(minor);
903*cfe80fe3SAlex Wilson
904*cfe80fe3SAlex Wilson hidp = ddi_get_soft_state(hid_statep, instance);
905*cfe80fe3SAlex Wilson if (hidp == NULL) {
906*cfe80fe3SAlex Wilson return (ENXIO);
907*cfe80fe3SAlex Wilson }
908*cfe80fe3SAlex Wilson
909*cfe80fe3SAlex Wilson if (!HID_IS_UGEN_OPEN(minor)) {
910*cfe80fe3SAlex Wilson return (ENXIO);
911*cfe80fe3SAlex Wilson }
912*cfe80fe3SAlex Wilson
913*cfe80fe3SAlex Wilson rval = usb_ugen_write(hidp->hid_ugen_hdl, dev, uiop, credp);
914*cfe80fe3SAlex Wilson
915*cfe80fe3SAlex Wilson return (rval);
916*cfe80fe3SAlex Wilson }
917*cfe80fe3SAlex Wilson
918*cfe80fe3SAlex Wilson static int
hid_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)919*cfe80fe3SAlex Wilson hid_poll(dev_t dev, short events, int anyyet, short *reventsp,
920*cfe80fe3SAlex Wilson struct pollhead **phpp)
921*cfe80fe3SAlex Wilson {
922*cfe80fe3SAlex Wilson int rval;
923*cfe80fe3SAlex Wilson minor_t minor = getminor(dev);
924*cfe80fe3SAlex Wilson int instance;
925*cfe80fe3SAlex Wilson hid_state_t *hidp;
926*cfe80fe3SAlex Wilson
927*cfe80fe3SAlex Wilson instance = HID_MINOR_TO_INSTANCE(minor);
928*cfe80fe3SAlex Wilson
929*cfe80fe3SAlex Wilson hidp = ddi_get_soft_state(hid_statep, instance);
930*cfe80fe3SAlex Wilson if (hidp == NULL) {
931*cfe80fe3SAlex Wilson return (ENXIO);
932*cfe80fe3SAlex Wilson }
933*cfe80fe3SAlex Wilson
934*cfe80fe3SAlex Wilson if (!HID_IS_UGEN_OPEN(minor)) {
935*cfe80fe3SAlex Wilson return (ENXIO);
936*cfe80fe3SAlex Wilson }
937*cfe80fe3SAlex Wilson
938*cfe80fe3SAlex Wilson rval = usb_ugen_poll(hidp->hid_ugen_hdl, dev, events, anyyet,
939*cfe80fe3SAlex Wilson reventsp, phpp);
940*cfe80fe3SAlex Wilson
941*cfe80fe3SAlex Wilson return (rval);
942*cfe80fe3SAlex Wilson }
943*cfe80fe3SAlex Wilson
9447c478bd9Sstevel@tonic-gate /*
9457c478bd9Sstevel@tonic-gate * hid_open :
9467c478bd9Sstevel@tonic-gate * Open entry point: Opens the interrupt pipe. Sets up queues.
9477c478bd9Sstevel@tonic-gate */
9487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9497c478bd9Sstevel@tonic-gate static int
hid_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)9507c478bd9Sstevel@tonic-gate hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate int no_of_ep = 0;
9537c478bd9Sstevel@tonic-gate int rval;
9547c478bd9Sstevel@tonic-gate int instance;
9557c478bd9Sstevel@tonic-gate hid_state_t *hidp;
9567c478bd9Sstevel@tonic-gate minor_t minor = getminor(*devp);
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate instance = HID_MINOR_TO_INSTANCE(minor);
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
9617c478bd9Sstevel@tonic-gate if (hidp == NULL) {
9627c478bd9Sstevel@tonic-gate return (ENXIO);
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate
9657c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle,
9667c478bd9Sstevel@tonic-gate "hid_open: Begin");
9677c478bd9Sstevel@tonic-gate
968*cfe80fe3SAlex Wilson /*
969*cfe80fe3SAlex Wilson * If this is a ugen device, return ENOSTR (no streams). This will
970*cfe80fe3SAlex Wilson * cause spec_open to try hid_chropen from our regular ops_cb instead
971*cfe80fe3SAlex Wilson * (and thus treat us as a plain character device).
972*cfe80fe3SAlex Wilson */
973*cfe80fe3SAlex Wilson if (HID_IS_UGEN_OPEN(minor)) {
974*cfe80fe3SAlex Wilson return (ENOSTR);
975*cfe80fe3SAlex Wilson }
976*cfe80fe3SAlex Wilson
9777c478bd9Sstevel@tonic-gate if (sflag) {
9787c478bd9Sstevel@tonic-gate /* clone open NOT supported here */
9797c478bd9Sstevel@tonic-gate return (ENXIO);
9807c478bd9Sstevel@tonic-gate }
9817c478bd9Sstevel@tonic-gate
982ac9468f8Spengcheng chen - Sun Microsystems - Beijing China if (!(flag & FREAD)) {
983ac9468f8Spengcheng chen - Sun Microsystems - Beijing China return (EIO);
984ac9468f8Spengcheng chen - Sun Microsystems - Beijing China }
9857c478bd9Sstevel@tonic-gate
986*cfe80fe3SAlex Wilson mutex_enter(&hidp->hid_mutex);
987*cfe80fe3SAlex Wilson
9887c478bd9Sstevel@tonic-gate /*
9897c478bd9Sstevel@tonic-gate * This is a workaround:
9907c478bd9Sstevel@tonic-gate * Currently, if we open an already disconnected device, and send
9917c478bd9Sstevel@tonic-gate * a CONSOPENPOLL ioctl to it, the system will panic, please refer
9927c478bd9Sstevel@tonic-gate * to the processing HID_OPEN_POLLED_INPUT ioctl in the routine
9937c478bd9Sstevel@tonic-gate * hid_mctl_receive().
9947c478bd9Sstevel@tonic-gate * The consconfig_dacf module need this interface to detect if the
9957c478bd9Sstevel@tonic-gate * device is already disconnnected.
9967c478bd9Sstevel@tonic-gate */
9975321cfb7Spengcheng chen - Sun Microsystems - Beijing China if (HID_IS_INTERNAL_OPEN(minor) &&
9985321cfb7Spengcheng chen - Sun Microsystems - Beijing China (hidp->hid_dev_state == USB_DEV_DISCONNECTED)) {
9997c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
10007c478bd9Sstevel@tonic-gate return (ENODEV);
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate
1003ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_INTERNAL_OPEN(minor) &&
1004ddee57faSrui zang - Sun Microsystems - Beijing China (hidp->hid_internal_rq != NULL)) {
1005ddee57faSrui zang - Sun Microsystems - Beijing China ASSERT(hidp->hid_internal_rq == q);
1006ddee57faSrui zang - Sun Microsystems - Beijing China
1007ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1008ddee57faSrui zang - Sun Microsystems - Beijing China return (0);
1009ddee57faSrui zang - Sun Microsystems - Beijing China }
1010ddee57faSrui zang - Sun Microsystems - Beijing China
1011ddee57faSrui zang - Sun Microsystems - Beijing China if ((!HID_IS_INTERNAL_OPEN(minor)) &&
1012ddee57faSrui zang - Sun Microsystems - Beijing China (hidp->hid_external_rq != NULL)) {
1013ddee57faSrui zang - Sun Microsystems - Beijing China ASSERT(hidp->hid_external_rq == q);
1014ddee57faSrui zang - Sun Microsystems - Beijing China
1015ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1016ddee57faSrui zang - Sun Microsystems - Beijing China return (0);
1017ac9468f8Spengcheng chen - Sun Microsystems - Beijing China }
1018ddee57faSrui zang - Sun Microsystems - Beijing China
1019ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
10207c478bd9Sstevel@tonic-gate
1021ddee57faSrui zang - Sun Microsystems - Beijing China q->q_ptr = hidp;
1022ddee57faSrui zang - Sun Microsystems - Beijing China WR(q)->q_ptr = hidp;
10237c478bd9Sstevel@tonic-gate
1024ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
1025ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_inuse_rq != NULL) {
1026ddee57faSrui zang - Sun Microsystems - Beijing China /* Pipe has already been setup */
1027ddee57faSrui zang - Sun Microsystems - Beijing China
1028ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_INTERNAL_OPEN(minor)) {
1029ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_flag = HID_STREAMS_OPEN;
1030ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = hidp->hid_internal_rq = q;
1031ddee57faSrui zang - Sun Microsystems - Beijing China } else {
1032ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_flag = HID_STREAMS_OPEN;
1033ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = hidp->hid_external_rq = q;
1034ddee57faSrui zang - Sun Microsystems - Beijing China }
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
1037ddee57faSrui zang - Sun Microsystems - Beijing China
1038ac9468f8Spengcheng chen - Sun Microsystems - Beijing China qprocson(q);
1039ddee57faSrui zang - Sun Microsystems - Beijing China
1040ac9468f8Spengcheng chen - Sun Microsystems - Beijing China return (0);
10417c478bd9Sstevel@tonic-gate }
10427c478bd9Sstevel@tonic-gate
1043ddee57faSrui zang - Sun Microsystems - Beijing China /* Pipe only needs to be opened once */
1044ac9468f8Spengcheng chen - Sun Microsystems - Beijing China hidp->hid_interrupt_pipe = NULL;
1045ac9468f8Spengcheng chen - Sun Microsystems - Beijing China no_of_ep = hidp->hid_if_descr.bNumEndpoints;
1046ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
10477c478bd9Sstevel@tonic-gate
1048ac9468f8Spengcheng chen - Sun Microsystems - Beijing China /* Check if interrupt endpoint exists */
1049ac9468f8Spengcheng chen - Sun Microsystems - Beijing China if (no_of_ep > 0) {
1050ac9468f8Spengcheng chen - Sun Microsystems - Beijing China /* Open the interrupt pipe */
1051993e3fafSRobert Mustacchi if (usb_pipe_xopen(hidp->hid_dip,
1052993e3fafSRobert Mustacchi &hidp->hid_ep_intr_xdescr,
1053ac9468f8Spengcheng chen - Sun Microsystems - Beijing China &hidp->hid_intr_pipe_policy, USB_FLAGS_SLEEP,
1054ac9468f8Spengcheng chen - Sun Microsystems - Beijing China &hidp->hid_interrupt_pipe) !=
1055ac9468f8Spengcheng chen - Sun Microsystems - Beijing China USB_SUCCESS) {
10567c478bd9Sstevel@tonic-gate
1057ac9468f8Spengcheng chen - Sun Microsystems - Beijing China q->q_ptr = NULL;
1058ac9468f8Spengcheng chen - Sun Microsystems - Beijing China WR(q)->q_ptr = NULL;
1059ac9468f8Spengcheng chen - Sun Microsystems - Beijing China return (EIO);
10607c478bd9Sstevel@tonic-gate }
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate
10637c478bd9Sstevel@tonic-gate hid_pm_busy_component(hidp);
10647c478bd9Sstevel@tonic-gate (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
1067ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_INTERNAL_OPEN(minor)) {
1068ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_flag = HID_STREAMS_OPEN;
1069ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = hidp->hid_internal_rq = q;
1070ddee57faSrui zang - Sun Microsystems - Beijing China } else {
1071ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_flag = HID_STREAMS_OPEN;
1072ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = hidp->hid_external_rq = q;
1073ddee57faSrui zang - Sun Microsystems - Beijing China }
1074ddee57faSrui zang - Sun Microsystems - Beijing China
10757c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
10767c478bd9Sstevel@tonic-gate
10777c478bd9Sstevel@tonic-gate qprocson(q);
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
10807c478bd9Sstevel@tonic-gate
10817c478bd9Sstevel@tonic-gate if ((rval = hid_start_intr_polling(hidp)) != USB_SUCCESS) {
10827c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_OPEN, hidp->hid_log_handle,
10837c478bd9Sstevel@tonic-gate "unable to start intr pipe polling. rval = %d", rval);
10847c478bd9Sstevel@tonic-gate
1085ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_INTERNAL_OPEN(minor))
1086ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_flag = HID_STREAMS_DISMANTLING;
1087ddee57faSrui zang - Sun Microsystems - Beijing China else
1088ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_flag = HID_STREAMS_DISMANTLING;
10897c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
10907c478bd9Sstevel@tonic-gate
10917c478bd9Sstevel@tonic-gate usb_pipe_close(hidp->hid_dip, hidp->hid_interrupt_pipe,
10927c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL);
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
10957c478bd9Sstevel@tonic-gate hidp->hid_interrupt_pipe = NULL;
10967c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate qprocsoff(q);
1099ddee57faSrui zang - Sun Microsystems - Beijing China
1100ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
1101ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_INTERNAL_OPEN(minor)) {
1102ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_flag = 0;
1103ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_rq = NULL;
1104ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_external_flag == HID_STREAMS_OPEN)
1105ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = hidp->hid_external_rq;
1106ddee57faSrui zang - Sun Microsystems - Beijing China else
1107ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = NULL;
1108ddee57faSrui zang - Sun Microsystems - Beijing China } else {
1109ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_flag = 0;
1110ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_rq = NULL;
1111ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_internal_flag == HID_STREAMS_OPEN)
1112ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = hidp->hid_internal_rq;
1113ddee57faSrui zang - Sun Microsystems - Beijing China else
1114ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = NULL;
1115ddee57faSrui zang - Sun Microsystems - Beijing China }
1116ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1117ddee57faSrui zang - Sun Microsystems - Beijing China
1118ac9468f8Spengcheng chen - Sun Microsystems - Beijing China q->q_ptr = NULL;
1119ac9468f8Spengcheng chen - Sun Microsystems - Beijing China WR(q)->q_ptr = NULL;
1120ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
11217c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
11227c478bd9Sstevel@tonic-gate
11237c478bd9Sstevel@tonic-gate return (EIO);
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle, "hid_open: End");
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate /*
11307c478bd9Sstevel@tonic-gate * Keyboard and mouse is Power managed by device activity.
11317c478bd9Sstevel@tonic-gate * All other devices go busy on open and idle on close.
11327c478bd9Sstevel@tonic-gate */
11337c478bd9Sstevel@tonic-gate switch (hidp->hid_pm->hid_pm_strategy) {
11347c478bd9Sstevel@tonic-gate case HID_PM_ACTIVITY:
11357c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
11367c478bd9Sstevel@tonic-gate
11377c478bd9Sstevel@tonic-gate break;
11387c478bd9Sstevel@tonic-gate default:
11397c478bd9Sstevel@tonic-gate
11407c478bd9Sstevel@tonic-gate break;
11417c478bd9Sstevel@tonic-gate }
11427c478bd9Sstevel@tonic-gate
11437c478bd9Sstevel@tonic-gate return (0);
11447c478bd9Sstevel@tonic-gate }
11457c478bd9Sstevel@tonic-gate
11467c478bd9Sstevel@tonic-gate
11477c478bd9Sstevel@tonic-gate /*
11487c478bd9Sstevel@tonic-gate * hid_close :
11497c478bd9Sstevel@tonic-gate * Close entry point.
11507c478bd9Sstevel@tonic-gate */
11517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11527c478bd9Sstevel@tonic-gate static int
hid_close(queue_t * q,int flag,cred_t * credp)11537c478bd9Sstevel@tonic-gate hid_close(queue_t *q, int flag, cred_t *credp)
11547c478bd9Sstevel@tonic-gate {
1155ddee57faSrui zang - Sun Microsystems - Beijing China hid_state_t *hidp = (hid_state_t *)q->q_ptr;
11567c478bd9Sstevel@tonic-gate queue_t *wq;
11577c478bd9Sstevel@tonic-gate mblk_t *mp;
11587c478bd9Sstevel@tonic-gate
11597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle, "hid_close:");
11607c478bd9Sstevel@tonic-gate
11617c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
1162ddee57faSrui zang - Sun Microsystems - Beijing China
1163ddee57faSrui zang - Sun Microsystems - Beijing China ASSERT((hidp->hid_internal_rq == q) ||
1164ddee57faSrui zang - Sun Microsystems - Beijing China (hidp->hid_external_rq == q));
1165ddee57faSrui zang - Sun Microsystems - Beijing China
1166ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_internal_rq == q)
1167ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_flag = HID_STREAMS_DISMANTLING;
1168ddee57faSrui zang - Sun Microsystems - Beijing China else
1169ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_flag = HID_STREAMS_DISMANTLING;
1170ddee57faSrui zang - Sun Microsystems - Beijing China
11717c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate /*
11747c478bd9Sstevel@tonic-gate * In case there are any outstanding requests on
11757c478bd9Sstevel@tonic-gate * the default pipe, wait forever for them to complete.
11767c478bd9Sstevel@tonic-gate */
11777c478bd9Sstevel@tonic-gate (void) usb_pipe_drain_reqs(hidp->hid_dip,
11787c478bd9Sstevel@tonic-gate hidp->hid_default_pipe, 0, USB_FLAGS_SLEEP, NULL, 0);
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
1181ac9468f8Spengcheng chen - Sun Microsystems - Beijing China wq = WR(q);
1182ac9468f8Spengcheng chen - Sun Microsystems - Beijing China /* drain any M_CTLS on the WQ */
11837c478bd9Sstevel@tonic-gate while (mp = getq(wq)) {
11847c478bd9Sstevel@tonic-gate hid_qreply_merror(wq, mp, EIO);
11857c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
11867c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
11877c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
11887c478bd9Sstevel@tonic-gate }
11897c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate qprocsoff(q);
1192ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
11937c478bd9Sstevel@tonic-gate q->q_ptr = NULL;
1194ac9468f8Spengcheng chen - Sun Microsystems - Beijing China wq->q_ptr = NULL;
1195ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
1196ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
1197ddee57faSrui zang - Sun Microsystems - Beijing China
1198ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_internal_rq == q) {
1199ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_rq = NULL;
1200ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_internal_flag = 0;
1201ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_inuse_rq == q) {
1202ddee57faSrui zang - Sun Microsystems - Beijing China /* We are closing the active stream */
1203ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_external_flag == HID_STREAMS_OPEN)
1204ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = hidp->hid_external_rq;
1205ddee57faSrui zang - Sun Microsystems - Beijing China else
1206ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = NULL;
1207ddee57faSrui zang - Sun Microsystems - Beijing China }
1208ac9468f8Spengcheng chen - Sun Microsystems - Beijing China } else {
1209ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_rq = NULL;
1210ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_flag = 0;
1211ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_inuse_rq == q) {
1212ddee57faSrui zang - Sun Microsystems - Beijing China /* We are closing the active stream */
1213ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_internal_flag == HID_STREAMS_OPEN)
1214ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = hidp->hid_internal_rq;
1215ddee57faSrui zang - Sun Microsystems - Beijing China else
1216ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = NULL;
1217ddee57faSrui zang - Sun Microsystems - Beijing China }
1218ac9468f8Spengcheng chen - Sun Microsystems - Beijing China }
1219ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
1220ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_inuse_rq != NULL) {
1221ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1222ac9468f8Spengcheng chen - Sun Microsystems - Beijing China return (0);
1223ac9468f8Spengcheng chen - Sun Microsystems - Beijing China }
1224ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
1225ac9468f8Spengcheng chen - Sun Microsystems - Beijing China /* all queues are closed, close USB pipes */
1226ac9468f8Spengcheng chen - Sun Microsystems - Beijing China hid_close_intr_pipe(hidp);
1227ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate /*
12307c478bd9Sstevel@tonic-gate * Devices other than keyboard/mouse go idle on close.
12317c478bd9Sstevel@tonic-gate */
12327c478bd9Sstevel@tonic-gate switch (hidp->hid_pm->hid_pm_strategy) {
12337c478bd9Sstevel@tonic-gate case HID_PM_ACTIVITY:
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate break;
12367c478bd9Sstevel@tonic-gate default:
12377c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
12387c478bd9Sstevel@tonic-gate
12397c478bd9Sstevel@tonic-gate break;
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
12427c478bd9Sstevel@tonic-gate "hid_close: End");
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate return (0);
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate
12477c478bd9Sstevel@tonic-gate
12487c478bd9Sstevel@tonic-gate /*
12497c478bd9Sstevel@tonic-gate * hid_wput :
12507c478bd9Sstevel@tonic-gate * write put routine for the hid module
12517c478bd9Sstevel@tonic-gate */
12527c478bd9Sstevel@tonic-gate static int
hid_wput(queue_t * q,mblk_t * mp)12537c478bd9Sstevel@tonic-gate hid_wput(queue_t *q, mblk_t *mp)
12547c478bd9Sstevel@tonic-gate {
1255ddee57faSrui zang - Sun Microsystems - Beijing China hid_state_t *hidp = (hid_state_t *)q->q_ptr;
12567c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
1257db1c88f6SSebastian Wiedenroth struct iocblk *iocbp;
1258ddee57faSrui zang - Sun Microsystems - Beijing China mblk_t *datap;
1259ddee57faSrui zang - Sun Microsystems - Beijing China int direction;
1260ddee57faSrui zang - Sun Microsystems - Beijing China struct copyresp *crp;
1261db1c88f6SSebastian Wiedenroth queue_t *tmpq;
1262ddee57faSrui zang - Sun Microsystems - Beijing China int flag;
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
12657c478bd9Sstevel@tonic-gate "hid_wput: Begin");
12667c478bd9Sstevel@tonic-gate
12677c478bd9Sstevel@tonic-gate /* See if the upper module is passing the right thing */
12687c478bd9Sstevel@tonic-gate ASSERT(mp != NULL);
12697c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap != NULL);
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
12727c478bd9Sstevel@tonic-gate case M_FLUSH: /* Canonical flush handling */
12737c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
12747c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA);
12757c478bd9Sstevel@tonic-gate }
12767c478bd9Sstevel@tonic-gate
12777c478bd9Sstevel@tonic-gate /* read queue not used so just send up */
12787c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
12797c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
12807c478bd9Sstevel@tonic-gate qreply(q, mp);
12817c478bd9Sstevel@tonic-gate } else {
12827c478bd9Sstevel@tonic-gate freemsg(mp);
12837c478bd9Sstevel@tonic-gate }
12847c478bd9Sstevel@tonic-gate
12857c478bd9Sstevel@tonic-gate break;
12867c478bd9Sstevel@tonic-gate case M_IOCTL:
1287ddee57faSrui zang - Sun Microsystems - Beijing China iocbp = (struct iocblk *)mp->b_rptr;
1288ddee57faSrui zang - Sun Microsystems - Beijing China
1289ddee57faSrui zang - Sun Microsystems - Beijing China /* Only accept transparent ioctls */
1290ddee57faSrui zang - Sun Microsystems - Beijing China if (iocbp->ioc_count != TRANSPARENT) {
1291ddee57faSrui zang - Sun Microsystems - Beijing China miocnak(q, mp, 0, EINVAL);
1292ddee57faSrui zang - Sun Microsystems - Beijing China break;
1293ddee57faSrui zang - Sun Microsystems - Beijing China }
1294ddee57faSrui zang - Sun Microsystems - Beijing China
1295ddee57faSrui zang - Sun Microsystems - Beijing China switch (iocbp->ioc_cmd) {
1296ddee57faSrui zang - Sun Microsystems - Beijing China case HIDIOCKMGDIRECT:
1297ddee57faSrui zang - Sun Microsystems - Beijing China
1298ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
1299ddee57faSrui zang - Sun Microsystems - Beijing China ASSERT(hidp->hid_inuse_rq != NULL);
1300ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1301ddee57faSrui zang - Sun Microsystems - Beijing China
1302ddee57faSrui zang - Sun Microsystems - Beijing China if ((datap = allocb(sizeof (int), BPRI_MED)) == NULL) {
1303ddee57faSrui zang - Sun Microsystems - Beijing China miocnak(q, mp, 0, ENOMEM);
1304ddee57faSrui zang - Sun Microsystems - Beijing China break;
1305ddee57faSrui zang - Sun Microsystems - Beijing China }
1306ddee57faSrui zang - Sun Microsystems - Beijing China
1307ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
1308ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_inuse_rq == hidp->hid_internal_rq) {
1309ddee57faSrui zang - Sun Microsystems - Beijing China *(int *)datap->b_wptr = 0;
1310ddee57faSrui zang - Sun Microsystems - Beijing China datap->b_wptr += sizeof (int);
1311ddee57faSrui zang - Sun Microsystems - Beijing China } else {
1312ddee57faSrui zang - Sun Microsystems - Beijing China ASSERT(hidp->hid_inuse_rq ==
1313ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_rq);
1314ddee57faSrui zang - Sun Microsystems - Beijing China *(int *)datap->b_wptr = 1;
1315ddee57faSrui zang - Sun Microsystems - Beijing China datap->b_wptr += sizeof (int);
1316ddee57faSrui zang - Sun Microsystems - Beijing China }
1317ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1318ddee57faSrui zang - Sun Microsystems - Beijing China
1319ddee57faSrui zang - Sun Microsystems - Beijing China mcopyout(mp, NULL, sizeof (int), NULL, datap);
1320ddee57faSrui zang - Sun Microsystems - Beijing China qreply(q, mp);
1321ddee57faSrui zang - Sun Microsystems - Beijing China break;
1322ddee57faSrui zang - Sun Microsystems - Beijing China
1323ddee57faSrui zang - Sun Microsystems - Beijing China case HIDIOCKMSDIRECT:
1324ddee57faSrui zang - Sun Microsystems - Beijing China mcopyin(mp, NULL, sizeof (int), NULL);
1325ddee57faSrui zang - Sun Microsystems - Beijing China qreply(q, mp);
1326ddee57faSrui zang - Sun Microsystems - Beijing China break;
1327ddee57faSrui zang - Sun Microsystems - Beijing China
1328ddee57faSrui zang - Sun Microsystems - Beijing China default:
1329ddee57faSrui zang - Sun Microsystems - Beijing China miocnak(q, mp, 0, ENOTTY);
1330ddee57faSrui zang - Sun Microsystems - Beijing China }
1331ddee57faSrui zang - Sun Microsystems - Beijing China
1332ddee57faSrui zang - Sun Microsystems - Beijing China break;
1333ddee57faSrui zang - Sun Microsystems - Beijing China
1334ddee57faSrui zang - Sun Microsystems - Beijing China case M_IOCDATA:
1335ddee57faSrui zang - Sun Microsystems - Beijing China
1336ddee57faSrui zang - Sun Microsystems - Beijing China crp = (void *)mp->b_rptr;
1337ddee57faSrui zang - Sun Microsystems - Beijing China
1338ddee57faSrui zang - Sun Microsystems - Beijing China if (crp->cp_rval != 0) {
1339ddee57faSrui zang - Sun Microsystems - Beijing China miocnak(q, mp, 0, EIO);
1340ddee57faSrui zang - Sun Microsystems - Beijing China break;
1341ddee57faSrui zang - Sun Microsystems - Beijing China }
1342ddee57faSrui zang - Sun Microsystems - Beijing China
1343ddee57faSrui zang - Sun Microsystems - Beijing China switch (crp->cp_cmd) {
1344ddee57faSrui zang - Sun Microsystems - Beijing China case HIDIOCKMGDIRECT:
1345ddee57faSrui zang - Sun Microsystems - Beijing China miocack(q, mp, 0, 0);
1346ddee57faSrui zang - Sun Microsystems - Beijing China break;
1347ddee57faSrui zang - Sun Microsystems - Beijing China
1348ddee57faSrui zang - Sun Microsystems - Beijing China case HIDIOCKMSDIRECT:
1349ddee57faSrui zang - Sun Microsystems - Beijing China direction = *(int *)mp->b_cont->b_rptr;
1350ddee57faSrui zang - Sun Microsystems - Beijing China
1351ddee57faSrui zang - Sun Microsystems - Beijing China if ((direction != 0) && (direction != 1)) {
1352ddee57faSrui zang - Sun Microsystems - Beijing China miocnak(q, mp, 0, EINVAL);
1353ddee57faSrui zang - Sun Microsystems - Beijing China break;
1354ddee57faSrui zang - Sun Microsystems - Beijing China }
1355ddee57faSrui zang - Sun Microsystems - Beijing China
1356ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
1357ddee57faSrui zang - Sun Microsystems - Beijing China
1358ddee57faSrui zang - Sun Microsystems - Beijing China if (direction == 0) {
1359ddee57faSrui zang - Sun Microsystems - Beijing China /* The internal stream is made active */
1360ddee57faSrui zang - Sun Microsystems - Beijing China flag = hidp->hid_internal_flag;
1361ddee57faSrui zang - Sun Microsystems - Beijing China tmpq = hidp->hid_internal_rq;
1362ddee57faSrui zang - Sun Microsystems - Beijing China } else {
1363ddee57faSrui zang - Sun Microsystems - Beijing China /* The external stream is made active */
1364ddee57faSrui zang - Sun Microsystems - Beijing China flag = hidp->hid_external_flag;
1365ddee57faSrui zang - Sun Microsystems - Beijing China tmpq = hidp->hid_external_rq;
1366ddee57faSrui zang - Sun Microsystems - Beijing China }
1367ddee57faSrui zang - Sun Microsystems - Beijing China
1368ddee57faSrui zang - Sun Microsystems - Beijing China if (flag != HID_STREAMS_OPEN) {
1369ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1370ddee57faSrui zang - Sun Microsystems - Beijing China miocnak(q, mp, 0, EIO);
1371ddee57faSrui zang - Sun Microsystems - Beijing China break;
1372ddee57faSrui zang - Sun Microsystems - Beijing China }
1373ddee57faSrui zang - Sun Microsystems - Beijing China
1374ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_inuse_rq = tmpq;
1375ddee57faSrui zang - Sun Microsystems - Beijing China
1376ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1377ddee57faSrui zang - Sun Microsystems - Beijing China miocack(q, mp, 0, 0);
1378ddee57faSrui zang - Sun Microsystems - Beijing China break;
1379ddee57faSrui zang - Sun Microsystems - Beijing China
1380ddee57faSrui zang - Sun Microsystems - Beijing China default:
1381ddee57faSrui zang - Sun Microsystems - Beijing China miocnak(q, mp, 0, ENOTTY);
1382ddee57faSrui zang - Sun Microsystems - Beijing China break;
1383ddee57faSrui zang - Sun Microsystems - Beijing China }
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate break;
1386ddee57faSrui zang - Sun Microsystems - Beijing China
13877c478bd9Sstevel@tonic-gate case M_CTL:
13887c478bd9Sstevel@tonic-gate /* we are busy now */
13897c478bd9Sstevel@tonic-gate hid_pm_busy_component(hidp);
13907c478bd9Sstevel@tonic-gate
13917c478bd9Sstevel@tonic-gate if (q->q_first) {
13927c478bd9Sstevel@tonic-gate (void) putq(q, mp);
13937c478bd9Sstevel@tonic-gate } else {
13947c478bd9Sstevel@tonic-gate error = hid_mctl_receive(q, mp);
13957c478bd9Sstevel@tonic-gate switch (error) {
13967c478bd9Sstevel@tonic-gate case HID_ENQUEUE:
13977c478bd9Sstevel@tonic-gate /*
13987c478bd9Sstevel@tonic-gate * put this mblk on the WQ for the wsrv to
13997c478bd9Sstevel@tonic-gate * process
14007c478bd9Sstevel@tonic-gate */
14017c478bd9Sstevel@tonic-gate (void) putq(q, mp);
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate break;
14047c478bd9Sstevel@tonic-gate case HID_INPROGRESS:
14057c478bd9Sstevel@tonic-gate /* request has been queued to the device */
14067c478bd9Sstevel@tonic-gate
14077c478bd9Sstevel@tonic-gate break;
14087c478bd9Sstevel@tonic-gate case HID_SUCCESS:
14097c478bd9Sstevel@tonic-gate /*
14107c478bd9Sstevel@tonic-gate * returned by M_CTLS that are processed
14117c478bd9Sstevel@tonic-gate * immediately
14127c478bd9Sstevel@tonic-gate */
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate /* FALLTHRU */
14157c478bd9Sstevel@tonic-gate case HID_FAILURE:
14167c478bd9Sstevel@tonic-gate default:
14177c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
14187c478bd9Sstevel@tonic-gate break;
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate }
14217c478bd9Sstevel@tonic-gate break;
14227c478bd9Sstevel@tonic-gate default:
14237c478bd9Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
14247c478bd9Sstevel@tonic-gate error = USB_FAILURE;
14257c478bd9Sstevel@tonic-gate break;
14267c478bd9Sstevel@tonic-gate }
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14297c478bd9Sstevel@tonic-gate "hid_wput: End");
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
14327c478bd9Sstevel@tonic-gate }
14337c478bd9Sstevel@tonic-gate
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate /*
14367c478bd9Sstevel@tonic-gate * hid_wsrv :
14377c478bd9Sstevel@tonic-gate * Write service routine for hid. When a message arrives through
14387c478bd9Sstevel@tonic-gate * hid_wput(), it is kept in write queue to be serviced later.
14397c478bd9Sstevel@tonic-gate */
14407c478bd9Sstevel@tonic-gate static int
hid_wsrv(queue_t * q)14417c478bd9Sstevel@tonic-gate hid_wsrv(queue_t *q)
14427c478bd9Sstevel@tonic-gate {
1443ddee57faSrui zang - Sun Microsystems - Beijing China hid_state_t *hidp = (hid_state_t *)q->q_ptr;
14447c478bd9Sstevel@tonic-gate int error;
14457c478bd9Sstevel@tonic-gate mblk_t *mp;
14467c478bd9Sstevel@tonic-gate
14477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14487c478bd9Sstevel@tonic-gate "hid_wsrv: Begin");
14497c478bd9Sstevel@tonic-gate
14507c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
14517c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14527c478bd9Sstevel@tonic-gate "hid_wsrv: dev_state: %s",
14537c478bd9Sstevel@tonic-gate usb_str_dev_state(hidp->hid_dev_state));
14547c478bd9Sstevel@tonic-gate
14557c478bd9Sstevel@tonic-gate /*
14567c478bd9Sstevel@tonic-gate * raise power if we are powered down. It is OK to block here since
14577c478bd9Sstevel@tonic-gate * we have a separate thread to process this STREAM
14587c478bd9Sstevel@tonic-gate */
14597c478bd9Sstevel@tonic-gate if (hidp->hid_dev_state == USB_DEV_PWRED_DOWN) {
14607c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
14617c478bd9Sstevel@tonic-gate (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
14627c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate /*
14667c478bd9Sstevel@tonic-gate * continue servicing all the M_CTL's till the queue is empty
14677c478bd9Sstevel@tonic-gate * or the device gets disconnected or till a hid_close()
14687c478bd9Sstevel@tonic-gate */
14697c478bd9Sstevel@tonic-gate while ((hidp->hid_dev_state == USB_DEV_ONLINE) &&
1470ddee57faSrui zang - Sun Microsystems - Beijing China (HID_STREAMS_FLAG(q, hidp) != HID_STREAMS_DISMANTLING) &&
14717c478bd9Sstevel@tonic-gate ((mp = getq(q)) != NULL)) {
14727c478bd9Sstevel@tonic-gate
14737c478bd9Sstevel@tonic-gate /* Send a message down */
14747c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
14757c478bd9Sstevel@tonic-gate error = hid_mctl_receive(q, mp);
14767c478bd9Sstevel@tonic-gate switch (error) {
14777c478bd9Sstevel@tonic-gate case HID_ENQUEUE:
14787c478bd9Sstevel@tonic-gate /* put this mblk back on q to preserve order */
14797c478bd9Sstevel@tonic-gate (void) putbq(q, mp);
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate break;
14827c478bd9Sstevel@tonic-gate case HID_INPROGRESS:
14837c478bd9Sstevel@tonic-gate /* request has been queued to the device */
14847c478bd9Sstevel@tonic-gate
14857c478bd9Sstevel@tonic-gate break;
14867c478bd9Sstevel@tonic-gate case HID_SUCCESS:
14877c478bd9Sstevel@tonic-gate case HID_FAILURE:
14887c478bd9Sstevel@tonic-gate default:
14897c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
14907c478bd9Sstevel@tonic-gate
14917c478bd9Sstevel@tonic-gate break;
14927c478bd9Sstevel@tonic-gate }
14937c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
14947c478bd9Sstevel@tonic-gate }
14957c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
14967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14977c478bd9Sstevel@tonic-gate "hid_wsrv: End");
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate
15037c478bd9Sstevel@tonic-gate /*
15047c478bd9Sstevel@tonic-gate * hid_power:
15057c478bd9Sstevel@tonic-gate * power entry point
15067c478bd9Sstevel@tonic-gate */
15077c478bd9Sstevel@tonic-gate static int
hid_power(dev_info_t * dip,int comp,int level)15087c478bd9Sstevel@tonic-gate hid_power(dev_info_t *dip, int comp, int level)
15097c478bd9Sstevel@tonic-gate {
15107c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
15117c478bd9Sstevel@tonic-gate hid_state_t *hidp;
15127c478bd9Sstevel@tonic-gate hid_power_t *hidpm;
15137c478bd9Sstevel@tonic-gate int retval;
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
15167c478bd9Sstevel@tonic-gate
15177c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_PM, hidp->hid_log_handle, "hid_power:"
15187c478bd9Sstevel@tonic-gate " hid_state: comp=%d level=%d", comp, level);
15197c478bd9Sstevel@tonic-gate
15207c478bd9Sstevel@tonic-gate /* check if we are transitioning to a legal power level */
15217c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
15227c478bd9Sstevel@tonic-gate hidpm = hidp->hid_pm;
15237c478bd9Sstevel@tonic-gate
15247c478bd9Sstevel@tonic-gate if (USB_DEV_PWRSTATE_OK(hidpm->hid_pwr_states, level)) {
15257c478bd9Sstevel@tonic-gate
15267c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM, hidp->hid_log_handle,
15277c478bd9Sstevel@tonic-gate "hid_power: illegal level=%d hid_pwr_states=%d",
15287c478bd9Sstevel@tonic-gate level, hidpm->hid_pwr_states);
15297c478bd9Sstevel@tonic-gate
15307c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
15317c478bd9Sstevel@tonic-gate
15327c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
15337c478bd9Sstevel@tonic-gate }
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate switch (level) {
15367c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_OFF:
15377c478bd9Sstevel@tonic-gate retval = hid_pwrlvl0(hidp);
15387c478bd9Sstevel@tonic-gate break;
15397c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_1:
15407c478bd9Sstevel@tonic-gate retval = hid_pwrlvl1(hidp);
15417c478bd9Sstevel@tonic-gate break;
15427c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_2:
15437c478bd9Sstevel@tonic-gate retval = hid_pwrlvl2(hidp);
15447c478bd9Sstevel@tonic-gate break;
15457c478bd9Sstevel@tonic-gate case USB_DEV_OS_FULL_PWR:
15467c478bd9Sstevel@tonic-gate retval = hid_pwrlvl3(hidp);
15477c478bd9Sstevel@tonic-gate break;
15487c478bd9Sstevel@tonic-gate default:
15497c478bd9Sstevel@tonic-gate retval = USB_FAILURE;
15507c478bd9Sstevel@tonic-gate break;
15517c478bd9Sstevel@tonic-gate }
15527c478bd9Sstevel@tonic-gate
15537c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate
15587c478bd9Sstevel@tonic-gate
15597c478bd9Sstevel@tonic-gate /*
15607c478bd9Sstevel@tonic-gate * hid_interrupt_pipe_callback:
15617c478bd9Sstevel@tonic-gate * Callback function for the hid intr pipe. This function is called by
15627c478bd9Sstevel@tonic-gate * USBA when a buffer has been filled. This driver does not cook the data,
15637c478bd9Sstevel@tonic-gate * it just sends the message up.
15647c478bd9Sstevel@tonic-gate */
15657c478bd9Sstevel@tonic-gate static void
hid_interrupt_pipe_callback(usb_pipe_handle_t pipe,usb_intr_req_t * req)15667c478bd9Sstevel@tonic-gate hid_interrupt_pipe_callback(usb_pipe_handle_t pipe, usb_intr_req_t *req)
15677c478bd9Sstevel@tonic-gate {
15687c478bd9Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)req->intr_client_private;
15697c478bd9Sstevel@tonic-gate queue_t *q;
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1572112116d8Sfb "hid_interrupt_pipe_callback: ph = 0x%p req = 0x%p",
1573112116d8Sfb (void *)pipe, (void *)req);
15747c478bd9Sstevel@tonic-gate
15757c478bd9Sstevel@tonic-gate hid_pm_busy_component(hidp);
15767c478bd9Sstevel@tonic-gate
15777c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
15787c478bd9Sstevel@tonic-gate
15797c478bd9Sstevel@tonic-gate /*
15807c478bd9Sstevel@tonic-gate * If hid_close() is in progress, we shouldn't try accessing queue
15817c478bd9Sstevel@tonic-gate * Otherwise indicate that a putnext is going to happen, so
15827c478bd9Sstevel@tonic-gate * if close after this, that should wait for the putnext to finish.
15837c478bd9Sstevel@tonic-gate */
1584ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_STREAMS_FLAG(hidp->hid_inuse_rq, hidp) ==
1585ddee57faSrui zang - Sun Microsystems - Beijing China HID_STREAMS_OPEN) {
15867c478bd9Sstevel@tonic-gate /*
15877c478bd9Sstevel@tonic-gate * Check if data can be put to the next queue.
15887c478bd9Sstevel@tonic-gate */
1589ddee57faSrui zang - Sun Microsystems - Beijing China if (!canputnext(hidp->hid_inuse_rq)) {
15907c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
15917c478bd9Sstevel@tonic-gate "Buffer flushed when overflowed.");
15927c478bd9Sstevel@tonic-gate
15937c478bd9Sstevel@tonic-gate /* Flush the queue above */
1594ddee57faSrui zang - Sun Microsystems - Beijing China hid_flush(hidp->hid_inuse_rq);
15957c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
15967c478bd9Sstevel@tonic-gate } else {
1597ddee57faSrui zang - Sun Microsystems - Beijing China q = hidp->hid_inuse_rq;
15987c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
15997c478bd9Sstevel@tonic-gate
16007c478bd9Sstevel@tonic-gate /* Put data upstream */
16017c478bd9Sstevel@tonic-gate putnext(q, req->intr_data);
16027c478bd9Sstevel@tonic-gate
16037c478bd9Sstevel@tonic-gate /* usb_free_intr_req should not free data */
16047c478bd9Sstevel@tonic-gate req->intr_data = NULL;
16057c478bd9Sstevel@tonic-gate }
16067c478bd9Sstevel@tonic-gate } else {
16077c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate /* free request and data */
16117c478bd9Sstevel@tonic-gate usb_free_intr_req(req);
16127c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate * hid_default_pipe_callback :
16187c478bd9Sstevel@tonic-gate * Callback routine for the asynchronous control transfer
16197c478bd9Sstevel@tonic-gate * Called from hid_send_async_ctrl_request() where we open
16207c478bd9Sstevel@tonic-gate * the pipe in exclusive mode
16217c478bd9Sstevel@tonic-gate */
16227c478bd9Sstevel@tonic-gate static void
hid_default_pipe_callback(usb_pipe_handle_t pipe,usb_ctrl_req_t * req)16237c478bd9Sstevel@tonic-gate hid_default_pipe_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *req)
16247c478bd9Sstevel@tonic-gate {
16257c478bd9Sstevel@tonic-gate hid_default_pipe_arg_t *hid_default_pipe_arg =
16267c478bd9Sstevel@tonic-gate (hid_default_pipe_arg_t *)req->ctrl_client_private;
1627ac9468f8Spengcheng chen - Sun Microsystems - Beijing China queue_t *wq = hid_default_pipe_arg->hid_default_pipe_arg_queue;
1628ac9468f8Spengcheng chen - Sun Microsystems - Beijing China queue_t *rq = RD(wq);
1629ddee57faSrui zang - Sun Microsystems - Beijing China hid_state_t *hidp = (hid_state_t *)rq->q_ptr;
16307c478bd9Sstevel@tonic-gate mblk_t *mctl_mp;
16317c478bd9Sstevel@tonic-gate mblk_t *data = NULL;
16327c478bd9Sstevel@tonic-gate
16337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
16347c478bd9Sstevel@tonic-gate "hid_default_pipe_callback: "
1635112116d8Sfb "ph = 0x%p, req = 0x%p, data= 0x%p",
1636112116d8Sfb (void *)pipe, (void *)req, (void *)data);
16377c478bd9Sstevel@tonic-gate
16387c478bd9Sstevel@tonic-gate ASSERT((req->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0);
16397c478bd9Sstevel@tonic-gate
16407c478bd9Sstevel@tonic-gate if (req->ctrl_data) {
16417c478bd9Sstevel@tonic-gate data = req->ctrl_data;
16427c478bd9Sstevel@tonic-gate req->ctrl_data = NULL;
16437c478bd9Sstevel@tonic-gate }
16447c478bd9Sstevel@tonic-gate
16457c478bd9Sstevel@tonic-gate /*
16467c478bd9Sstevel@tonic-gate * Free the b_cont of the original message that was sent down.
16477c478bd9Sstevel@tonic-gate */
16487c478bd9Sstevel@tonic-gate mctl_mp = hid_default_pipe_arg->hid_default_pipe_arg_mblk;
16497c478bd9Sstevel@tonic-gate freemsg(mctl_mp->b_cont);
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate /* chain the mblk received to the original & send it up */
16527c478bd9Sstevel@tonic-gate mctl_mp->b_cont = data;
1653ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
1654ac9468f8Spengcheng chen - Sun Microsystems - Beijing China if (canputnext(rq)) {
1655ac9468f8Spengcheng chen - Sun Microsystems - Beijing China putnext(rq, mctl_mp);
16567c478bd9Sstevel@tonic-gate } else {
16577c478bd9Sstevel@tonic-gate freemsg(mctl_mp); /* avoid leak */
16587c478bd9Sstevel@tonic-gate }
16597c478bd9Sstevel@tonic-gate
16607c478bd9Sstevel@tonic-gate /*
16617c478bd9Sstevel@tonic-gate * Free the argument for the asynchronous callback
16627c478bd9Sstevel@tonic-gate */
16637c478bd9Sstevel@tonic-gate kmem_free(hid_default_pipe_arg, sizeof (hid_default_pipe_arg_t));
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate /*
16667c478bd9Sstevel@tonic-gate * Free the control pipe request structure.
16677c478bd9Sstevel@tonic-gate */
16687c478bd9Sstevel@tonic-gate usb_free_ctrl_req(req);
16697c478bd9Sstevel@tonic-gate
16707c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
16717c478bd9Sstevel@tonic-gate hidp->hid_default_pipe_req--;
16727c478bd9Sstevel@tonic-gate ASSERT(hidp->hid_default_pipe_req >= 0);
16737c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
16747c478bd9Sstevel@tonic-gate
16757c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
1676ac9468f8Spengcheng chen - Sun Microsystems - Beijing China qenable(wq);
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate /*
16817c478bd9Sstevel@tonic-gate * hid_interrupt_pipe_exception_callback:
16827c478bd9Sstevel@tonic-gate * Exception callback routine for interrupt pipe. If there is any data,
16837c478bd9Sstevel@tonic-gate * destroy it. No threads are waiting for the exception callback.
16847c478bd9Sstevel@tonic-gate */
16857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16867c478bd9Sstevel@tonic-gate static void
hid_interrupt_pipe_exception_callback(usb_pipe_handle_t pipe,usb_intr_req_t * req)16877c478bd9Sstevel@tonic-gate hid_interrupt_pipe_exception_callback(usb_pipe_handle_t pipe,
16887c478bd9Sstevel@tonic-gate usb_intr_req_t *req)
16897c478bd9Sstevel@tonic-gate {
16907c478bd9Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)req->intr_client_private;
16917c478bd9Sstevel@tonic-gate mblk_t *data = req->intr_data;
16927c478bd9Sstevel@tonic-gate usb_cb_flags_t flags = req->intr_cb_flags;
16937c478bd9Sstevel@tonic-gate int rval;
16947c478bd9Sstevel@tonic-gate
16957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
16967c478bd9Sstevel@tonic-gate "hid_interrupt_pipe_exception_callback: "
16977c478bd9Sstevel@tonic-gate "completion_reason = 0x%x, data = 0x%p, flag = 0x%x",
16987c478bd9Sstevel@tonic-gate req->intr_completion_reason, (void *)data, req->intr_cb_flags);
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate ASSERT((req->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0);
17017c478bd9Sstevel@tonic-gate
17027c478bd9Sstevel@tonic-gate if (((flags & USB_CB_FUNCTIONAL_STALL) != 0) &&
17037c478bd9Sstevel@tonic-gate ((flags & USB_CB_STALL_CLEARED) == 0)) {
17047c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
17057c478bd9Sstevel@tonic-gate hidp->hid_log_handle,
17067c478bd9Sstevel@tonic-gate "hid_interrupt_pipe_exception_callback: "
17077c478bd9Sstevel@tonic-gate "unable to clear stall. flags = 0x%x",
17087c478bd9Sstevel@tonic-gate req->intr_cb_flags);
17097c478bd9Sstevel@tonic-gate }
17107c478bd9Sstevel@tonic-gate
17117c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
17127c478bd9Sstevel@tonic-gate
17137c478bd9Sstevel@tonic-gate switch (req->intr_completion_reason) {
17147c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING:
17157c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING:
17167c478bd9Sstevel@tonic-gate default:
17177c478bd9Sstevel@tonic-gate
17187c478bd9Sstevel@tonic-gate break;
17197c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET:
17207c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES:
17217c478bd9Sstevel@tonic-gate if ((hidp->hid_dev_state == USB_DEV_ONLINE) &&
17227c478bd9Sstevel@tonic-gate ((rval = hid_start_intr_polling(hidp)) !=
17237c478bd9Sstevel@tonic-gate USB_SUCCESS)) {
17247c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
17257c478bd9Sstevel@tonic-gate "unable to restart interrupt poll. rval = %d",
17267c478bd9Sstevel@tonic-gate rval);
17277c478bd9Sstevel@tonic-gate }
17287c478bd9Sstevel@tonic-gate
17297c478bd9Sstevel@tonic-gate break;
17307c478bd9Sstevel@tonic-gate }
17317c478bd9Sstevel@tonic-gate
17327c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
17337c478bd9Sstevel@tonic-gate
17347c478bd9Sstevel@tonic-gate usb_free_intr_req(req);
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate
17377c478bd9Sstevel@tonic-gate
17387c478bd9Sstevel@tonic-gate /*
17397c478bd9Sstevel@tonic-gate * hid_default_pipe_exception_callback:
17407c478bd9Sstevel@tonic-gate * Exception callback routine for default pipe.
17417c478bd9Sstevel@tonic-gate */
17427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17437c478bd9Sstevel@tonic-gate static void
hid_default_pipe_exception_callback(usb_pipe_handle_t pipe,usb_ctrl_req_t * req)17447c478bd9Sstevel@tonic-gate hid_default_pipe_exception_callback(usb_pipe_handle_t pipe,
17457c478bd9Sstevel@tonic-gate usb_ctrl_req_t *req)
17467c478bd9Sstevel@tonic-gate {
17477c478bd9Sstevel@tonic-gate hid_default_pipe_arg_t *hid_default_pipe_arg =
17487c478bd9Sstevel@tonic-gate (hid_default_pipe_arg_t *)req->ctrl_client_private;
1749ac9468f8Spengcheng chen - Sun Microsystems - Beijing China queue_t *wq = hid_default_pipe_arg->hid_default_pipe_arg_queue;
1750ac9468f8Spengcheng chen - Sun Microsystems - Beijing China queue_t *rq = RD(wq);
1751ddee57faSrui zang - Sun Microsystems - Beijing China hid_state_t *hidp = (hid_state_t *)rq->q_ptr;
17527c478bd9Sstevel@tonic-gate usb_cr_t ctrl_completion_reason = req->ctrl_completion_reason;
1753ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mblk_t *mp, *data = NULL;
17547c478bd9Sstevel@tonic-gate
17557c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
17567c478bd9Sstevel@tonic-gate "hid_default_pipe_exception_callback: "
17577c478bd9Sstevel@tonic-gate "completion_reason = 0x%x, data = 0x%p, flag = 0x%x",
17587c478bd9Sstevel@tonic-gate ctrl_completion_reason, (void *)data, req->ctrl_cb_flags);
17597c478bd9Sstevel@tonic-gate
17607c478bd9Sstevel@tonic-gate ASSERT((req->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0);
17617c478bd9Sstevel@tonic-gate
1762ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mp = hid_default_pipe_arg->hid_default_pipe_arg_mblk;
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate /*
17657c478bd9Sstevel@tonic-gate * Pass an error message up. Reuse existing mblk.
17667c478bd9Sstevel@tonic-gate */
1767ac9468f8Spengcheng chen - Sun Microsystems - Beijing China if (canputnext(rq)) {
17687c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR;
17697c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base;
17707c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char);
17717c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO;
1772ac9468f8Spengcheng chen - Sun Microsystems - Beijing China putnext(rq, mp);
17737c478bd9Sstevel@tonic-gate } else {
1774ac9468f8Spengcheng chen - Sun Microsystems - Beijing China freemsg(mp);
17757c478bd9Sstevel@tonic-gate }
1776ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
17777c478bd9Sstevel@tonic-gate kmem_free(hid_default_pipe_arg, sizeof (hid_default_pipe_arg_t));
17787c478bd9Sstevel@tonic-gate
17797c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
17807c478bd9Sstevel@tonic-gate hidp->hid_default_pipe_req--;
17817c478bd9Sstevel@tonic-gate ASSERT(hidp->hid_default_pipe_req >= 0);
17827c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
17837c478bd9Sstevel@tonic-gate
1784ac9468f8Spengcheng chen - Sun Microsystems - Beijing China qenable(wq);
17857c478bd9Sstevel@tonic-gate usb_free_ctrl_req(req);
17867c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
17877c478bd9Sstevel@tonic-gate }
17887c478bd9Sstevel@tonic-gate
17897c478bd9Sstevel@tonic-gate
17907c478bd9Sstevel@tonic-gate /*
17917c478bd9Sstevel@tonic-gate * event handling:
17927c478bd9Sstevel@tonic-gate *
17937c478bd9Sstevel@tonic-gate * hid_reconnect_event_callback:
17947c478bd9Sstevel@tonic-gate * the device was disconnected but this instance not detached, probably
17957c478bd9Sstevel@tonic-gate * because the device was busy
17967c478bd9Sstevel@tonic-gate *
17977c478bd9Sstevel@tonic-gate * If the same device, continue with restoring state
17987c478bd9Sstevel@tonic-gate */
17997c478bd9Sstevel@tonic-gate static int
hid_restore_state_event_callback(dev_info_t * dip)18007c478bd9Sstevel@tonic-gate hid_restore_state_event_callback(dev_info_t *dip)
18017c478bd9Sstevel@tonic-gate {
18027c478bd9Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)ddi_get_soft_state(hid_statep,
1803112116d8Sfb ddi_get_instance(dip));
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate ASSERT(hidp != NULL);
18067c478bd9Sstevel@tonic-gate
18077c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1808112116d8Sfb "hid_restore_state_event_callback: dip=0x%p", (void *)dip);
18097c478bd9Sstevel@tonic-gate
18107c478bd9Sstevel@tonic-gate hid_restore_device_state(dip, hidp);
18117c478bd9Sstevel@tonic-gate
18127c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
18137c478bd9Sstevel@tonic-gate }
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate
18167c478bd9Sstevel@tonic-gate /*
18177c478bd9Sstevel@tonic-gate * hid_cpr_suspend
18187c478bd9Sstevel@tonic-gate * Fail suspend if we can't finish outstanding i/o activity.
18197c478bd9Sstevel@tonic-gate */
18207c478bd9Sstevel@tonic-gate static int
hid_cpr_suspend(hid_state_t * hidp)18217c478bd9Sstevel@tonic-gate hid_cpr_suspend(hid_state_t *hidp)
18227c478bd9Sstevel@tonic-gate {
18237c478bd9Sstevel@tonic-gate int rval, prev_state;
18247c478bd9Sstevel@tonic-gate int retval = USB_FAILURE;
18257c478bd9Sstevel@tonic-gate
18267c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1827112116d8Sfb "hid_cpr_suspend: dip=0x%p", (void *)hidp->hid_dip);
18287c478bd9Sstevel@tonic-gate
18297c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
18307c478bd9Sstevel@tonic-gate switch (hidp->hid_dev_state) {
18317c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE:
18327c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
18337c478bd9Sstevel@tonic-gate prev_state = hidp->hid_dev_state;
18347c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_SUSPENDED;
18357c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
18367c478bd9Sstevel@tonic-gate
18377c478bd9Sstevel@tonic-gate /* drain all request outstanding on the default control pipe */
18387c478bd9Sstevel@tonic-gate rval = usb_pipe_drain_reqs(hidp->hid_dip,
18397c478bd9Sstevel@tonic-gate hidp->hid_default_pipe, hid_default_pipe_drain_timeout,
18407c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, 0);
18417c478bd9Sstevel@tonic-gate
18427c478bd9Sstevel@tonic-gate /* fail checkpoint if we haven't finished the job yet */
18437c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
18447c478bd9Sstevel@tonic-gate if ((rval != USB_SUCCESS) || (hidp->hid_default_pipe_req > 0)) {
18457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
18467c478bd9Sstevel@tonic-gate "hid_cpr_suspend: "
18477c478bd9Sstevel@tonic-gate "device busy - can't checkpoint");
18487c478bd9Sstevel@tonic-gate
18497c478bd9Sstevel@tonic-gate /* fall back to previous state */
18507c478bd9Sstevel@tonic-gate hidp->hid_dev_state = prev_state;
18517c478bd9Sstevel@tonic-gate } else {
18527c478bd9Sstevel@tonic-gate retval = USB_SUCCESS;
18537c478bd9Sstevel@tonic-gate hid_save_device_state(hidp);
18547c478bd9Sstevel@tonic-gate }
18557c478bd9Sstevel@tonic-gate
1856f67c0a39Sfei feng - Sun Microsystems - Beijing China break;
1857f67c0a39Sfei feng - Sun Microsystems - Beijing China case USB_DEV_DISCONNECTED:
1858f67c0a39Sfei feng - Sun Microsystems - Beijing China hidp->hid_dev_state = USB_DEV_SUSPENDED;
1859f67c0a39Sfei feng - Sun Microsystems - Beijing China hid_save_device_state(hidp);
1860f67c0a39Sfei feng - Sun Microsystems - Beijing China retval = USB_SUCCESS;
18617c478bd9Sstevel@tonic-gate break;
18627c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED:
18637c478bd9Sstevel@tonic-gate default:
18647c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
18657c478bd9Sstevel@tonic-gate "hid_cpr_suspend: Illegal dev state: %d",
18667c478bd9Sstevel@tonic-gate hidp->hid_dev_state);
18677c478bd9Sstevel@tonic-gate
18687c478bd9Sstevel@tonic-gate break;
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
18717c478bd9Sstevel@tonic-gate
1872*cfe80fe3SAlex Wilson if ((retval == USB_SUCCESS) && hidp->hid_ugen_hdl != NULL) {
1873*cfe80fe3SAlex Wilson retval = usb_ugen_detach(hidp->hid_ugen_hdl,
1874*cfe80fe3SAlex Wilson DDI_SUSPEND);
1875*cfe80fe3SAlex Wilson }
1876*cfe80fe3SAlex Wilson
18777c478bd9Sstevel@tonic-gate return (retval);
18787c478bd9Sstevel@tonic-gate }
18797c478bd9Sstevel@tonic-gate
18807c478bd9Sstevel@tonic-gate
18817c478bd9Sstevel@tonic-gate static void
hid_cpr_resume(hid_state_t * hidp)18827c478bd9Sstevel@tonic-gate hid_cpr_resume(hid_state_t *hidp)
18837c478bd9Sstevel@tonic-gate {
18847c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1885112116d8Sfb "hid_cpr_resume: dip=0x%p", (void *)hidp->hid_dip);
18867c478bd9Sstevel@tonic-gate
18877c478bd9Sstevel@tonic-gate hid_restore_device_state(hidp->hid_dip, hidp);
1888*cfe80fe3SAlex Wilson
1889*cfe80fe3SAlex Wilson if (hidp->hid_ugen_hdl != NULL) {
1890*cfe80fe3SAlex Wilson (void) usb_ugen_attach(hidp->hid_ugen_hdl, DDI_RESUME);
1891*cfe80fe3SAlex Wilson }
18927c478bd9Sstevel@tonic-gate }
18937c478bd9Sstevel@tonic-gate
18947c478bd9Sstevel@tonic-gate
18957c478bd9Sstevel@tonic-gate /*
18967c478bd9Sstevel@tonic-gate * hid_disconnect_event_callback:
18977c478bd9Sstevel@tonic-gate * The device has been disconnected. We either wait for
18987c478bd9Sstevel@tonic-gate * detach or a reconnect event. Close all pipes and timeouts.
18997c478bd9Sstevel@tonic-gate */
19007c478bd9Sstevel@tonic-gate static int
hid_disconnect_event_callback(dev_info_t * dip)19017c478bd9Sstevel@tonic-gate hid_disconnect_event_callback(dev_info_t *dip)
19027c478bd9Sstevel@tonic-gate {
19037c478bd9Sstevel@tonic-gate hid_state_t *hidp;
1904ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mblk_t *mp;
19057c478bd9Sstevel@tonic-gate
19067c478bd9Sstevel@tonic-gate hidp = (hid_state_t *)ddi_get_soft_state(hid_statep,
19077c478bd9Sstevel@tonic-gate ddi_get_instance(dip));
19087c478bd9Sstevel@tonic-gate ASSERT(hidp != NULL);
19097c478bd9Sstevel@tonic-gate
19107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1911112116d8Sfb "hid_disconnect_event_callback: dip=0x%p", (void *)dip);
19127c478bd9Sstevel@tonic-gate
19137c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
19147c478bd9Sstevel@tonic-gate switch (hidp->hid_dev_state) {
19157c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE:
19167c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
19177c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_DISCONNECTED;
1918ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_OPEN(hidp)) {
19197c478bd9Sstevel@tonic-gate
19207c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
19217c478bd9Sstevel@tonic-gate "busy device has been disconnected");
19227c478bd9Sstevel@tonic-gate }
19237c478bd9Sstevel@tonic-gate hid_save_device_state(hidp);
19247c478bd9Sstevel@tonic-gate
1925ac9468f8Spengcheng chen - Sun Microsystems - Beijing China /*
1926ac9468f8Spengcheng chen - Sun Microsystems - Beijing China * Notify applications about device removal, this only
1927ac9468f8Spengcheng chen - Sun Microsystems - Beijing China * applies to an external (aka. physical) open. For an
1928ac9468f8Spengcheng chen - Sun Microsystems - Beijing China * internal open, consconfig_dacf closes the queue.
1929ac9468f8Spengcheng chen - Sun Microsystems - Beijing China */
1930ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
1931ddee57faSrui zang - Sun Microsystems - Beijing China queue_t *q = hidp->hid_external_rq;
1932ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
1933ddee57faSrui zang - Sun Microsystems - Beijing China mp = allocb(sizeof (uchar_t), BPRI_HI);
1934ddee57faSrui zang - Sun Microsystems - Beijing China if (mp != NULL) {
1935ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_type = M_ERROR;
1936ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_rptr = mp->b_datap->db_base;
1937ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_wptr = mp->b_rptr + sizeof (char);
1938ddee57faSrui zang - Sun Microsystems - Beijing China *mp->b_rptr = ENODEV;
1939ddee57faSrui zang - Sun Microsystems - Beijing China putnext(q, mp);
1940ac9468f8Spengcheng chen - Sun Microsystems - Beijing China }
1941ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
1942ac9468f8Spengcheng chen - Sun Microsystems - Beijing China }
1943ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
19447c478bd9Sstevel@tonic-gate break;
19457c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED:
19467c478bd9Sstevel@tonic-gate /* we remain suspended */
19477c478bd9Sstevel@tonic-gate
19487c478bd9Sstevel@tonic-gate break;
19497c478bd9Sstevel@tonic-gate default:
19507c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
19517c478bd9Sstevel@tonic-gate "hid_disconnect_event_callback: Illegal dev state: %d",
19527c478bd9Sstevel@tonic-gate hidp->hid_dev_state);
19537c478bd9Sstevel@tonic-gate
19547c478bd9Sstevel@tonic-gate break;
19557c478bd9Sstevel@tonic-gate }
19567c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
19577c478bd9Sstevel@tonic-gate
19587c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate
19617c478bd9Sstevel@tonic-gate
19627c478bd9Sstevel@tonic-gate /*
19637c478bd9Sstevel@tonic-gate * hid_power_change_callback:
19647c478bd9Sstevel@tonic-gate * Async callback function to notify pm_raise_power completion
19657c478bd9Sstevel@tonic-gate * after hid_power entry point is called.
19667c478bd9Sstevel@tonic-gate */
19677c478bd9Sstevel@tonic-gate static void
hid_power_change_callback(void * arg,int rval)19687c478bd9Sstevel@tonic-gate hid_power_change_callback(void *arg, int rval)
19697c478bd9Sstevel@tonic-gate {
19707c478bd9Sstevel@tonic-gate hid_state_t *hidp;
19717c478bd9Sstevel@tonic-gate queue_t *wq;
19727c478bd9Sstevel@tonic-gate
19737c478bd9Sstevel@tonic-gate hidp = (hid_state_t *)arg;
19747c478bd9Sstevel@tonic-gate
19757c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
19767c478bd9Sstevel@tonic-gate "hid_power_change_callback - rval: %d", rval);
19777c478bd9Sstevel@tonic-gate
19787c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
19797c478bd9Sstevel@tonic-gate hidp->hid_pm->hid_raise_power = B_FALSE;
19807c478bd9Sstevel@tonic-gate
19817c478bd9Sstevel@tonic-gate if (hidp->hid_dev_state == USB_DEV_ONLINE) {
1982ddee57faSrui zang - Sun Microsystems - Beijing China wq = WR(hidp->hid_inuse_rq);
19837c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
19847c478bd9Sstevel@tonic-gate
19857c478bd9Sstevel@tonic-gate qenable(wq);
19867c478bd9Sstevel@tonic-gate
19877c478bd9Sstevel@tonic-gate } else {
19887c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
19897c478bd9Sstevel@tonic-gate }
19907c478bd9Sstevel@tonic-gate }
19917c478bd9Sstevel@tonic-gate
19927c478bd9Sstevel@tonic-gate
19937c478bd9Sstevel@tonic-gate /*
19947c478bd9Sstevel@tonic-gate * hid_parse_hid_descr:
19957c478bd9Sstevel@tonic-gate * Parse the hid descriptor, check after interface and after
19967c478bd9Sstevel@tonic-gate * endpoint descriptor
19977c478bd9Sstevel@tonic-gate */
19987c478bd9Sstevel@tonic-gate static size_t
hid_parse_hid_descr(usb_hid_descr_t * ret_descr,size_t ret_buf_len,usb_alt_if_data_t * altif_data,usb_ep_data_t * ep_data)1999993e3fafSRobert Mustacchi hid_parse_hid_descr(usb_hid_descr_t *ret_descr, size_t ret_buf_len,
2000993e3fafSRobert Mustacchi usb_alt_if_data_t *altif_data, usb_ep_data_t *ep_data)
20017c478bd9Sstevel@tonic-gate {
20027c478bd9Sstevel@tonic-gate usb_cvs_data_t *cvs;
20037c478bd9Sstevel@tonic-gate int which_cvs;
20047c478bd9Sstevel@tonic-gate
20057c478bd9Sstevel@tonic-gate for (which_cvs = 0; which_cvs < altif_data->altif_n_cvs; which_cvs++) {
20067c478bd9Sstevel@tonic-gate cvs = &altif_data->altif_cvs[which_cvs];
20077c478bd9Sstevel@tonic-gate if (cvs->cvs_buf == NULL) {
20087c478bd9Sstevel@tonic-gate continue;
20097c478bd9Sstevel@tonic-gate }
20107c478bd9Sstevel@tonic-gate if (cvs->cvs_buf[1] == USB_DESCR_TYPE_HID) {
20117c478bd9Sstevel@tonic-gate return (usb_parse_data("ccscccs",
2012112116d8Sfb cvs->cvs_buf, cvs->cvs_buf_len,
2013112116d8Sfb (void *)ret_descr,
2014112116d8Sfb (size_t)ret_buf_len));
20157c478bd9Sstevel@tonic-gate }
20167c478bd9Sstevel@tonic-gate }
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate /* now try after endpoint */
20197c478bd9Sstevel@tonic-gate for (which_cvs = 0; which_cvs < ep_data->ep_n_cvs; which_cvs++) {
20207c478bd9Sstevel@tonic-gate cvs = &ep_data->ep_cvs[which_cvs];
20217c478bd9Sstevel@tonic-gate if (cvs->cvs_buf == NULL) {
20227c478bd9Sstevel@tonic-gate continue;
20237c478bd9Sstevel@tonic-gate }
20247c478bd9Sstevel@tonic-gate if (cvs->cvs_buf[1] == USB_DESCR_TYPE_HID) {
20257c478bd9Sstevel@tonic-gate return (usb_parse_data("ccscccs",
2026112116d8Sfb cvs->cvs_buf, cvs->cvs_buf_len,
2027112116d8Sfb (void *)ret_descr,
2028112116d8Sfb (size_t)ret_buf_len));
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate }
20317c478bd9Sstevel@tonic-gate
20327c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
20337c478bd9Sstevel@tonic-gate }
20347c478bd9Sstevel@tonic-gate
20357c478bd9Sstevel@tonic-gate
20367c478bd9Sstevel@tonic-gate /*
20377c478bd9Sstevel@tonic-gate * hid_parse_hid_descr_failure:
20387c478bd9Sstevel@tonic-gate * If parsing of hid descriptor failed and the device is
20397c478bd9Sstevel@tonic-gate * a keyboard or mouse, use predefined length and packet size.
20407c478bd9Sstevel@tonic-gate */
20417c478bd9Sstevel@tonic-gate static int
hid_parse_hid_descr_failure(hid_state_t * hidp)20427c478bd9Sstevel@tonic-gate hid_parse_hid_descr_failure(hid_state_t *hidp)
20437c478bd9Sstevel@tonic-gate {
20447c478bd9Sstevel@tonic-gate /*
20457c478bd9Sstevel@tonic-gate * Parsing hid descriptor failed, probably because the
20467c478bd9Sstevel@tonic-gate * device did not return a valid hid descriptor. Check to
20477c478bd9Sstevel@tonic-gate * see if this is a keyboard or mouse. If so, use the
20487c478bd9Sstevel@tonic-gate * predefined hid descriptor length and packet size.
20497c478bd9Sstevel@tonic-gate * Otherwise, detach and return failure.
20507c478bd9Sstevel@tonic-gate */
20517c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
20527c478bd9Sstevel@tonic-gate "Parsing of hid descriptor failed");
20537c478bd9Sstevel@tonic-gate
20547c478bd9Sstevel@tonic-gate if (hidp->hid_if_descr.bInterfaceProtocol == KEYBOARD_PROTOCOL) {
20557c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
20567c478bd9Sstevel@tonic-gate "Set hid descriptor length to predefined "
20577c478bd9Sstevel@tonic-gate "USB_KB_HID_DESCR_LENGTH for keyboard.");
20587c478bd9Sstevel@tonic-gate
20597c478bd9Sstevel@tonic-gate /* device is a keyboard */
20607c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.wReportDescriptorLength =
2061112116d8Sfb USB_KB_HID_DESCR_LENGTH;
20627c478bd9Sstevel@tonic-gate
20637c478bd9Sstevel@tonic-gate hidp->hid_packet_size = USBKPSZ;
20647c478bd9Sstevel@tonic-gate
20657c478bd9Sstevel@tonic-gate } else if (hidp->hid_if_descr.bInterfaceProtocol ==
20667c478bd9Sstevel@tonic-gate MOUSE_PROTOCOL) {
20677c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
20687c478bd9Sstevel@tonic-gate "Set hid descriptor length to predefined "
20697c478bd9Sstevel@tonic-gate "USB_MS_HID_DESCR_LENGTH for mouse.");
20707c478bd9Sstevel@tonic-gate
20717c478bd9Sstevel@tonic-gate /* device is a mouse */
20727c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.wReportDescriptorLength =
2073112116d8Sfb USB_MS_HID_DESCR_LENGTH;
20747c478bd9Sstevel@tonic-gate
20757c478bd9Sstevel@tonic-gate hidp->hid_packet_size = USBMSSZ;
20767c478bd9Sstevel@tonic-gate } else {
20777c478bd9Sstevel@tonic-gate
20787c478bd9Sstevel@tonic-gate return (USB_FAILURE);
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
20827c478bd9Sstevel@tonic-gate }
20837c478bd9Sstevel@tonic-gate
20847c478bd9Sstevel@tonic-gate
20857c478bd9Sstevel@tonic-gate /*
20867c478bd9Sstevel@tonic-gate * hid_handle_report_descriptor:
20877c478bd9Sstevel@tonic-gate * Get the report descriptor, call hidparser routine to parse
20887c478bd9Sstevel@tonic-gate * it and query the hidparser tree to get the packet size
20897c478bd9Sstevel@tonic-gate */
20907c478bd9Sstevel@tonic-gate static int
hid_handle_report_descriptor(hid_state_t * hidp,int interface)2091993e3fafSRobert Mustacchi hid_handle_report_descriptor(hid_state_t *hidp, int interface)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate usb_cr_t completion_reason;
20947c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags;
20957c478bd9Sstevel@tonic-gate mblk_t *data = NULL;
20967c478bd9Sstevel@tonic-gate hidparser_packet_info_t hpack;
20977c478bd9Sstevel@tonic-gate int i;
20987c478bd9Sstevel@tonic-gate usb_ctrl_setup_t setup = {
20997c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | /* bmRequestType */
2100112116d8Sfb USB_DEV_REQ_RCPT_IF,
21017c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, /* bRequest */
21027c478bd9Sstevel@tonic-gate USB_CLASS_DESCR_TYPE_REPORT, /* wValue */
21037c478bd9Sstevel@tonic-gate 0, /* wIndex: interface, fill in later */
21047c478bd9Sstevel@tonic-gate 0, /* wLength, fill in later */
21057c478bd9Sstevel@tonic-gate 0 /* attributes */
2106112116d8Sfb };
21077c478bd9Sstevel@tonic-gate
21087c478bd9Sstevel@tonic-gate /*
21097c478bd9Sstevel@tonic-gate * Parsing hid desciptor was successful earlier.
21107c478bd9Sstevel@tonic-gate * Get Report Descriptor
21117c478bd9Sstevel@tonic-gate */
21127c478bd9Sstevel@tonic-gate setup.wIndex = (uint16_t)interface;
21137c478bd9Sstevel@tonic-gate setup.wLength = hidp->hid_hid_descr.wReportDescriptorLength;
21147c478bd9Sstevel@tonic-gate if (usb_pipe_ctrl_xfer_wait(hidp->hid_default_pipe,
21157c478bd9Sstevel@tonic-gate &setup,
21167c478bd9Sstevel@tonic-gate &data, /* data */
21177c478bd9Sstevel@tonic-gate &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
21187c478bd9Sstevel@tonic-gate
2119d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
2120112116d8Sfb "Failed to receive the Report Descriptor");
21217c478bd9Sstevel@tonic-gate freemsg(data);
21227c478bd9Sstevel@tonic-gate
21237c478bd9Sstevel@tonic-gate return (USB_FAILURE);
21247c478bd9Sstevel@tonic-gate
21257c478bd9Sstevel@tonic-gate } else {
21267c478bd9Sstevel@tonic-gate int n = hidp->hid_hid_descr.wReportDescriptorLength;
21277c478bd9Sstevel@tonic-gate
21287c478bd9Sstevel@tonic-gate ASSERT(data);
21297c478bd9Sstevel@tonic-gate
21307c478bd9Sstevel@tonic-gate /* Print the report descriptor */
21317c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) {
21327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
2133112116d8Sfb "Index = %d\tvalue =0x%x", i,
2134112116d8Sfb (int)(data->b_rptr[i]));
21357c478bd9Sstevel@tonic-gate }
21367c478bd9Sstevel@tonic-gate
21377c478bd9Sstevel@tonic-gate /* Get Report Descriptor was successful */
21387c478bd9Sstevel@tonic-gate if (hidparser_parse_report_descriptor(
21397c478bd9Sstevel@tonic-gate data->b_rptr,
21407c478bd9Sstevel@tonic-gate hidp->hid_hid_descr.wReportDescriptorLength,
21417c478bd9Sstevel@tonic-gate &hidp->hid_hid_descr,
21427c478bd9Sstevel@tonic-gate &hidp->hid_report_descr) == HIDPARSER_SUCCESS) {
21437c478bd9Sstevel@tonic-gate
21447c478bd9Sstevel@tonic-gate /* find max intr-in xfer length */
21457c478bd9Sstevel@tonic-gate hidparser_find_max_packet_size_from_report_descriptor(
21467c478bd9Sstevel@tonic-gate hidp->hid_report_descr, &hpack);
21477c478bd9Sstevel@tonic-gate /* round up to the nearest byte */
21487c478bd9Sstevel@tonic-gate hidp->hid_packet_size = (hpack.max_packet_size + 7) / 8;
21497c478bd9Sstevel@tonic-gate
21507c478bd9Sstevel@tonic-gate /* if report id is used, add more more byte for it */
21517c478bd9Sstevel@tonic-gate if (hpack.report_id != HID_REPORT_ID_UNDEFINED) {
21527c478bd9Sstevel@tonic-gate hidp->hid_packet_size++;
21537c478bd9Sstevel@tonic-gate }
21547c478bd9Sstevel@tonic-gate } else {
21557c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
21567c478bd9Sstevel@tonic-gate "Invalid Report Descriptor");
21577c478bd9Sstevel@tonic-gate freemsg(data);
21587c478bd9Sstevel@tonic-gate
21597c478bd9Sstevel@tonic-gate return (USB_FAILURE);
21607c478bd9Sstevel@tonic-gate }
21617c478bd9Sstevel@tonic-gate
21627c478bd9Sstevel@tonic-gate freemsg(data);
21637c478bd9Sstevel@tonic-gate
21647c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
21657c478bd9Sstevel@tonic-gate }
21667c478bd9Sstevel@tonic-gate }
21677c478bd9Sstevel@tonic-gate
21687c478bd9Sstevel@tonic-gate
21697c478bd9Sstevel@tonic-gate /*
21707c478bd9Sstevel@tonic-gate * hid_set_idle:
21717c478bd9Sstevel@tonic-gate * Make a clas specific request to SET_IDLE.
21727c478bd9Sstevel@tonic-gate * In this case send no reports if state has not changed.
21737c478bd9Sstevel@tonic-gate * See HID 7.2.4.
21747c478bd9Sstevel@tonic-gate */
21757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21767c478bd9Sstevel@tonic-gate static void
hid_set_idle(hid_state_t * hidp)2177993e3fafSRobert Mustacchi hid_set_idle(hid_state_t *hidp)
21787c478bd9Sstevel@tonic-gate {
21797c478bd9Sstevel@tonic-gate usb_cr_t completion_reason;
21807c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags;
21817c478bd9Sstevel@tonic-gate usb_ctrl_setup_t setup = {
21827c478bd9Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV | /* bmRequestType */
2183112116d8Sfb USB_DEV_REQ_TYPE_CLASS |
2184112116d8Sfb USB_DEV_REQ_RCPT_IF,
21857c478bd9Sstevel@tonic-gate SET_IDLE, /* bRequest */
21867c478bd9Sstevel@tonic-gate DURATION, /* wValue */
21877c478bd9Sstevel@tonic-gate 0, /* wIndex: interface, fill in later */
21887c478bd9Sstevel@tonic-gate 0, /* wLength */
21897c478bd9Sstevel@tonic-gate 0 /* attributes */
2190112116d8Sfb };
21917c478bd9Sstevel@tonic-gate
21927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
21937c478bd9Sstevel@tonic-gate "hid_set_idle: Begin");
21947c478bd9Sstevel@tonic-gate
21957c478bd9Sstevel@tonic-gate setup.wIndex = hidp->hid_if_descr.bInterfaceNumber;
21967c478bd9Sstevel@tonic-gate if (usb_pipe_ctrl_xfer_wait(
21977c478bd9Sstevel@tonic-gate hidp->hid_default_pipe,
21987c478bd9Sstevel@tonic-gate &setup,
21997c478bd9Sstevel@tonic-gate NULL, /* no data to send. */
22007c478bd9Sstevel@tonic-gate &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
22017c478bd9Sstevel@tonic-gate
22027c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
22037c478bd9Sstevel@tonic-gate "Failed while trying to set idle,"
22047c478bd9Sstevel@tonic-gate "cr = %d, cb_flags = 0x%x\n",
22057c478bd9Sstevel@tonic-gate completion_reason, cb_flags);
22067c478bd9Sstevel@tonic-gate }
22077c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2208112116d8Sfb "hid_set_idle: End");
22097c478bd9Sstevel@tonic-gate }
22107c478bd9Sstevel@tonic-gate
22117c478bd9Sstevel@tonic-gate
22127c478bd9Sstevel@tonic-gate /*
22137c478bd9Sstevel@tonic-gate * hid_set_protocol:
22147c478bd9Sstevel@tonic-gate * Initialize the device to set the preferred protocol
22157c478bd9Sstevel@tonic-gate */
22167c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22177c478bd9Sstevel@tonic-gate static void
hid_set_protocol(hid_state_t * hidp,int protocol)22187c478bd9Sstevel@tonic-gate hid_set_protocol(hid_state_t *hidp, int protocol)
22197c478bd9Sstevel@tonic-gate {
22207c478bd9Sstevel@tonic-gate usb_cr_t completion_reason;
22217c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags;
22227c478bd9Sstevel@tonic-gate usb_ctrl_setup_t setup;
22237c478bd9Sstevel@tonic-gate
22247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
22257c478bd9Sstevel@tonic-gate "hid_set_protocol(%d): Begin", protocol);
22267c478bd9Sstevel@tonic-gate
22277c478bd9Sstevel@tonic-gate /* initialize the setup request */
22287c478bd9Sstevel@tonic-gate setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
22297c478bd9Sstevel@tonic-gate USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
22307c478bd9Sstevel@tonic-gate setup.bRequest = SET_PROTOCOL;
2231d29f5a71Szhigang lu - Sun Microsystems - Beijing China setup.wValue = (uint16_t)protocol;
22327c478bd9Sstevel@tonic-gate setup.wIndex = hidp->hid_if_descr.bInterfaceNumber;
22337c478bd9Sstevel@tonic-gate setup.wLength = 0;
22347c478bd9Sstevel@tonic-gate setup.attrs = 0;
22357c478bd9Sstevel@tonic-gate if (usb_pipe_ctrl_xfer_wait(
22367c478bd9Sstevel@tonic-gate hidp->hid_default_pipe, /* bmRequestType */
22377c478bd9Sstevel@tonic-gate &setup,
22387c478bd9Sstevel@tonic-gate NULL, /* no data to send */
22397c478bd9Sstevel@tonic-gate &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
22407c478bd9Sstevel@tonic-gate /*
22417c478bd9Sstevel@tonic-gate * Some devices fail to follow the specification
22427c478bd9Sstevel@tonic-gate * and instead of STALLing, they continously
22437c478bd9Sstevel@tonic-gate * NAK the SET_IDLE command. We need to reset
22447c478bd9Sstevel@tonic-gate * the pipe then, so that ohci doesn't panic.
22457c478bd9Sstevel@tonic-gate */
22467c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
22477c478bd9Sstevel@tonic-gate "Failed while trying to set protocol:%d,"
22487c478bd9Sstevel@tonic-gate "cr = %d cb_flags = 0x%x\n",
22497c478bd9Sstevel@tonic-gate completion_reason, cb_flags, protocol);
22507c478bd9Sstevel@tonic-gate }
22517c478bd9Sstevel@tonic-gate
22527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2253112116d8Sfb "hid_set_protocol: End");
22547c478bd9Sstevel@tonic-gate }
22557c478bd9Sstevel@tonic-gate
22567c478bd9Sstevel@tonic-gate
22577c478bd9Sstevel@tonic-gate /*
22587c478bd9Sstevel@tonic-gate * hid_detach_cleanup:
22597c478bd9Sstevel@tonic-gate * called by attach and detach for cleanup.
22607c478bd9Sstevel@tonic-gate */
22617c478bd9Sstevel@tonic-gate static void
hid_detach_cleanup(dev_info_t * dip,hid_state_t * hidp)22627c478bd9Sstevel@tonic-gate hid_detach_cleanup(dev_info_t *dip, hid_state_t *hidp)
22637c478bd9Sstevel@tonic-gate {
22647c478bd9Sstevel@tonic-gate int flags = hidp->hid_attach_flags;
22657c478bd9Sstevel@tonic-gate int rval;
22667c478bd9Sstevel@tonic-gate hid_power_t *hidpm;
22677c478bd9Sstevel@tonic-gate
22687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
22697c478bd9Sstevel@tonic-gate "hid_detach_cleanup: Begin");
22707c478bd9Sstevel@tonic-gate
22717c478bd9Sstevel@tonic-gate if ((hidp->hid_attach_flags & HID_LOCK_INIT) == 0) {
22727c478bd9Sstevel@tonic-gate
22737c478bd9Sstevel@tonic-gate goto done;
22747c478bd9Sstevel@tonic-gate }
22757c478bd9Sstevel@tonic-gate
22767c478bd9Sstevel@tonic-gate /*
22777c478bd9Sstevel@tonic-gate * Disable the event callbacks first, after this point, event
22787c478bd9Sstevel@tonic-gate * callbacks will never get called. Note we shouldn't hold
22797c478bd9Sstevel@tonic-gate * mutex while unregistering events because there may be a
22807c478bd9Sstevel@tonic-gate * competing event callback thread. Event callbacks are done
22817c478bd9Sstevel@tonic-gate * with ndi mutex held and this can cause a potential deadlock.
22827c478bd9Sstevel@tonic-gate */
22837c478bd9Sstevel@tonic-gate usb_unregister_event_cbs(dip, &hid_events);
22847c478bd9Sstevel@tonic-gate
22857c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
22867c478bd9Sstevel@tonic-gate
22877c478bd9Sstevel@tonic-gate hidpm = hidp->hid_pm;
22887c478bd9Sstevel@tonic-gate
22897c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
2290112116d8Sfb "hid_detach_cleanup: hidpm=0x%p", (void *)hidpm);
22917c478bd9Sstevel@tonic-gate
22927c478bd9Sstevel@tonic-gate if (hidpm && (hidp->hid_dev_state != USB_DEV_DISCONNECTED)) {
22937c478bd9Sstevel@tonic-gate
22947c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
22957c478bd9Sstevel@tonic-gate hid_pm_busy_component(hidp);
22967c478bd9Sstevel@tonic-gate if (hid_is_pm_enabled(dip) == USB_SUCCESS) {
22977c478bd9Sstevel@tonic-gate
22987c478bd9Sstevel@tonic-gate if (hidpm->hid_wakeup_enabled) {
22997c478bd9Sstevel@tonic-gate
23007c478bd9Sstevel@tonic-gate /* First bring the device to full power */
23017c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0,
23027c478bd9Sstevel@tonic-gate USB_DEV_OS_FULL_PWR);
23037c478bd9Sstevel@tonic-gate
23047c478bd9Sstevel@tonic-gate /* Disable remote wakeup */
23057c478bd9Sstevel@tonic-gate rval = usb_handle_remote_wakeup(dip,
23067c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_DISABLE);
23077c478bd9Sstevel@tonic-gate
23087c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) {
23097c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
23107c478bd9Sstevel@tonic-gate hidp->hid_log_handle,
23117c478bd9Sstevel@tonic-gate "hid_detach_cleanup: "
23127c478bd9Sstevel@tonic-gate "disble remote wakeup failed, "
23137c478bd9Sstevel@tonic-gate "rval= %d", rval);
23147c478bd9Sstevel@tonic-gate }
23157c478bd9Sstevel@tonic-gate }
23167c478bd9Sstevel@tonic-gate
23177c478bd9Sstevel@tonic-gate (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
23187c478bd9Sstevel@tonic-gate }
23197c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
23207c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
23217c478bd9Sstevel@tonic-gate }
23227c478bd9Sstevel@tonic-gate
23237c478bd9Sstevel@tonic-gate if (hidpm) {
23247c478bd9Sstevel@tonic-gate freemsg(hidpm->hid_pm_pwrup);
23257c478bd9Sstevel@tonic-gate kmem_free(hidpm, sizeof (hid_power_t));
23267c478bd9Sstevel@tonic-gate hidp->hid_pm = NULL;
23277c478bd9Sstevel@tonic-gate }
23287c478bd9Sstevel@tonic-gate
2329*cfe80fe3SAlex Wilson if (hidp->hid_ugen_hdl != NULL) {
2330*cfe80fe3SAlex Wilson rval = usb_ugen_detach(hidp->hid_ugen_hdl, DDI_DETACH);
2331*cfe80fe3SAlex Wilson VERIFY0(rval);
2332*cfe80fe3SAlex Wilson usb_ugen_release_hdl(hidp->hid_ugen_hdl);
2333*cfe80fe3SAlex Wilson }
2334*cfe80fe3SAlex Wilson
23357c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
23367c478bd9Sstevel@tonic-gate
23377c478bd9Sstevel@tonic-gate if (hidp->hid_report_descr != NULL) {
23387c478bd9Sstevel@tonic-gate (void) hidparser_free_report_descriptor_handle(
2339112116d8Sfb hidp->hid_report_descr);
23407c478bd9Sstevel@tonic-gate }
23417c478bd9Sstevel@tonic-gate
23427c478bd9Sstevel@tonic-gate if (flags & HID_MINOR_NODES) {
23437c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL);
23447c478bd9Sstevel@tonic-gate }
23457c478bd9Sstevel@tonic-gate
23467c478bd9Sstevel@tonic-gate mutex_destroy(&hidp->hid_mutex);
23477c478bd9Sstevel@tonic-gate
23487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
23497c478bd9Sstevel@tonic-gate "hid_detach_cleanup: End");
23507c478bd9Sstevel@tonic-gate
23517c478bd9Sstevel@tonic-gate done:
23527c478bd9Sstevel@tonic-gate usb_client_detach(dip, hidp->hid_dev_data);
23537c478bd9Sstevel@tonic-gate usb_free_log_hdl(hidp->hid_log_handle);
23547c478bd9Sstevel@tonic-gate ddi_soft_state_free(hid_statep, hidp->hid_instance);
23557c478bd9Sstevel@tonic-gate
23567c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip);
23577c478bd9Sstevel@tonic-gate }
23587c478bd9Sstevel@tonic-gate
23597c478bd9Sstevel@tonic-gate
23607c478bd9Sstevel@tonic-gate /*
23617c478bd9Sstevel@tonic-gate * hid_start_intr_polling:
23627c478bd9Sstevel@tonic-gate * Allocate an interrupt request structure, initialize,
23637c478bd9Sstevel@tonic-gate * and start interrupt transfers.
23647c478bd9Sstevel@tonic-gate */
23657c478bd9Sstevel@tonic-gate static int
hid_start_intr_polling(hid_state_t * hidp)23667c478bd9Sstevel@tonic-gate hid_start_intr_polling(hid_state_t *hidp)
23677c478bd9Sstevel@tonic-gate {
23687c478bd9Sstevel@tonic-gate usb_intr_req_t *req;
23697c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS;
23707c478bd9Sstevel@tonic-gate
23717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
23727c478bd9Sstevel@tonic-gate "hid_start_intr_polling: "
2373ddee57faSrui zang - Sun Microsystems - Beijing China "dev_state=%s internal_str_flag=%d external_str_flag=%d ph=0x%p",
2374ddee57faSrui zang - Sun Microsystems - Beijing China usb_str_dev_state(hidp->hid_dev_state), hidp->hid_internal_flag,
2375ddee57faSrui zang - Sun Microsystems - Beijing China hidp->hid_external_flag, (void *)hidp->hid_interrupt_pipe);
23767c478bd9Sstevel@tonic-gate
2377ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_OPEN(hidp) && (hidp->hid_interrupt_pipe != NULL)) {
23787c478bd9Sstevel@tonic-gate /*
23797c478bd9Sstevel@tonic-gate * initialize interrupt pipe request structure
23807c478bd9Sstevel@tonic-gate */
23817c478bd9Sstevel@tonic-gate req = usb_alloc_intr_req(hidp->hid_dip, 0, USB_FLAGS_SLEEP);
23827c478bd9Sstevel@tonic-gate req->intr_client_private = (usb_opaque_t)hidp;
23837c478bd9Sstevel@tonic-gate req->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
2384112116d8Sfb USB_ATTRS_AUTOCLEARING;
23857c478bd9Sstevel@tonic-gate req->intr_len = hidp->hid_packet_size;
23867c478bd9Sstevel@tonic-gate req->intr_cb = hid_interrupt_pipe_callback;
23877c478bd9Sstevel@tonic-gate req->intr_exc_cb = hid_interrupt_pipe_exception_callback;
23887c478bd9Sstevel@tonic-gate
23897c478bd9Sstevel@tonic-gate /*
23907c478bd9Sstevel@tonic-gate * Start polling on the interrupt pipe.
23917c478bd9Sstevel@tonic-gate */
23927c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
23937c478bd9Sstevel@tonic-gate
23947c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_intr_xfer(hidp->hid_interrupt_pipe, req,
23957c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP)) != USB_SUCCESS) {
23967c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM, hidp->hid_log_handle,
23977c478bd9Sstevel@tonic-gate "hid_start_intr_polling failed: rval = %d",
23987c478bd9Sstevel@tonic-gate rval);
23997c478bd9Sstevel@tonic-gate usb_free_intr_req(req);
24007c478bd9Sstevel@tonic-gate }
24017c478bd9Sstevel@tonic-gate
24027c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
24037c478bd9Sstevel@tonic-gate }
24047c478bd9Sstevel@tonic-gate
24057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
24067c478bd9Sstevel@tonic-gate "hid_start_intr_polling: done, rval = %d", rval);
24077c478bd9Sstevel@tonic-gate
24087c478bd9Sstevel@tonic-gate return (rval);
24097c478bd9Sstevel@tonic-gate }
24107c478bd9Sstevel@tonic-gate
24117c478bd9Sstevel@tonic-gate
24127c478bd9Sstevel@tonic-gate /*
24137c478bd9Sstevel@tonic-gate * hid_close_intr_pipe:
24147c478bd9Sstevel@tonic-gate * close the interrupt pipe after draining all callbacks
24157c478bd9Sstevel@tonic-gate */
24167c478bd9Sstevel@tonic-gate static void
hid_close_intr_pipe(hid_state_t * hidp)24177c478bd9Sstevel@tonic-gate hid_close_intr_pipe(hid_state_t *hidp)
24187c478bd9Sstevel@tonic-gate {
24197c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
24207c478bd9Sstevel@tonic-gate "hid_close_intr_pipe: Begin");
24217c478bd9Sstevel@tonic-gate
24227c478bd9Sstevel@tonic-gate if (hidp->hid_interrupt_pipe) {
24237c478bd9Sstevel@tonic-gate /*
24247c478bd9Sstevel@tonic-gate * Close the interrupt pipe
24257c478bd9Sstevel@tonic-gate */
24267c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
24277c478bd9Sstevel@tonic-gate usb_pipe_close(hidp->hid_dip, hidp->hid_interrupt_pipe,
24287c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL);
24297c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
24307c478bd9Sstevel@tonic-gate hidp->hid_interrupt_pipe = NULL;
24317c478bd9Sstevel@tonic-gate }
24327c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
24337c478bd9Sstevel@tonic-gate "hid_close_intr_pipe: End");
24347c478bd9Sstevel@tonic-gate }
24357c478bd9Sstevel@tonic-gate
24367c478bd9Sstevel@tonic-gate
24377c478bd9Sstevel@tonic-gate /*
24387c478bd9Sstevel@tonic-gate * hid_mctl_receive:
24397c478bd9Sstevel@tonic-gate * Handle M_CTL messages from upper stream. If
24407c478bd9Sstevel@tonic-gate * we don't understand the command, free message.
24417c478bd9Sstevel@tonic-gate */
24427c478bd9Sstevel@tonic-gate static int
hid_mctl_receive(register queue_t * q,register mblk_t * mp)24437c478bd9Sstevel@tonic-gate hid_mctl_receive(register queue_t *q, register mblk_t *mp)
24447c478bd9Sstevel@tonic-gate {
2445ddee57faSrui zang - Sun Microsystems - Beijing China hid_state_t *hidp = (hid_state_t *)q->q_ptr;
24467c478bd9Sstevel@tonic-gate struct iocblk *iocp;
24477c478bd9Sstevel@tonic-gate int error = HID_FAILURE;
24487c478bd9Sstevel@tonic-gate uchar_t request_type;
24497c478bd9Sstevel@tonic-gate hid_req_t *hid_req_data = NULL;
24507c478bd9Sstevel@tonic-gate hid_polled_input_callback_t hid_polled_input;
24516d9a41ffSqz hid_vid_pid_t hid_vid_pid;
24527c478bd9Sstevel@tonic-gate
24537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
24547c478bd9Sstevel@tonic-gate "hid_mctl_receive");
24557c478bd9Sstevel@tonic-gate
24567c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
24577c478bd9Sstevel@tonic-gate
24587c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
24597c478bd9Sstevel@tonic-gate case HID_SET_REPORT:
24607c478bd9Sstevel@tonic-gate /* FALLTHRU */
24617c478bd9Sstevel@tonic-gate case HID_SET_IDLE:
24627c478bd9Sstevel@tonic-gate /* FALLTHRU */
24637c478bd9Sstevel@tonic-gate case HID_SET_PROTOCOL:
24647c478bd9Sstevel@tonic-gate request_type = USB_DEV_REQ_HOST_TO_DEV |
24657c478bd9Sstevel@tonic-gate USB_DEV_REQ_RCPT_IF | USB_DEV_REQ_TYPE_CLASS;
24667c478bd9Sstevel@tonic-gate
24677c478bd9Sstevel@tonic-gate break;
24687c478bd9Sstevel@tonic-gate case HID_GET_REPORT:
24697c478bd9Sstevel@tonic-gate /* FALLTHRU */
24707c478bd9Sstevel@tonic-gate case HID_GET_IDLE:
24717c478bd9Sstevel@tonic-gate /* FALLTHRU */
24727c478bd9Sstevel@tonic-gate case HID_GET_PROTOCOL:
24737c478bd9Sstevel@tonic-gate request_type = USB_DEV_REQ_DEV_TO_HOST |
24747c478bd9Sstevel@tonic-gate USB_DEV_REQ_RCPT_IF | USB_DEV_REQ_TYPE_CLASS;
24757c478bd9Sstevel@tonic-gate
24767c478bd9Sstevel@tonic-gate break;
24777c478bd9Sstevel@tonic-gate case HID_GET_PARSER_HANDLE:
24787c478bd9Sstevel@tonic-gate if (canputnext(RD(q))) {
24797c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
24807c478bd9Sstevel@tonic-gate mp->b_cont = hid_data2mblk(
24817c478bd9Sstevel@tonic-gate (uchar_t *)&hidp->hid_report_descr,
24827c478bd9Sstevel@tonic-gate sizeof (hidp->hid_report_descr));
24837c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) {
24847c478bd9Sstevel@tonic-gate /*
24857c478bd9Sstevel@tonic-gate * can't allocate mblk, indicate
24867c478bd9Sstevel@tonic-gate * that nothing is returned
24877c478bd9Sstevel@tonic-gate */
24887c478bd9Sstevel@tonic-gate iocp->ioc_count = 0;
24897c478bd9Sstevel@tonic-gate } else {
24907c478bd9Sstevel@tonic-gate iocp->ioc_count =
24917c478bd9Sstevel@tonic-gate sizeof (hidp->hid_report_descr);
24927c478bd9Sstevel@tonic-gate }
24937c478bd9Sstevel@tonic-gate qreply(q, mp);
24947c478bd9Sstevel@tonic-gate
24956d9a41ffSqz return (HID_SUCCESS);
24966d9a41ffSqz } else {
24976d9a41ffSqz
24986d9a41ffSqz /* retry */
24996d9a41ffSqz return (HID_ENQUEUE);
25006d9a41ffSqz }
25016d9a41ffSqz case HID_GET_VID_PID:
25026d9a41ffSqz if (canputnext(RD(q))) {
25036d9a41ffSqz freemsg(mp->b_cont);
25046d9a41ffSqz
25056d9a41ffSqz hid_vid_pid.VendorId =
2506112116d8Sfb hidp->hid_dev_descr->idVendor;
25076d9a41ffSqz hid_vid_pid.ProductId =
2508112116d8Sfb hidp->hid_dev_descr->idProduct;
25096d9a41ffSqz
25106d9a41ffSqz mp->b_cont = hid_data2mblk(
25116d9a41ffSqz (uchar_t *)&hid_vid_pid, sizeof (hid_vid_pid_t));
25126d9a41ffSqz if (mp->b_cont == NULL) {
25136d9a41ffSqz /*
25146d9a41ffSqz * can't allocate mblk, indicate that nothing
25156d9a41ffSqz * is being returned.
25166d9a41ffSqz */
25176d9a41ffSqz iocp->ioc_count = 0;
25186d9a41ffSqz } else {
25196d9a41ffSqz iocp->ioc_count =
25206d9a41ffSqz sizeof (hid_vid_pid_t);
25216d9a41ffSqz }
25226d9a41ffSqz qreply(q, mp);
25236d9a41ffSqz
25247c478bd9Sstevel@tonic-gate return (HID_SUCCESS);
25257c478bd9Sstevel@tonic-gate } else {
25267c478bd9Sstevel@tonic-gate
25277c478bd9Sstevel@tonic-gate /* retry */
25287c478bd9Sstevel@tonic-gate return (HID_ENQUEUE);
25297c478bd9Sstevel@tonic-gate }
25307c478bd9Sstevel@tonic-gate case HID_OPEN_POLLED_INPUT:
25317c478bd9Sstevel@tonic-gate if (canputnext(RD(q))) {
25327c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
25337c478bd9Sstevel@tonic-gate
25347c478bd9Sstevel@tonic-gate /* Initialize the structure */
25357c478bd9Sstevel@tonic-gate hid_polled_input.hid_polled_version =
2536112116d8Sfb HID_POLLED_INPUT_V0;
25377c478bd9Sstevel@tonic-gate hid_polled_input.hid_polled_read = hid_polled_read;
25387c478bd9Sstevel@tonic-gate hid_polled_input.hid_polled_input_enter =
2539112116d8Sfb hid_polled_input_enter;
25407c478bd9Sstevel@tonic-gate hid_polled_input.hid_polled_input_exit =
2541112116d8Sfb hid_polled_input_exit;
25427c478bd9Sstevel@tonic-gate hid_polled_input.hid_polled_input_handle =
2543112116d8Sfb (hid_polled_handle_t)hidp;
25447c478bd9Sstevel@tonic-gate
25457c478bd9Sstevel@tonic-gate mp->b_cont = hid_data2mblk(
25467c478bd9Sstevel@tonic-gate (uchar_t *)&hid_polled_input,
25477c478bd9Sstevel@tonic-gate sizeof (hid_polled_input_callback_t));
25487c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) {
25497c478bd9Sstevel@tonic-gate /*
25507c478bd9Sstevel@tonic-gate * can't allocate mblk, indicate that nothing
25517c478bd9Sstevel@tonic-gate * is being returned.
25527c478bd9Sstevel@tonic-gate */
25537c478bd9Sstevel@tonic-gate iocp->ioc_count = 0;
25547c478bd9Sstevel@tonic-gate } else {
25557c478bd9Sstevel@tonic-gate /* Call down into USBA */
25567c478bd9Sstevel@tonic-gate (void) hid_polled_input_init(hidp);
25577c478bd9Sstevel@tonic-gate
25587c478bd9Sstevel@tonic-gate iocp->ioc_count =
25597c478bd9Sstevel@tonic-gate sizeof (hid_polled_input_callback_t);
25607c478bd9Sstevel@tonic-gate }
25617c478bd9Sstevel@tonic-gate qreply(q, mp);
25627c478bd9Sstevel@tonic-gate
25637c478bd9Sstevel@tonic-gate return (HID_SUCCESS);
25647c478bd9Sstevel@tonic-gate } else {
25657c478bd9Sstevel@tonic-gate
25667c478bd9Sstevel@tonic-gate /* retry */
25677c478bd9Sstevel@tonic-gate return (HID_ENQUEUE);
25687c478bd9Sstevel@tonic-gate }
25697c478bd9Sstevel@tonic-gate case HID_CLOSE_POLLED_INPUT:
25707c478bd9Sstevel@tonic-gate /* Call down into USBA */
25717c478bd9Sstevel@tonic-gate (void) hid_polled_input_fini(hidp);
25727c478bd9Sstevel@tonic-gate
25737c478bd9Sstevel@tonic-gate iocp->ioc_count = 0;
25747c478bd9Sstevel@tonic-gate qreply(q, mp);
25757c478bd9Sstevel@tonic-gate
25767c478bd9Sstevel@tonic-gate return (HID_SUCCESS);
25777c478bd9Sstevel@tonic-gate default:
25787c478bd9Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
25797c478bd9Sstevel@tonic-gate
25807c478bd9Sstevel@tonic-gate return (HID_FAILURE);
25817c478bd9Sstevel@tonic-gate }
25827c478bd9Sstevel@tonic-gate
25837c478bd9Sstevel@tonic-gate /*
25847c478bd9Sstevel@tonic-gate * These (device executable) commands require a hid_req_t.
25857c478bd9Sstevel@tonic-gate * Make sure one is present
25867c478bd9Sstevel@tonic-gate */
25877c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) {
25887c478bd9Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
25897c478bd9Sstevel@tonic-gate
25907c478bd9Sstevel@tonic-gate return (error);
25917c478bd9Sstevel@tonic-gate } else {
25927c478bd9Sstevel@tonic-gate hid_req_data = (hid_req_t *)mp->b_cont->b_rptr;
25937c478bd9Sstevel@tonic-gate if ((iocp->ioc_cmd == HID_SET_REPORT) &&
259459c81845Sgc (hid_req_data->hid_req_wLength == 0)) {
25957c478bd9Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
25967c478bd9Sstevel@tonic-gate
25977c478bd9Sstevel@tonic-gate return (error);
25987c478bd9Sstevel@tonic-gate }
25997c478bd9Sstevel@tonic-gate }
26007c478bd9Sstevel@tonic-gate
26017c478bd9Sstevel@tonic-gate /*
26027c478bd9Sstevel@tonic-gate * Check is version no. is correct. This
26037c478bd9Sstevel@tonic-gate * is coming from the user
26047c478bd9Sstevel@tonic-gate */
26057c478bd9Sstevel@tonic-gate if (hid_req_data->hid_req_version_no != HID_VERSION_V_0) {
26067c478bd9Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
26077c478bd9Sstevel@tonic-gate
26087c478bd9Sstevel@tonic-gate return (error);
26097c478bd9Sstevel@tonic-gate }
26107c478bd9Sstevel@tonic-gate
26117c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
26127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
26137c478bd9Sstevel@tonic-gate "hid_mctl_receive: dev_state=%s",
26147c478bd9Sstevel@tonic-gate usb_str_dev_state(hidp->hid_dev_state));
26157c478bd9Sstevel@tonic-gate
26167c478bd9Sstevel@tonic-gate switch (hidp->hid_dev_state) {
26177c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
26187c478bd9Sstevel@tonic-gate /*
26197c478bd9Sstevel@tonic-gate * get the device full powered. We get a callback
26207c478bd9Sstevel@tonic-gate * which enables the WQ and kicks off IO
26217c478bd9Sstevel@tonic-gate */
26227c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_HID_POWER_CHANGE;
26237c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
26247c478bd9Sstevel@tonic-gate if (usb_req_raise_power(hidp->hid_dip, 0,
26257c478bd9Sstevel@tonic-gate USB_DEV_OS_FULL_PWR, hid_power_change_callback,
26267c478bd9Sstevel@tonic-gate hidp, 0) != USB_SUCCESS) {
26277c478bd9Sstevel@tonic-gate /* we retry raising power in wsrv */
26287c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
26297c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_PWRED_DOWN;
26307c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
26317c478bd9Sstevel@tonic-gate }
26327c478bd9Sstevel@tonic-gate error = HID_ENQUEUE;
26337c478bd9Sstevel@tonic-gate
26347c478bd9Sstevel@tonic-gate break;
26357c478bd9Sstevel@tonic-gate case USB_DEV_HID_POWER_CHANGE:
26367c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
26377c478bd9Sstevel@tonic-gate error = HID_ENQUEUE;
26387c478bd9Sstevel@tonic-gate
26397c478bd9Sstevel@tonic-gate break;
26407c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE:
2641ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_STREAMS_FLAG(q, hidp) != HID_STREAMS_DISMANTLING) {
26427c478bd9Sstevel@tonic-gate /* Send a message down */
26437c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
2644ac9468f8Spengcheng chen - Sun Microsystems - Beijing China error = hid_mctl_execute_cmd(q, request_type,
26457c478bd9Sstevel@tonic-gate hid_req_data, mp);
26467c478bd9Sstevel@tonic-gate if (error == HID_FAILURE) {
26477c478bd9Sstevel@tonic-gate hid_qreply_merror(q, mp, EIO);
26487c478bd9Sstevel@tonic-gate }
26497c478bd9Sstevel@tonic-gate } else {
26507c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
26517c478bd9Sstevel@tonic-gate hid_qreply_merror(q, mp, EIO);
26527c478bd9Sstevel@tonic-gate }
26537c478bd9Sstevel@tonic-gate
26547c478bd9Sstevel@tonic-gate break;
26557c478bd9Sstevel@tonic-gate default:
26567c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
26577c478bd9Sstevel@tonic-gate hid_qreply_merror(q, mp, EIO);
26587c478bd9Sstevel@tonic-gate
26597c478bd9Sstevel@tonic-gate break;
26607c478bd9Sstevel@tonic-gate }
26617c478bd9Sstevel@tonic-gate
26627c478bd9Sstevel@tonic-gate return (error);
26637c478bd9Sstevel@tonic-gate }
26647c478bd9Sstevel@tonic-gate
26657c478bd9Sstevel@tonic-gate
26667c478bd9Sstevel@tonic-gate /*
26677c478bd9Sstevel@tonic-gate * hid_mctl_execute_cmd:
26687c478bd9Sstevel@tonic-gate * Send the command to the device.
26697c478bd9Sstevel@tonic-gate */
26707c478bd9Sstevel@tonic-gate static int
hid_mctl_execute_cmd(queue_t * q,int request_type,hid_req_t * hid_req_data,mblk_t * mp)2671ac9468f8Spengcheng chen - Sun Microsystems - Beijing China hid_mctl_execute_cmd(queue_t *q, int request_type, hid_req_t *hid_req_data,
2672ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mblk_t *mp)
26737c478bd9Sstevel@tonic-gate {
26747c478bd9Sstevel@tonic-gate int request_index;
26757c478bd9Sstevel@tonic-gate struct iocblk *iocp;
26767c478bd9Sstevel@tonic-gate hid_default_pipe_arg_t *def_pipe_arg;
2677ddee57faSrui zang - Sun Microsystems - Beijing China hid_state_t *hidp = (hid_state_t *)q->q_ptr;
26787c478bd9Sstevel@tonic-gate
26797c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
26807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
2681112116d8Sfb "hid_mctl_execute_cmd: iocp=0x%p", (void *)iocp);
26827c478bd9Sstevel@tonic-gate
26837c478bd9Sstevel@tonic-gate request_index = hidp->hid_if_descr.bInterfaceNumber;
26847c478bd9Sstevel@tonic-gate
26857c478bd9Sstevel@tonic-gate /*
26867c478bd9Sstevel@tonic-gate * Set up the argument to be passed back to hid
26877c478bd9Sstevel@tonic-gate * when the asynchronous control callback is
26887c478bd9Sstevel@tonic-gate * executed.
26897c478bd9Sstevel@tonic-gate */
26907c478bd9Sstevel@tonic-gate def_pipe_arg = kmem_zalloc(sizeof (hid_default_pipe_arg_t), 0);
26917c478bd9Sstevel@tonic-gate
26927c478bd9Sstevel@tonic-gate if (def_pipe_arg == NULL) {
26937c478bd9Sstevel@tonic-gate
26947c478bd9Sstevel@tonic-gate return (HID_FAILURE);
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate
2697ac9468f8Spengcheng chen - Sun Microsystems - Beijing China def_pipe_arg->hid_default_pipe_arg_queue = q;
26987c478bd9Sstevel@tonic-gate def_pipe_arg->hid_default_pipe_arg_mctlmsg.ioc_cmd = iocp->ioc_cmd;
26997c478bd9Sstevel@tonic-gate def_pipe_arg->hid_default_pipe_arg_mctlmsg.ioc_count = 0;
27007c478bd9Sstevel@tonic-gate def_pipe_arg->hid_default_pipe_arg_mblk = mp;
27017c478bd9Sstevel@tonic-gate
27027c478bd9Sstevel@tonic-gate /*
27037c478bd9Sstevel@tonic-gate * Send the command down to USBA through default
27047c478bd9Sstevel@tonic-gate * pipe.
27057c478bd9Sstevel@tonic-gate */
2706ac9468f8Spengcheng chen - Sun Microsystems - Beijing China if (hid_send_async_ctrl_request(def_pipe_arg, hid_req_data,
2707ac9468f8Spengcheng chen - Sun Microsystems - Beijing China request_type, iocp->ioc_cmd, request_index) != USB_SUCCESS) {
27087c478bd9Sstevel@tonic-gate
27097c478bd9Sstevel@tonic-gate kmem_free(def_pipe_arg, sizeof (hid_default_pipe_arg_t));
27107c478bd9Sstevel@tonic-gate
27117c478bd9Sstevel@tonic-gate return (HID_FAILURE);
27127c478bd9Sstevel@tonic-gate }
27137c478bd9Sstevel@tonic-gate
27147c478bd9Sstevel@tonic-gate return (HID_INPROGRESS);
27157c478bd9Sstevel@tonic-gate }
27167c478bd9Sstevel@tonic-gate
27177c478bd9Sstevel@tonic-gate
27187c478bd9Sstevel@tonic-gate /*
27197c478bd9Sstevel@tonic-gate * hid_send_async_ctrl_request:
27207c478bd9Sstevel@tonic-gate * Send an asynchronous control request to USBA. Since hid is a STREAMS
27217c478bd9Sstevel@tonic-gate * driver, it is not allowed to wait in its entry points except for the
27227c478bd9Sstevel@tonic-gate * open and close entry points. Therefore, hid must use the asynchronous
27237c478bd9Sstevel@tonic-gate * USBA calls.
27247c478bd9Sstevel@tonic-gate */
27257c478bd9Sstevel@tonic-gate static int
hid_send_async_ctrl_request(hid_default_pipe_arg_t * hid_default_pipe_arg,hid_req_t * hid_request,uchar_t request_type,int request_request,ushort_t request_index)2726ac9468f8Spengcheng chen - Sun Microsystems - Beijing China hid_send_async_ctrl_request(hid_default_pipe_arg_t *hid_default_pipe_arg,
2727993e3fafSRobert Mustacchi hid_req_t *hid_request, uchar_t request_type, int request_request,
2728993e3fafSRobert Mustacchi ushort_t request_index)
27297c478bd9Sstevel@tonic-gate {
2730ac9468f8Spengcheng chen - Sun Microsystems - Beijing China queue_t *q = hid_default_pipe_arg->hid_default_pipe_arg_queue;
2731ddee57faSrui zang - Sun Microsystems - Beijing China hid_state_t *hidp = (hid_state_t *)q->q_ptr;
27327c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_req;
27337c478bd9Sstevel@tonic-gate int rval;
27347c478bd9Sstevel@tonic-gate size_t length = 0;
27357c478bd9Sstevel@tonic-gate
27367c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
27377c478bd9Sstevel@tonic-gate "hid_send_async_ctrl_request: "
27387c478bd9Sstevel@tonic-gate "rq_type=%d rq_rq=%d index=%d",
27397c478bd9Sstevel@tonic-gate request_type, request_request, request_index);
27407c478bd9Sstevel@tonic-gate
27417c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
27427c478bd9Sstevel@tonic-gate hidp->hid_default_pipe_req++;
27437c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
27447c478bd9Sstevel@tonic-gate
27457c478bd9Sstevel@tonic-gate /*
27467c478bd9Sstevel@tonic-gate * Note that ctrl_req->ctrl_data should be allocated by usba
27477c478bd9Sstevel@tonic-gate * only for IN requests. OUT request(e.g SET_REPORT) can have a
27487c478bd9Sstevel@tonic-gate * non-zero wLength value but ctrl_data would be allocated by
27497c478bd9Sstevel@tonic-gate * client for them.
27507c478bd9Sstevel@tonic-gate */
275159c81845Sgc if (hid_request->hid_req_wLength >= MAX_REPORT_DATA) {
275259c81845Sgc USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
275359c81845Sgc "hid_req_wLength is exceeded");
275459c81845Sgc return (USB_FAILURE);
275559c81845Sgc }
275659c81845Sgc if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_DEV_TO_HOST) {
275759c81845Sgc length = hid_request->hid_req_wLength;
27587c478bd9Sstevel@tonic-gate }
27597c478bd9Sstevel@tonic-gate
27607c478bd9Sstevel@tonic-gate if ((ctrl_req = usb_alloc_ctrl_req(hidp->hid_dip, length, 0)) == NULL) {
27617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
27627c478bd9Sstevel@tonic-gate "unable to alloc ctrl req. async trans failed");
27637c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
27647c478bd9Sstevel@tonic-gate hidp->hid_default_pipe_req--;
27657c478bd9Sstevel@tonic-gate ASSERT(hidp->hid_default_pipe_req >= 0);
27667c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
27677c478bd9Sstevel@tonic-gate
27687c478bd9Sstevel@tonic-gate return (USB_FAILURE);
27697c478bd9Sstevel@tonic-gate }
27707c478bd9Sstevel@tonic-gate
277159c81845Sgc if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_HOST_TO_DEV) {
27727c478bd9Sstevel@tonic-gate ASSERT((length == 0) && (ctrl_req->ctrl_data == NULL));
27737c478bd9Sstevel@tonic-gate }
27747c478bd9Sstevel@tonic-gate
27757c478bd9Sstevel@tonic-gate ctrl_req->ctrl_bmRequestType = request_type;
2776db1c88f6SSebastian Wiedenroth ctrl_req->ctrl_bRequest = (uint8_t)request_request;
27777c478bd9Sstevel@tonic-gate ctrl_req->ctrl_wValue = hid_request->hid_req_wValue;
27787c478bd9Sstevel@tonic-gate ctrl_req->ctrl_wIndex = request_index;
27797c478bd9Sstevel@tonic-gate ctrl_req->ctrl_wLength = hid_request->hid_req_wLength;
278059c81845Sgc /* host to device: create a msg from hid_req_data */
278159c81845Sgc if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_HOST_TO_DEV) {
278259c81845Sgc mblk_t *pblk = allocb(hid_request->hid_req_wLength, BPRI_HI);
278359c81845Sgc if (pblk == NULL) {
278459c81845Sgc usb_free_ctrl_req(ctrl_req);
278559c81845Sgc return (USB_FAILURE);
278659c81845Sgc }
278759c81845Sgc bcopy(hid_request->hid_req_data, pblk->b_wptr,
2788112116d8Sfb hid_request->hid_req_wLength);
278959c81845Sgc pblk->b_wptr += hid_request->hid_req_wLength;
279059c81845Sgc ctrl_req->ctrl_data = pblk;
279159c81845Sgc }
27927c478bd9Sstevel@tonic-gate ctrl_req->ctrl_attributes = USB_ATTRS_AUTOCLEARING;
27937c478bd9Sstevel@tonic-gate ctrl_req->ctrl_client_private = (usb_opaque_t)hid_default_pipe_arg;
27947c478bd9Sstevel@tonic-gate ctrl_req->ctrl_cb = hid_default_pipe_callback;
27957c478bd9Sstevel@tonic-gate ctrl_req->ctrl_exc_cb = hid_default_pipe_exception_callback;
27967c478bd9Sstevel@tonic-gate
27977c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_ctrl_xfer(hidp->hid_default_pipe,
27987c478bd9Sstevel@tonic-gate ctrl_req, 0)) != USB_SUCCESS) {
27997c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
28007c478bd9Sstevel@tonic-gate hidp->hid_default_pipe_req--;
28017c478bd9Sstevel@tonic-gate ASSERT(hidp->hid_default_pipe_req >= 0);
28027c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
28037c478bd9Sstevel@tonic-gate
28047c478bd9Sstevel@tonic-gate usb_free_ctrl_req(ctrl_req);
28057c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
28067c478bd9Sstevel@tonic-gate "usb_pipe_ctrl_xfer() failed. rval = %d", rval);
28077c478bd9Sstevel@tonic-gate
28087c478bd9Sstevel@tonic-gate return (USB_FAILURE);
28097c478bd9Sstevel@tonic-gate }
28107c478bd9Sstevel@tonic-gate
28117c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
28127c478bd9Sstevel@tonic-gate }
28137c478bd9Sstevel@tonic-gate
28147c478bd9Sstevel@tonic-gate /*
28157c478bd9Sstevel@tonic-gate * hid_create_pm_components:
28167c478bd9Sstevel@tonic-gate * Create the pm components required for power management.
28177c478bd9Sstevel@tonic-gate * For keyboard/mouse, the components is created only if the device
28187c478bd9Sstevel@tonic-gate * supports a remote wakeup.
28197c478bd9Sstevel@tonic-gate * For other hid devices they are created unconditionally.
28207c478bd9Sstevel@tonic-gate */
28217c478bd9Sstevel@tonic-gate static void
hid_create_pm_components(dev_info_t * dip,hid_state_t * hidp)28227c478bd9Sstevel@tonic-gate hid_create_pm_components(dev_info_t *dip, hid_state_t *hidp)
28237c478bd9Sstevel@tonic-gate {
28247c478bd9Sstevel@tonic-gate hid_power_t *hidpm;
28257c478bd9Sstevel@tonic-gate uint_t pwr_states;
28267c478bd9Sstevel@tonic-gate
28277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
28287c478bd9Sstevel@tonic-gate "hid_create_pm_components: Begin");
28297c478bd9Sstevel@tonic-gate
28307c478bd9Sstevel@tonic-gate /* Allocate the state structure */
28317c478bd9Sstevel@tonic-gate hidpm = kmem_zalloc(sizeof (hid_power_t), KM_SLEEP);
28327c478bd9Sstevel@tonic-gate hidp->hid_pm = hidpm;
28337c478bd9Sstevel@tonic-gate hidpm->hid_state = hidp;
28347c478bd9Sstevel@tonic-gate hidpm->hid_raise_power = B_FALSE;
28357c478bd9Sstevel@tonic-gate hidpm->hid_pm_capabilities = 0;
28367c478bd9Sstevel@tonic-gate hidpm->hid_current_power = USB_DEV_OS_FULL_PWR;
28377c478bd9Sstevel@tonic-gate
28387c478bd9Sstevel@tonic-gate switch (hidp->hid_if_descr.bInterfaceProtocol) {
28397c478bd9Sstevel@tonic-gate case KEYBOARD_PROTOCOL:
28407c478bd9Sstevel@tonic-gate case MOUSE_PROTOCOL:
28417c478bd9Sstevel@tonic-gate hidpm->hid_pm_strategy = HID_PM_ACTIVITY;
28427c478bd9Sstevel@tonic-gate if ((hid_is_pm_enabled(dip) == USB_SUCCESS) &&
28437c478bd9Sstevel@tonic-gate (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
28447c478bd9Sstevel@tonic-gate USB_SUCCESS)) {
28457c478bd9Sstevel@tonic-gate
28467c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_PM, hidp->hid_log_handle,
28477c478bd9Sstevel@tonic-gate "hid_create_pm_components: Remote Wakeup Enabled");
28487c478bd9Sstevel@tonic-gate
28497c478bd9Sstevel@tonic-gate if (usb_create_pm_components(dip, &pwr_states) ==
28507c478bd9Sstevel@tonic-gate USB_SUCCESS) {
28517c478bd9Sstevel@tonic-gate hidpm->hid_wakeup_enabled = 1;
28527c478bd9Sstevel@tonic-gate hidpm->hid_pwr_states = (uint8_t)pwr_states;
28537c478bd9Sstevel@tonic-gate }
28547c478bd9Sstevel@tonic-gate }
28557c478bd9Sstevel@tonic-gate
28567c478bd9Sstevel@tonic-gate break;
28577c478bd9Sstevel@tonic-gate default:
28587c478bd9Sstevel@tonic-gate hidpm->hid_pm_strategy = HID_PM_OPEN_CLOSE;
28597c478bd9Sstevel@tonic-gate if ((hid_is_pm_enabled(dip) == USB_SUCCESS) &&
28607c478bd9Sstevel@tonic-gate (usb_create_pm_components(dip, &pwr_states) ==
28617c478bd9Sstevel@tonic-gate USB_SUCCESS)) {
28627c478bd9Sstevel@tonic-gate hidpm->hid_wakeup_enabled = 0;
28637c478bd9Sstevel@tonic-gate hidpm->hid_pwr_states = (uint8_t)pwr_states;
28647c478bd9Sstevel@tonic-gate }
28657c478bd9Sstevel@tonic-gate
28667c478bd9Sstevel@tonic-gate break;
28677c478bd9Sstevel@tonic-gate }
28687c478bd9Sstevel@tonic-gate
28697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
2870112116d8Sfb "hid_create_pm_components: END");
28717c478bd9Sstevel@tonic-gate }
28727c478bd9Sstevel@tonic-gate
28737c478bd9Sstevel@tonic-gate
28747c478bd9Sstevel@tonic-gate /*
28757c478bd9Sstevel@tonic-gate * hid_is_pm_enabled
28767c478bd9Sstevel@tonic-gate * Check if the device is pm enabled. Always enable
28777c478bd9Sstevel@tonic-gate * pm on the new SUN mouse
28787c478bd9Sstevel@tonic-gate */
28797c478bd9Sstevel@tonic-gate static int
hid_is_pm_enabled(dev_info_t * dip)28807c478bd9Sstevel@tonic-gate hid_is_pm_enabled(dev_info_t *dip)
28817c478bd9Sstevel@tonic-gate {
28827c478bd9Sstevel@tonic-gate hid_state_t *hidp = ddi_get_soft_state(hid_statep,
2883112116d8Sfb ddi_get_instance(dip));
28847c478bd9Sstevel@tonic-gate
28857c478bd9Sstevel@tonic-gate if (strcmp(ddi_node_name(dip), "mouse") == 0) {
28864610e4a0Sfrits /* check for overrides first */
28874610e4a0Sfrits if (hid_pm_mouse ||
28884610e4a0Sfrits (ddi_prop_exists(DDI_DEV_T_ANY, dip,
28894610e4a0Sfrits (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
28904610e4a0Sfrits "hid-mouse-pm-enable") == 1)) {
28914610e4a0Sfrits
28924610e4a0Sfrits return (USB_SUCCESS);
28934610e4a0Sfrits }
28944610e4a0Sfrits
28957c478bd9Sstevel@tonic-gate /*
28964610e4a0Sfrits * Always enable PM for 1.05 or greater SUN mouse
28977c478bd9Sstevel@tonic-gate * hidp->hid_dev_descr won't be NULL.
28987c478bd9Sstevel@tonic-gate */
28994610e4a0Sfrits if ((hidp->hid_dev_descr->idVendor ==
29007c478bd9Sstevel@tonic-gate HID_SUN_MOUSE_VENDOR_ID) &&
29017c478bd9Sstevel@tonic-gate (hidp->hid_dev_descr->idProduct ==
29027c478bd9Sstevel@tonic-gate HID_SUN_MOUSE_PROD_ID) &&
29037c478bd9Sstevel@tonic-gate (hidp->hid_dev_descr->bcdDevice >=
29044610e4a0Sfrits HID_SUN_MOUSE_BCDDEVICE)) {
29057c478bd9Sstevel@tonic-gate
29067c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
29077c478bd9Sstevel@tonic-gate }
29087c478bd9Sstevel@tonic-gate } else {
29097c478bd9Sstevel@tonic-gate
29107c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
29117c478bd9Sstevel@tonic-gate }
29127c478bd9Sstevel@tonic-gate
29137c478bd9Sstevel@tonic-gate return (USB_FAILURE);
29147c478bd9Sstevel@tonic-gate }
29157c478bd9Sstevel@tonic-gate
29167c478bd9Sstevel@tonic-gate
29177c478bd9Sstevel@tonic-gate /*
29187c478bd9Sstevel@tonic-gate * hid_save_device_state
29197c478bd9Sstevel@tonic-gate * Save the current device/driver state.
29207c478bd9Sstevel@tonic-gate */
29217c478bd9Sstevel@tonic-gate static void
hid_save_device_state(hid_state_t * hidp)29227c478bd9Sstevel@tonic-gate hid_save_device_state(hid_state_t *hidp)
29237c478bd9Sstevel@tonic-gate {
29247c478bd9Sstevel@tonic-gate struct iocblk *mctlmsg;
29257c478bd9Sstevel@tonic-gate mblk_t *mp;
29267c478bd9Sstevel@tonic-gate queue_t *q;
29277c478bd9Sstevel@tonic-gate
29287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
29297c478bd9Sstevel@tonic-gate "hid_save_device_state");
29307c478bd9Sstevel@tonic-gate
2931ddee57faSrui zang - Sun Microsystems - Beijing China if (!(HID_IS_OPEN(hidp)))
2932ddee57faSrui zang - Sun Microsystems - Beijing China return;
2933ddee57faSrui zang - Sun Microsystems - Beijing China
2934ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_internal_flag == HID_STREAMS_OPEN) {
29357c478bd9Sstevel@tonic-gate /*
2936ac9468f8Spengcheng chen - Sun Microsystems - Beijing China * Send MCTLs up indicating that the device
2937ac9468f8Spengcheng chen - Sun Microsystems - Beijing China * will loose its state
29387c478bd9Sstevel@tonic-gate */
2939ddee57faSrui zang - Sun Microsystems - Beijing China q = hidp->hid_internal_rq;
2940ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
2941ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
2942ddee57faSrui zang - Sun Microsystems - Beijing China if (canputnext(q)) {
2943ddee57faSrui zang - Sun Microsystems - Beijing China mp = allocb(sizeof (struct iocblk), BPRI_HI);
2944ddee57faSrui zang - Sun Microsystems - Beijing China if (mp != NULL) {
2945ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_type = M_CTL;
2946ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg = (struct iocblk *)
2947ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_base;
2948ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg->ioc_cmd = HID_DISCONNECT_EVENT;
2949ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg->ioc_count = 0;
2950ddee57faSrui zang - Sun Microsystems - Beijing China putnext(q, mp);
29517c478bd9Sstevel@tonic-gate }
29527c478bd9Sstevel@tonic-gate }
2953ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
2954ddee57faSrui zang - Sun Microsystems - Beijing China }
2955ddee57faSrui zang - Sun Microsystems - Beijing China
2956ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
2957ddee57faSrui zang - Sun Microsystems - Beijing China /*
2958ddee57faSrui zang - Sun Microsystems - Beijing China * Send MCTLs up indicating that the device
2959ddee57faSrui zang - Sun Microsystems - Beijing China * will loose its state
2960ddee57faSrui zang - Sun Microsystems - Beijing China */
2961ddee57faSrui zang - Sun Microsystems - Beijing China q = hidp->hid_external_rq;
2962ddee57faSrui zang - Sun Microsystems - Beijing China
2963ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
2964ddee57faSrui zang - Sun Microsystems - Beijing China if (canputnext(q)) {
2965ddee57faSrui zang - Sun Microsystems - Beijing China mp = allocb(sizeof (struct iocblk), BPRI_HI);
2966ddee57faSrui zang - Sun Microsystems - Beijing China if (mp != NULL) {
2967ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_type = M_CTL;
2968ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg = (struct iocblk *)
2969ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_base;
2970ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg->ioc_cmd = HID_DISCONNECT_EVENT;
2971ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg->ioc_count = 0;
2972ddee57faSrui zang - Sun Microsystems - Beijing China putnext(q, mp);
2973ddee57faSrui zang - Sun Microsystems - Beijing China }
2974ddee57faSrui zang - Sun Microsystems - Beijing China }
29757c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
29767c478bd9Sstevel@tonic-gate }
2977ddee57faSrui zang - Sun Microsystems - Beijing China
2978ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
2979ddee57faSrui zang - Sun Microsystems - Beijing China /* stop polling on the intr pipe */
2980ddee57faSrui zang - Sun Microsystems - Beijing China usb_pipe_stop_intr_polling(hidp->hid_interrupt_pipe, USB_FLAGS_SLEEP);
2981ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
29827c478bd9Sstevel@tonic-gate }
29837c478bd9Sstevel@tonic-gate
29847c478bd9Sstevel@tonic-gate
29857c478bd9Sstevel@tonic-gate /*
29867c478bd9Sstevel@tonic-gate * hid_restore_device_state:
29877c478bd9Sstevel@tonic-gate * Set original configuration of the device.
29887c478bd9Sstevel@tonic-gate * Reopen intr pipe.
29897c478bd9Sstevel@tonic-gate * Enable wrq - this starts new transactions on the control pipe.
29907c478bd9Sstevel@tonic-gate */
29917c478bd9Sstevel@tonic-gate static void
hid_restore_device_state(dev_info_t * dip,hid_state_t * hidp)29927c478bd9Sstevel@tonic-gate hid_restore_device_state(dev_info_t *dip, hid_state_t *hidp)
29937c478bd9Sstevel@tonic-gate {
29947c478bd9Sstevel@tonic-gate int rval;
29957c478bd9Sstevel@tonic-gate hid_power_t *hidpm;
29967c478bd9Sstevel@tonic-gate struct iocblk *mctlmsg;
29977c478bd9Sstevel@tonic-gate mblk_t *mp;
2998ddee57faSrui zang - Sun Microsystems - Beijing China queue_t *q;
29997c478bd9Sstevel@tonic-gate
30007c478bd9Sstevel@tonic-gate hid_pm_busy_component(hidp);
30017c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
30027c478bd9Sstevel@tonic-gate
30037c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
30047c478bd9Sstevel@tonic-gate "hid_restore_device_state: %s",
30057c478bd9Sstevel@tonic-gate usb_str_dev_state(hidp->hid_dev_state));
30067c478bd9Sstevel@tonic-gate
30077c478bd9Sstevel@tonic-gate hidpm = hidp->hid_pm;
30087c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
30097c478bd9Sstevel@tonic-gate
30107c478bd9Sstevel@tonic-gate /* First bring the device to full power */
30117c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
30127c478bd9Sstevel@tonic-gate
30137c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
30147c478bd9Sstevel@tonic-gate if (hidp->hid_dev_state == USB_DEV_ONLINE) {
30157c478bd9Sstevel@tonic-gate /*
30167c478bd9Sstevel@tonic-gate * We failed the checkpoint, there is no need to restore
30177c478bd9Sstevel@tonic-gate * the device state
30187c478bd9Sstevel@tonic-gate */
30197c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
30207c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
30217c478bd9Sstevel@tonic-gate
30227c478bd9Sstevel@tonic-gate return;
30237c478bd9Sstevel@tonic-gate }
30247c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
30257c478bd9Sstevel@tonic-gate
30267c478bd9Sstevel@tonic-gate
30277c478bd9Sstevel@tonic-gate /* Check if we are talking to the same device */
30287c478bd9Sstevel@tonic-gate if (usb_check_same_device(dip, hidp->hid_log_handle, USB_LOG_L2,
30297c478bd9Sstevel@tonic-gate PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
30307c478bd9Sstevel@tonic-gate
30317c478bd9Sstevel@tonic-gate /* change the device state from suspended to disconnected */
30327c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
30337c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_DISCONNECTED;
30347c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
30357c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
3036ac9468f8Spengcheng chen - Sun Microsystems - Beijing China goto nodev;
30377c478bd9Sstevel@tonic-gate }
30387c478bd9Sstevel@tonic-gate
30397c478bd9Sstevel@tonic-gate hid_set_idle(hidp);
30407c478bd9Sstevel@tonic-gate hid_set_protocol(hidp, SET_REPORT_PROTOCOL);
30417c478bd9Sstevel@tonic-gate
30427c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
30437c478bd9Sstevel@tonic-gate /* if the device had remote wakeup earlier, enable it again */
30447c478bd9Sstevel@tonic-gate if (hidpm->hid_wakeup_enabled) {
30457c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
30467c478bd9Sstevel@tonic-gate
30477c478bd9Sstevel@tonic-gate if ((rval = usb_handle_remote_wakeup(hidp->hid_dip,
30487c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE)) != USB_SUCCESS) {
30497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
30507c478bd9Sstevel@tonic-gate hidp->hid_log_handle,
30517c478bd9Sstevel@tonic-gate "usb_handle_remote_wakeup failed (%d)", rval);
30527c478bd9Sstevel@tonic-gate }
30537c478bd9Sstevel@tonic-gate
30547c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
30557c478bd9Sstevel@tonic-gate }
30567c478bd9Sstevel@tonic-gate
30577c478bd9Sstevel@tonic-gate /*
30587c478bd9Sstevel@tonic-gate * restart polling on the interrupt pipe only if the device
30597c478bd9Sstevel@tonic-gate * was previously operational (open)
30607c478bd9Sstevel@tonic-gate */
3061ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_OPEN(hidp)) {
30627c478bd9Sstevel@tonic-gate if ((rval = hid_start_intr_polling(hidp)) != USB_SUCCESS) {
30637c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
30647c478bd9Sstevel@tonic-gate "hid_restore_device_state:"
30657c478bd9Sstevel@tonic-gate "unable to restart intr pipe poll"
30667c478bd9Sstevel@tonic-gate " rval = %d ", rval);
30677c478bd9Sstevel@tonic-gate /*
30687c478bd9Sstevel@tonic-gate * change the device state from
30697c478bd9Sstevel@tonic-gate * suspended to disconnected
30707c478bd9Sstevel@tonic-gate */
30717c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_DISCONNECTED;
30727c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
30737c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
3074ac9468f8Spengcheng chen - Sun Microsystems - Beijing China goto nodev;
30757c478bd9Sstevel@tonic-gate }
30767c478bd9Sstevel@tonic-gate
30777c478bd9Sstevel@tonic-gate if (hidp->hid_dev_state == USB_DEV_DISCONNECTED) {
30787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
30797c478bd9Sstevel@tonic-gate "device is being re-connected");
30807c478bd9Sstevel@tonic-gate }
30817c478bd9Sstevel@tonic-gate
30827c478bd9Sstevel@tonic-gate /* set the device state ONLINE */
30837c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_ONLINE;
30847c478bd9Sstevel@tonic-gate
30857c478bd9Sstevel@tonic-gate /* inform upstream modules that the device is back */
3086ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_internal_flag == HID_STREAMS_OPEN) {
3087ddee57faSrui zang - Sun Microsystems - Beijing China q = hidp->hid_internal_rq;
3088ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
3089ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
3090ddee57faSrui zang - Sun Microsystems - Beijing China if (canputnext(q)) {
3091ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mp = allocb(sizeof (struct iocblk), BPRI_HI);
3092ac9468f8Spengcheng chen - Sun Microsystems - Beijing China if (mp != NULL) {
3093ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mp->b_datap->db_type = M_CTL;
3094ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mctlmsg = (struct iocblk *)
3095ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mp->b_datap->db_base;
3096ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mctlmsg->ioc_cmd = HID_CONNECT_EVENT;
3097ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mctlmsg->ioc_count = 0;
3098ddee57faSrui zang - Sun Microsystems - Beijing China putnext(q, mp);
3099ac9468f8Spengcheng chen - Sun Microsystems - Beijing China }
31007c478bd9Sstevel@tonic-gate }
3101ac9468f8Spengcheng chen - Sun Microsystems - Beijing China /* enable write side q */
3102ddee57faSrui zang - Sun Microsystems - Beijing China qenable(WR(q));
3103ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
3104ddee57faSrui zang - Sun Microsystems - Beijing China }
3105ddee57faSrui zang - Sun Microsystems - Beijing China
3106ddee57faSrui zang - Sun Microsystems - Beijing China if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
3107ddee57faSrui zang - Sun Microsystems - Beijing China q = hidp->hid_external_rq;
3108ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
3109ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
3110ddee57faSrui zang - Sun Microsystems - Beijing China if (canputnext(q)) {
3111ddee57faSrui zang - Sun Microsystems - Beijing China mp = allocb(sizeof (struct iocblk), BPRI_HI);
3112ddee57faSrui zang - Sun Microsystems - Beijing China if (mp != NULL) {
3113ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_type = M_CTL;
3114ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg = (struct iocblk *)
3115ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_base;
3116ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg->ioc_cmd = HID_CONNECT_EVENT;
3117ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg->ioc_count = 0;
3118ddee57faSrui zang - Sun Microsystems - Beijing China putnext(q, mp);
3119ddee57faSrui zang - Sun Microsystems - Beijing China }
3120ddee57faSrui zang - Sun Microsystems - Beijing China }
3121ddee57faSrui zang - Sun Microsystems - Beijing China /* enable write side q */
3122ddee57faSrui zang - Sun Microsystems - Beijing China qenable(WR(q));
3123ddee57faSrui zang - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
31247c478bd9Sstevel@tonic-gate }
31257c478bd9Sstevel@tonic-gate } else {
31267c478bd9Sstevel@tonic-gate /* set the device state ONLINE */
31277c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_ONLINE;
31287c478bd9Sstevel@tonic-gate }
31297c478bd9Sstevel@tonic-gate
31307c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
31317c478bd9Sstevel@tonic-gate hid_pm_idle_component(hidp);
3132ac9468f8Spengcheng chen - Sun Microsystems - Beijing China return;
3133ac9468f8Spengcheng chen - Sun Microsystems - Beijing China
3134ac9468f8Spengcheng chen - Sun Microsystems - Beijing China nodev:
3135ac9468f8Spengcheng chen - Sun Microsystems - Beijing China /*
3136ac9468f8Spengcheng chen - Sun Microsystems - Beijing China * Notify applications about device removal. This only
3137ac9468f8Spengcheng chen - Sun Microsystems - Beijing China * applies to an external (aka. physical) open. Not sure how to
3138ac9468f8Spengcheng chen - Sun Microsystems - Beijing China * notify consconfig to close the internal minor node.
3139ac9468f8Spengcheng chen - Sun Microsystems - Beijing China */
3140ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_enter(&hidp->hid_mutex);
3141ddee57faSrui zang - Sun Microsystems - Beijing China
3142ddee57faSrui zang - Sun Microsystems - Beijing China if ((q = hidp->hid_external_rq) == NULL) {
3143ddee57faSrui zang - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
3144ddee57faSrui zang - Sun Microsystems - Beijing China return;
3145ac9468f8Spengcheng chen - Sun Microsystems - Beijing China }
3146ddee57faSrui zang - Sun Microsystems - Beijing China
3147ac9468f8Spengcheng chen - Sun Microsystems - Beijing China mutex_exit(&hidp->hid_mutex);
3148ddee57faSrui zang - Sun Microsystems - Beijing China mp = allocb(sizeof (uchar_t), BPRI_HI);
3149ddee57faSrui zang - Sun Microsystems - Beijing China if (mp != NULL) {
3150ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_type = M_ERROR;
3151ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_rptr = mp->b_datap->db_base;
3152ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_wptr = mp->b_rptr + sizeof (char);
3153ddee57faSrui zang - Sun Microsystems - Beijing China *mp->b_rptr = ENODEV;
3154ddee57faSrui zang - Sun Microsystems - Beijing China putnext(q, mp);
3155ddee57faSrui zang - Sun Microsystems - Beijing China }
31567c478bd9Sstevel@tonic-gate }
31577c478bd9Sstevel@tonic-gate
31587c478bd9Sstevel@tonic-gate
31597c478bd9Sstevel@tonic-gate /*
31607c478bd9Sstevel@tonic-gate * hid_qreply_merror:
31617c478bd9Sstevel@tonic-gate * Pass an error message up.
31627c478bd9Sstevel@tonic-gate */
31637c478bd9Sstevel@tonic-gate static void
hid_qreply_merror(queue_t * q,mblk_t * mp,uchar_t errval)31647c478bd9Sstevel@tonic-gate hid_qreply_merror(queue_t *q, mblk_t *mp, uchar_t errval)
31657c478bd9Sstevel@tonic-gate {
31667c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR;
31677c478bd9Sstevel@tonic-gate if (mp->b_cont) {
31687c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
31697c478bd9Sstevel@tonic-gate mp->b_cont = NULL;
31707c478bd9Sstevel@tonic-gate }
31717c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base;
31727c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char);
31737c478bd9Sstevel@tonic-gate *mp->b_rptr = errval;
31747c478bd9Sstevel@tonic-gate
31757c478bd9Sstevel@tonic-gate qreply(q, mp);
31767c478bd9Sstevel@tonic-gate }
31777c478bd9Sstevel@tonic-gate
31787c478bd9Sstevel@tonic-gate
31797c478bd9Sstevel@tonic-gate /*
31807c478bd9Sstevel@tonic-gate * hid_data2mblk:
31817c478bd9Sstevel@tonic-gate * Form an mblk from the given data
31827c478bd9Sstevel@tonic-gate */
31837c478bd9Sstevel@tonic-gate static mblk_t *
hid_data2mblk(uchar_t * buf,int len)31847c478bd9Sstevel@tonic-gate hid_data2mblk(uchar_t *buf, int len)
31857c478bd9Sstevel@tonic-gate {
31867c478bd9Sstevel@tonic-gate mblk_t *mp = NULL;
31877c478bd9Sstevel@tonic-gate
31887c478bd9Sstevel@tonic-gate if (len >= 0) {
31897c478bd9Sstevel@tonic-gate mp = allocb(len, BPRI_HI);
31907c478bd9Sstevel@tonic-gate if (mp) {
31917c478bd9Sstevel@tonic-gate bcopy(buf, mp->b_datap->db_base, len);
31927c478bd9Sstevel@tonic-gate mp->b_wptr += len;
31937c478bd9Sstevel@tonic-gate }
31947c478bd9Sstevel@tonic-gate }
31957c478bd9Sstevel@tonic-gate
31967c478bd9Sstevel@tonic-gate return (mp);
31977c478bd9Sstevel@tonic-gate }
31987c478bd9Sstevel@tonic-gate
31997c478bd9Sstevel@tonic-gate
32007c478bd9Sstevel@tonic-gate /*
32017c478bd9Sstevel@tonic-gate * hid_flush :
32027c478bd9Sstevel@tonic-gate * Flush data already sent upstreams to client module.
32037c478bd9Sstevel@tonic-gate */
32047c478bd9Sstevel@tonic-gate static void
hid_flush(queue_t * q)32057c478bd9Sstevel@tonic-gate hid_flush(queue_t *q)
32067c478bd9Sstevel@tonic-gate {
32077c478bd9Sstevel@tonic-gate /*
32087c478bd9Sstevel@tonic-gate * Flush pending data already sent upstream
32097c478bd9Sstevel@tonic-gate */
32107c478bd9Sstevel@tonic-gate if ((q != NULL) && (q->q_next != NULL)) {
32117c478bd9Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHR);
32127c478bd9Sstevel@tonic-gate }
32137c478bd9Sstevel@tonic-gate }
32147c478bd9Sstevel@tonic-gate
32157c478bd9Sstevel@tonic-gate
32167c478bd9Sstevel@tonic-gate static void
hid_pm_busy_component(hid_state_t * hid_statep)32177c478bd9Sstevel@tonic-gate hid_pm_busy_component(hid_state_t *hid_statep)
32187c478bd9Sstevel@tonic-gate {
32197c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&hid_statep->hid_mutex));
32207c478bd9Sstevel@tonic-gate
32217c478bd9Sstevel@tonic-gate if (hid_statep->hid_pm != NULL) {
32227c478bd9Sstevel@tonic-gate mutex_enter(&hid_statep->hid_mutex);
32237c478bd9Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy++;
32247c478bd9Sstevel@tonic-gate
32257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hid_statep->hid_log_handle,
32267c478bd9Sstevel@tonic-gate "hid_pm_busy_component: %d",
32277c478bd9Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy);
32287c478bd9Sstevel@tonic-gate
32297c478bd9Sstevel@tonic-gate mutex_exit(&hid_statep->hid_mutex);
32307c478bd9Sstevel@tonic-gate if (pm_busy_component(hid_statep->hid_dip, 0) != DDI_SUCCESS) {
32317c478bd9Sstevel@tonic-gate mutex_enter(&hid_statep->hid_mutex);
32327c478bd9Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy--;
32337c478bd9Sstevel@tonic-gate
32347c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM,
32357c478bd9Sstevel@tonic-gate hid_statep->hid_log_handle,
32367c478bd9Sstevel@tonic-gate "hid_pm_busy_component failed: %d",
32377c478bd9Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy);
32387c478bd9Sstevel@tonic-gate
32397c478bd9Sstevel@tonic-gate mutex_exit(&hid_statep->hid_mutex);
32407c478bd9Sstevel@tonic-gate }
32417c478bd9Sstevel@tonic-gate
32427c478bd9Sstevel@tonic-gate }
32437c478bd9Sstevel@tonic-gate }
32447c478bd9Sstevel@tonic-gate
32457c478bd9Sstevel@tonic-gate
32467c478bd9Sstevel@tonic-gate static void
hid_pm_idle_component(hid_state_t * hid_statep)32477c478bd9Sstevel@tonic-gate hid_pm_idle_component(hid_state_t *hid_statep)
32487c478bd9Sstevel@tonic-gate {
32497c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&hid_statep->hid_mutex));
32507c478bd9Sstevel@tonic-gate
32517c478bd9Sstevel@tonic-gate if (hid_statep->hid_pm != NULL) {
32527c478bd9Sstevel@tonic-gate if (pm_idle_component(hid_statep->hid_dip, 0) == DDI_SUCCESS) {
32537c478bd9Sstevel@tonic-gate mutex_enter(&hid_statep->hid_mutex);
32547c478bd9Sstevel@tonic-gate ASSERT(hid_statep->hid_pm->hid_pm_busy > 0);
32557c478bd9Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy--;
32567c478bd9Sstevel@tonic-gate
32577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM,
32587c478bd9Sstevel@tonic-gate hid_statep->hid_log_handle,
32597c478bd9Sstevel@tonic-gate "hid_pm_idle_component: %d",
32607c478bd9Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy);
32617c478bd9Sstevel@tonic-gate
32627c478bd9Sstevel@tonic-gate mutex_exit(&hid_statep->hid_mutex);
32637c478bd9Sstevel@tonic-gate }
32647c478bd9Sstevel@tonic-gate }
32657c478bd9Sstevel@tonic-gate }
32667c478bd9Sstevel@tonic-gate
32677c478bd9Sstevel@tonic-gate
32687c478bd9Sstevel@tonic-gate /*
32697c478bd9Sstevel@tonic-gate * hid_pwrlvl0:
32707c478bd9Sstevel@tonic-gate * Functions to handle power transition for various levels
32717c478bd9Sstevel@tonic-gate * These functions act as place holders to issue USB commands
32727c478bd9Sstevel@tonic-gate * to the devices to change their power levels
32737c478bd9Sstevel@tonic-gate */
32747c478bd9Sstevel@tonic-gate static int
hid_pwrlvl0(hid_state_t * hidp)32757c478bd9Sstevel@tonic-gate hid_pwrlvl0(hid_state_t *hidp)
32767c478bd9Sstevel@tonic-gate {
32777c478bd9Sstevel@tonic-gate hid_power_t *hidpm;
32787c478bd9Sstevel@tonic-gate int rval;
32797c478bd9Sstevel@tonic-gate struct iocblk *mctlmsg;
32807c478bd9Sstevel@tonic-gate mblk_t *mp_lowpwr, *mp_fullpwr;
32817c478bd9Sstevel@tonic-gate queue_t *q;
32827c478bd9Sstevel@tonic-gate
32837c478bd9Sstevel@tonic-gate hidpm = hidp->hid_pm;
32847c478bd9Sstevel@tonic-gate
32857c478bd9Sstevel@tonic-gate switch (hidp->hid_dev_state) {
32867c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE:
32877c478bd9Sstevel@tonic-gate /* Deny the powerdown request if the device is busy */
32887c478bd9Sstevel@tonic-gate if (hidpm->hid_pm_busy != 0) {
32897c478bd9Sstevel@tonic-gate
32907c478bd9Sstevel@tonic-gate return (USB_FAILURE);
32917c478bd9Sstevel@tonic-gate }
32927c478bd9Sstevel@tonic-gate
3293ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_OPEN(hidp)) {
3294ddee57faSrui zang - Sun Microsystems - Beijing China q = hidp->hid_inuse_rq;
32957c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
32967c478bd9Sstevel@tonic-gate if (canputnext(q)) {
32977c478bd9Sstevel@tonic-gate /* try to preallocate mblks */
32987c478bd9Sstevel@tonic-gate mp_lowpwr = allocb(
32997c478bd9Sstevel@tonic-gate (int)sizeof (struct iocblk), BPRI_HI);
33007c478bd9Sstevel@tonic-gate mp_fullpwr = allocb(
33017c478bd9Sstevel@tonic-gate (int)sizeof (struct iocblk), BPRI_HI);
33027c478bd9Sstevel@tonic-gate if ((mp_lowpwr != NULL) &&
33037c478bd9Sstevel@tonic-gate (mp_fullpwr != NULL)) {
33047c478bd9Sstevel@tonic-gate /* stop polling */
33057c478bd9Sstevel@tonic-gate usb_pipe_stop_intr_polling(
33067c478bd9Sstevel@tonic-gate hidp->hid_interrupt_pipe,
33077c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP);
33087c478bd9Sstevel@tonic-gate
33097c478bd9Sstevel@tonic-gate /*
33107c478bd9Sstevel@tonic-gate * Send an MCTL up indicating that
33117c478bd9Sstevel@tonic-gate * we are powering off
33127c478bd9Sstevel@tonic-gate */
33137c478bd9Sstevel@tonic-gate mp_lowpwr->b_datap->db_type = M_CTL;
33147c478bd9Sstevel@tonic-gate mctlmsg = (struct iocblk *)
33157c478bd9Sstevel@tonic-gate mp_lowpwr->b_datap->db_base;
33167c478bd9Sstevel@tonic-gate mctlmsg->ioc_cmd = HID_POWER_OFF;
33177c478bd9Sstevel@tonic-gate mctlmsg->ioc_count = 0;
33187c478bd9Sstevel@tonic-gate putnext(q, mp_lowpwr);
33197c478bd9Sstevel@tonic-gate
33207c478bd9Sstevel@tonic-gate /* save the full powr mblk */
33217c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
33227c478bd9Sstevel@tonic-gate hidpm->hid_pm_pwrup = mp_fullpwr;
33237c478bd9Sstevel@tonic-gate } else {
33247c478bd9Sstevel@tonic-gate /*
33257c478bd9Sstevel@tonic-gate * Since we failed to allocate one
33267c478bd9Sstevel@tonic-gate * or more mblks, we fail attempt
33277c478bd9Sstevel@tonic-gate * to go into low power this time
33287c478bd9Sstevel@tonic-gate */
33297c478bd9Sstevel@tonic-gate freemsg(mp_lowpwr);
33307c478bd9Sstevel@tonic-gate freemsg(mp_fullpwr);
33317c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
33327c478bd9Sstevel@tonic-gate
33337c478bd9Sstevel@tonic-gate return (USB_FAILURE);
33347c478bd9Sstevel@tonic-gate }
33357c478bd9Sstevel@tonic-gate } else {
33367c478bd9Sstevel@tonic-gate /*
33377c478bd9Sstevel@tonic-gate * Since we can't send an mblk up,
33387c478bd9Sstevel@tonic-gate * we fail this attempt to go to low power
33397c478bd9Sstevel@tonic-gate */
33407c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
33417c478bd9Sstevel@tonic-gate
33427c478bd9Sstevel@tonic-gate return (USB_FAILURE);
33437c478bd9Sstevel@tonic-gate }
33447c478bd9Sstevel@tonic-gate }
3345ddee57faSrui zang - Sun Microsystems - Beijing China
33467c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
33477c478bd9Sstevel@tonic-gate /* Issue USB D3 command to the device here */
33487c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl3(hidp->hid_dip);
33497c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
33507c478bd9Sstevel@tonic-gate
33517c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
33527c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_PWRED_DOWN;
33537c478bd9Sstevel@tonic-gate hidpm->hid_current_power = USB_DEV_OS_PWR_OFF;
33547c478bd9Sstevel@tonic-gate
33557c478bd9Sstevel@tonic-gate /* FALLTHRU */
33567c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED:
33577c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED:
33587c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
33597c478bd9Sstevel@tonic-gate default:
33607c478bd9Sstevel@tonic-gate break;
33617c478bd9Sstevel@tonic-gate }
33627c478bd9Sstevel@tonic-gate
33637c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
33647c478bd9Sstevel@tonic-gate }
33657c478bd9Sstevel@tonic-gate
33667c478bd9Sstevel@tonic-gate
33677c478bd9Sstevel@tonic-gate /* ARGSUSED */
33687c478bd9Sstevel@tonic-gate static int
hid_pwrlvl1(hid_state_t * hidp)33697c478bd9Sstevel@tonic-gate hid_pwrlvl1(hid_state_t *hidp)
33707c478bd9Sstevel@tonic-gate {
33717c478bd9Sstevel@tonic-gate int rval;
33727c478bd9Sstevel@tonic-gate
33737c478bd9Sstevel@tonic-gate /* Issue USB D2 command to the device here */
33747c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl2(hidp->hid_dip);
33757c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
33767c478bd9Sstevel@tonic-gate
33777c478bd9Sstevel@tonic-gate return (USB_FAILURE);
33787c478bd9Sstevel@tonic-gate }
33797c478bd9Sstevel@tonic-gate
33807c478bd9Sstevel@tonic-gate
33817c478bd9Sstevel@tonic-gate /* ARGSUSED */
33827c478bd9Sstevel@tonic-gate static int
hid_pwrlvl2(hid_state_t * hidp)33837c478bd9Sstevel@tonic-gate hid_pwrlvl2(hid_state_t *hidp)
33847c478bd9Sstevel@tonic-gate {
33857c478bd9Sstevel@tonic-gate int rval;
33867c478bd9Sstevel@tonic-gate
33877c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl1(hidp->hid_dip);
33887c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
33897c478bd9Sstevel@tonic-gate
33907c478bd9Sstevel@tonic-gate return (USB_FAILURE);
33917c478bd9Sstevel@tonic-gate }
33927c478bd9Sstevel@tonic-gate
33937c478bd9Sstevel@tonic-gate
33947c478bd9Sstevel@tonic-gate static int
hid_pwrlvl3(hid_state_t * hidp)33957c478bd9Sstevel@tonic-gate hid_pwrlvl3(hid_state_t *hidp)
33967c478bd9Sstevel@tonic-gate {
33977c478bd9Sstevel@tonic-gate hid_power_t *hidpm;
33987c478bd9Sstevel@tonic-gate int rval;
33997c478bd9Sstevel@tonic-gate struct iocblk *mctlmsg;
34007c478bd9Sstevel@tonic-gate mblk_t *mp;
34017c478bd9Sstevel@tonic-gate queue_t *q;
34027c478bd9Sstevel@tonic-gate
34037c478bd9Sstevel@tonic-gate hidpm = hidp->hid_pm;
34047c478bd9Sstevel@tonic-gate
34057c478bd9Sstevel@tonic-gate switch (hidp->hid_dev_state) {
34067c478bd9Sstevel@tonic-gate case USB_DEV_HID_POWER_CHANGE:
34077c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
34087c478bd9Sstevel@tonic-gate /* Issue USB D0 command to the device here */
34097c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl0(hidp->hid_dip);
34107c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
34117c478bd9Sstevel@tonic-gate
3412ddee57faSrui zang - Sun Microsystems - Beijing China if (HID_IS_OPEN(hidp)) {
34137c478bd9Sstevel@tonic-gate /* restart polling on intr pipe */
34147c478bd9Sstevel@tonic-gate rval = hid_start_intr_polling(hidp);
34157c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
34167c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS,
34177c478bd9Sstevel@tonic-gate hidp->hid_log_handle,
34187c478bd9Sstevel@tonic-gate "unable to restart intr polling rval = %d",
34197c478bd9Sstevel@tonic-gate rval);
34207c478bd9Sstevel@tonic-gate
34217c478bd9Sstevel@tonic-gate return (USB_FAILURE);
34227c478bd9Sstevel@tonic-gate }
34237c478bd9Sstevel@tonic-gate
34247c478bd9Sstevel@tonic-gate /* Send an MCTL up indicating device in full power */
3425ddee57faSrui zang - Sun Microsystems - Beijing China q = hidp->hid_inuse_rq;
34267c478bd9Sstevel@tonic-gate mp = hidpm->hid_pm_pwrup;
34277c478bd9Sstevel@tonic-gate hidpm->hid_pm_pwrup = NULL;
34287c478bd9Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
34297c478bd9Sstevel@tonic-gate if (canputnext(q)) {
34307c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_CTL;
3431ddee57faSrui zang - Sun Microsystems - Beijing China mctlmsg = (struct iocblk *)
3432ddee57faSrui zang - Sun Microsystems - Beijing China mp->b_datap->db_base;
34337c478bd9Sstevel@tonic-gate mctlmsg->ioc_cmd = HID_FULL_POWER;
34347c478bd9Sstevel@tonic-gate mctlmsg->ioc_count = 0;
34357c478bd9Sstevel@tonic-gate putnext(q, mp);
34367c478bd9Sstevel@tonic-gate } else {
34377c478bd9Sstevel@tonic-gate freemsg(mp);
34387c478bd9Sstevel@tonic-gate }
34397c478bd9Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
34407c478bd9Sstevel@tonic-gate }
3441ddee57faSrui zang - Sun Microsystems - Beijing China
34427c478bd9Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_ONLINE;
34437c478bd9Sstevel@tonic-gate hidpm->hid_current_power = USB_DEV_OS_FULL_PWR;
34447c478bd9Sstevel@tonic-gate
34457c478bd9Sstevel@tonic-gate /* FALLTHRU */
34467c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED:
34477c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED:
34487c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE:
34497c478bd9Sstevel@tonic-gate
34507c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
34517c478bd9Sstevel@tonic-gate default:
34527c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
34537c478bd9Sstevel@tonic-gate "hid_pwrlvl3: Improper State");
34547c478bd9Sstevel@tonic-gate
34557c478bd9Sstevel@tonic-gate return (USB_FAILURE);
34567c478bd9Sstevel@tonic-gate }
34577c478bd9Sstevel@tonic-gate }
34587c478bd9Sstevel@tonic-gate
34597c478bd9Sstevel@tonic-gate
34607c478bd9Sstevel@tonic-gate /*
34617c478bd9Sstevel@tonic-gate * hid_polled_input_init :
34627c478bd9Sstevel@tonic-gate * This routine calls down to the lower layers to initialize any state
34637c478bd9Sstevel@tonic-gate * information. This routine initializes the lower layers for input.
34647c478bd9Sstevel@tonic-gate */
34657c478bd9Sstevel@tonic-gate static int
hid_polled_input_init(hid_state_t * hidp)34667c478bd9Sstevel@tonic-gate hid_polled_input_init(hid_state_t *hidp)
34677c478bd9Sstevel@tonic-gate {
34687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
34697c478bd9Sstevel@tonic-gate "hid_polled_input_init");
34707c478bd9Sstevel@tonic-gate
34717c478bd9Sstevel@tonic-gate /*
34727c478bd9Sstevel@tonic-gate * Call the lower layers to intialize any state information
34737c478bd9Sstevel@tonic-gate * that they will need to provide the polled characters.
34747c478bd9Sstevel@tonic-gate */
34757c478bd9Sstevel@tonic-gate if (usb_console_input_init(hidp->hid_dip, hidp->hid_interrupt_pipe,
34767c478bd9Sstevel@tonic-gate &hidp->hid_polled_raw_buf,
34777c478bd9Sstevel@tonic-gate &hidp->hid_polled_console_info) != USB_SUCCESS) {
34787c478bd9Sstevel@tonic-gate /*
34797c478bd9Sstevel@tonic-gate * If for some reason the lower layers cannot initialized, then
34807c478bd9Sstevel@tonic-gate * bail.
34817c478bd9Sstevel@tonic-gate */
34827c478bd9Sstevel@tonic-gate (void) hid_polled_input_fini(hidp);
34837c478bd9Sstevel@tonic-gate
34847c478bd9Sstevel@tonic-gate return (USB_FAILURE);
34857c478bd9Sstevel@tonic-gate }
34867c478bd9Sstevel@tonic-gate
34877c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
34887c478bd9Sstevel@tonic-gate }
34897c478bd9Sstevel@tonic-gate
34907c478bd9Sstevel@tonic-gate
34917c478bd9Sstevel@tonic-gate /*
34927c478bd9Sstevel@tonic-gate * hid_polled_input_fini:
34937c478bd9Sstevel@tonic-gate * This routine is called when we are done using this device as an input
34947c478bd9Sstevel@tonic-gate * device.
34957c478bd9Sstevel@tonic-gate */
34967c478bd9Sstevel@tonic-gate static int
hid_polled_input_fini(hid_state_t * hidp)34977c478bd9Sstevel@tonic-gate hid_polled_input_fini(hid_state_t *hidp)
34987c478bd9Sstevel@tonic-gate {
34997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
35007c478bd9Sstevel@tonic-gate "hid_polled_input_fini");
35017c478bd9Sstevel@tonic-gate
35027c478bd9Sstevel@tonic-gate /*
35037c478bd9Sstevel@tonic-gate * Call the lower layers to free any state information
35047c478bd9Sstevel@tonic-gate * only if polled input has been initialised.
35057c478bd9Sstevel@tonic-gate */
35067c478bd9Sstevel@tonic-gate if ((hidp->hid_polled_console_info) &&
35077c478bd9Sstevel@tonic-gate (usb_console_input_fini(hidp->hid_polled_console_info) !=
35087c478bd9Sstevel@tonic-gate USB_SUCCESS)) {
35097c478bd9Sstevel@tonic-gate
35107c478bd9Sstevel@tonic-gate return (USB_FAILURE);
35117c478bd9Sstevel@tonic-gate }
35127c478bd9Sstevel@tonic-gate hidp->hid_polled_console_info = NULL;
35137c478bd9Sstevel@tonic-gate
35147c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
35157c478bd9Sstevel@tonic-gate }
35167c478bd9Sstevel@tonic-gate
35177c478bd9Sstevel@tonic-gate
35187c478bd9Sstevel@tonic-gate /*
35197c478bd9Sstevel@tonic-gate * hid_polled_input_enter:
35207c478bd9Sstevel@tonic-gate * This is the routine that is called in polled mode to save the USB
35217c478bd9Sstevel@tonic-gate * state information before using the USB keyboard as an input device.
35227c478bd9Sstevel@tonic-gate * This routine, and all of the routines that it calls, are responsible
35237c478bd9Sstevel@tonic-gate * for saving any state information so that it can be restored when
35247c478bd9Sstevel@tonic-gate * polling mode is over.
35257c478bd9Sstevel@tonic-gate */
35267c478bd9Sstevel@tonic-gate static int
35277c478bd9Sstevel@tonic-gate /* ARGSUSED */
hid_polled_input_enter(hid_polled_handle_t hid_polled_inputp)35287c478bd9Sstevel@tonic-gate hid_polled_input_enter(hid_polled_handle_t hid_polled_inputp)
35297c478bd9Sstevel@tonic-gate {
35307c478bd9Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)hid_polled_inputp;
35317c478bd9Sstevel@tonic-gate
35327c478bd9Sstevel@tonic-gate /*
35337c478bd9Sstevel@tonic-gate * Call the lower layers to tell them to save any state information.
35347c478bd9Sstevel@tonic-gate */
35357c478bd9Sstevel@tonic-gate (void) usb_console_input_enter(hidp->hid_polled_console_info);
35367c478bd9Sstevel@tonic-gate
35377c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
35387c478bd9Sstevel@tonic-gate }
35397c478bd9Sstevel@tonic-gate
35407c478bd9Sstevel@tonic-gate
35417c478bd9Sstevel@tonic-gate /*
35427c478bd9Sstevel@tonic-gate * hid_polled_read :
35437c478bd9Sstevel@tonic-gate * This is the routine that is called in polled mode when it wants to read
35447c478bd9Sstevel@tonic-gate * a character. We will call to the lower layers to see if there is any
35457c478bd9Sstevel@tonic-gate * input data available. If there is USB scancodes available, we will
35467c478bd9Sstevel@tonic-gate * give them back.
35477c478bd9Sstevel@tonic-gate */
35487c478bd9Sstevel@tonic-gate static int
hid_polled_read(hid_polled_handle_t hid_polled_input,uchar_t ** buffer)35497c478bd9Sstevel@tonic-gate hid_polled_read(hid_polled_handle_t hid_polled_input, uchar_t **buffer)
35507c478bd9Sstevel@tonic-gate {
35517c478bd9Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)hid_polled_input;
35527c478bd9Sstevel@tonic-gate uint_t num_bytes;
35537c478bd9Sstevel@tonic-gate
35547c478bd9Sstevel@tonic-gate /*
35557c478bd9Sstevel@tonic-gate * Call the lower layers to get the character from the controller.
35567c478bd9Sstevel@tonic-gate * The lower layers will return the number of characters that
35577c478bd9Sstevel@tonic-gate * were put in the raw buffer. The address of the raw buffer
35587c478bd9Sstevel@tonic-gate * was passed down to the lower layers during hid_polled_init.
35597c478bd9Sstevel@tonic-gate */
35607c478bd9Sstevel@tonic-gate if (usb_console_read(hidp->hid_polled_console_info,
35617c478bd9Sstevel@tonic-gate &num_bytes) != USB_SUCCESS) {
35627c478bd9Sstevel@tonic-gate
35637c478bd9Sstevel@tonic-gate return (0);
35647c478bd9Sstevel@tonic-gate }
35657c478bd9Sstevel@tonic-gate
35667c478bd9Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW);
35677c478bd9Sstevel@tonic-gate
35687c478bd9Sstevel@tonic-gate *buffer = hidp->hid_polled_raw_buf;
35697c478bd9Sstevel@tonic-gate
35707c478bd9Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
35717c478bd9Sstevel@tonic-gate
35727c478bd9Sstevel@tonic-gate /*
35737c478bd9Sstevel@tonic-gate * Return the number of characters that were copied into the
35747c478bd9Sstevel@tonic-gate * polled buffer.
35757c478bd9Sstevel@tonic-gate */
35767c478bd9Sstevel@tonic-gate return (num_bytes);
35777c478bd9Sstevel@tonic-gate }
35787c478bd9Sstevel@tonic-gate
35797c478bd9Sstevel@tonic-gate
35807c478bd9Sstevel@tonic-gate /*
35817c478bd9Sstevel@tonic-gate * hid_polled_input_exit :
35827c478bd9Sstevel@tonic-gate * This is the routine that is called in polled mode when it is giving up
35837c478bd9Sstevel@tonic-gate * control of the USB keyboard. This routine, and the lower layer routines
35847c478bd9Sstevel@tonic-gate * that it calls, are responsible for restoring the controller state to the
35857c478bd9Sstevel@tonic-gate * state it was in before polled mode.
35867c478bd9Sstevel@tonic-gate */
35877c478bd9Sstevel@tonic-gate static int
hid_polled_input_exit(hid_polled_handle_t hid_polled_inputp)35887c478bd9Sstevel@tonic-gate hid_polled_input_exit(hid_polled_handle_t hid_polled_inputp)
35897c478bd9Sstevel@tonic-gate {
35907c478bd9Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)hid_polled_inputp;
35917c478bd9Sstevel@tonic-gate
35927c478bd9Sstevel@tonic-gate /*
35937c478bd9Sstevel@tonic-gate * Call the lower layers to restore any state information.
35947c478bd9Sstevel@tonic-gate */
35957c478bd9Sstevel@tonic-gate (void) usb_console_input_exit(hidp->hid_polled_console_info);
35967c478bd9Sstevel@tonic-gate
35977c478bd9Sstevel@tonic-gate return (0);
35987c478bd9Sstevel@tonic-gate }
3599