10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51244Scg149915 * Common Development and Distribution License (the "License").
61244Scg149915 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
211244Scg149915
220Sstevel@tonic-gate /*
2312419SFei.Feng@Sun.COM * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * Human Interface Device driver (HID)
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * The HID driver is a software driver which acts as a class
310Sstevel@tonic-gate * driver for USB human input devices like keyboard, mouse,
320Sstevel@tonic-gate * joystick etc and provides the class-specific interfaces
330Sstevel@tonic-gate * between these client driver modules and the Universal Serial
340Sstevel@tonic-gate * Bus Driver(USBA).
350Sstevel@tonic-gate *
360Sstevel@tonic-gate * NOTE: This driver is not DDI compliant in that it uses undocumented
370Sstevel@tonic-gate * functions for logging (USB_DPRINTF_L*, usb_alloc_log_hdl, usb_free_log_hdl).
380Sstevel@tonic-gate *
390Sstevel@tonic-gate * Undocumented functions may go away in a future Solaris OS release.
400Sstevel@tonic-gate *
410Sstevel@tonic-gate * Please see the DDK for sample code of these functions, and for the usbskel
420Sstevel@tonic-gate * skeleton template driver which contains scaled-down versions of these
430Sstevel@tonic-gate * functions written in a DDI-compliant way.
440Sstevel@tonic-gate */
450Sstevel@tonic-gate
460Sstevel@tonic-gate #define USBDRV_MAJOR_VER 2
470Sstevel@tonic-gate #define USBDRV_MINOR_VER 0
480Sstevel@tonic-gate
490Sstevel@tonic-gate #include <sys/usb/usba.h>
500Sstevel@tonic-gate #include <sys/usb/usba/genconsole.h>
510Sstevel@tonic-gate #include <sys/usb/clients/hid/hid.h>
520Sstevel@tonic-gate #include <sys/usb/clients/hid/hid_polled.h>
530Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hidparser.h>
540Sstevel@tonic-gate #include <sys/usb/clients/hid/hidvar.h>
550Sstevel@tonic-gate #include <sys/usb/clients/hid/hidminor.h>
560Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hid_parser_driver.h>
570Sstevel@tonic-gate #include <sys/stropts.h>
581244Scg149915 #include <sys/sunddi.h>
5910153SAaron.Zang@Sun.COM #include <sys/stream.h>
6010153SAaron.Zang@Sun.COM #include <sys/strsun.h>
610Sstevel@tonic-gate
620Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
631244Scg149915
640Sstevel@tonic-gate /* Debugging support */
65880Sfrits uint_t hid_errmask = (uint_t)PRINT_MASK_ALL;
66880Sfrits uint_t hid_errlevel = USB_LOG_L4;
67880Sfrits uint_t hid_instance_debug = (uint_t)-1;
680Sstevel@tonic-gate
690Sstevel@tonic-gate /* tunables */
700Sstevel@tonic-gate int hid_default_pipe_drain_timeout = HID_DEFAULT_PIPE_DRAIN_TIMEOUT;
71*12819SVincent.Wang@Sun.COM int hid_pm_mouse = 1; /* enable remote_wakeup for USB mouse/keyboard */
720Sstevel@tonic-gate
730Sstevel@tonic-gate /* soft state structures */
740Sstevel@tonic-gate #define HID_INITIAL_SOFT_SPACE 4
750Sstevel@tonic-gate static void *hid_statep;
760Sstevel@tonic-gate
770Sstevel@tonic-gate /* Callbacks */
780Sstevel@tonic-gate static void hid_interrupt_pipe_callback(usb_pipe_handle_t,
790Sstevel@tonic-gate usb_intr_req_t *);
800Sstevel@tonic-gate static void hid_default_pipe_callback(usb_pipe_handle_t, usb_ctrl_req_t *);
810Sstevel@tonic-gate static void hid_interrupt_pipe_exception_callback(usb_pipe_handle_t,
820Sstevel@tonic-gate usb_intr_req_t *);
830Sstevel@tonic-gate static void hid_default_pipe_exception_callback(usb_pipe_handle_t,
840Sstevel@tonic-gate usb_ctrl_req_t *);
850Sstevel@tonic-gate static int hid_restore_state_event_callback(dev_info_t *);
860Sstevel@tonic-gate static int hid_disconnect_event_callback(dev_info_t *);
870Sstevel@tonic-gate static int hid_cpr_suspend(hid_state_t *hidp);
880Sstevel@tonic-gate static void hid_cpr_resume(hid_state_t *hidp);
890Sstevel@tonic-gate static void hid_power_change_callback(void *arg, int rval);
900Sstevel@tonic-gate
910Sstevel@tonic-gate /* Supporting routines */
920Sstevel@tonic-gate static size_t hid_parse_hid_descr(usb_hid_descr_t *, size_t,
930Sstevel@tonic-gate usb_alt_if_data_t *, usb_ep_data_t *);
940Sstevel@tonic-gate static int hid_parse_hid_descr_failure(hid_state_t *);
950Sstevel@tonic-gate static int hid_handle_report_descriptor(hid_state_t *, int);
960Sstevel@tonic-gate static void hid_set_idle(hid_state_t *);
970Sstevel@tonic-gate static void hid_set_protocol(hid_state_t *, int);
980Sstevel@tonic-gate static void hid_detach_cleanup(dev_info_t *, hid_state_t *);
990Sstevel@tonic-gate
1000Sstevel@tonic-gate static int hid_start_intr_polling(hid_state_t *);
1010Sstevel@tonic-gate static void hid_close_intr_pipe(hid_state_t *);
1029432SPengcheng.Chen@Sun.COM static int hid_mctl_execute_cmd(queue_t *, int, hid_req_t *,
1039432SPengcheng.Chen@Sun.COM mblk_t *);
1040Sstevel@tonic-gate static int hid_mctl_receive(queue_t *, mblk_t *);
1059432SPengcheng.Chen@Sun.COM static int hid_send_async_ctrl_request(hid_default_pipe_arg_t *, hid_req_t *,
1069432SPengcheng.Chen@Sun.COM uchar_t, int, ushort_t);
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate static void hid_create_pm_components(dev_info_t *, hid_state_t *);
1090Sstevel@tonic-gate static int hid_is_pm_enabled(dev_info_t *);
1100Sstevel@tonic-gate static void hid_restore_device_state(dev_info_t *, hid_state_t *);
1110Sstevel@tonic-gate static void hid_save_device_state(hid_state_t *);
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate static void hid_qreply_merror(queue_t *, mblk_t *, uchar_t);
1140Sstevel@tonic-gate static mblk_t *hid_data2mblk(uchar_t *, int);
1150Sstevel@tonic-gate static void hid_flush(queue_t *);
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate static int hid_pwrlvl0(hid_state_t *);
1180Sstevel@tonic-gate static int hid_pwrlvl1(hid_state_t *);
1190Sstevel@tonic-gate static int hid_pwrlvl2(hid_state_t *);
1200Sstevel@tonic-gate static int hid_pwrlvl3(hid_state_t *);
1210Sstevel@tonic-gate static void hid_pm_busy_component(hid_state_t *);
1220Sstevel@tonic-gate static void hid_pm_idle_component(hid_state_t *);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate static int hid_polled_read(hid_polled_handle_t, uchar_t **);
1250Sstevel@tonic-gate static int hid_polled_input_enter(hid_polled_handle_t);
1260Sstevel@tonic-gate static int hid_polled_input_exit(hid_polled_handle_t);
1270Sstevel@tonic-gate static int hid_polled_input_init(hid_state_t *);
1280Sstevel@tonic-gate static int hid_polled_input_fini(hid_state_t *);
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate /* Streams entry points */
1310Sstevel@tonic-gate static int hid_open(queue_t *, dev_t *, int, int, cred_t *);
1320Sstevel@tonic-gate static int hid_close(queue_t *, int, cred_t *);
1330Sstevel@tonic-gate static int hid_wput(queue_t *, mblk_t *);
1340Sstevel@tonic-gate static int hid_wsrv(queue_t *);
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate /* dev_ops entry points */
1370Sstevel@tonic-gate static int hid_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1380Sstevel@tonic-gate static int hid_attach(dev_info_t *, ddi_attach_cmd_t);
1390Sstevel@tonic-gate static int hid_detach(dev_info_t *, ddi_detach_cmd_t);
1400Sstevel@tonic-gate static int hid_power(dev_info_t *, int, int);
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate /*
1430Sstevel@tonic-gate * Warlock is not aware of the automatic locking mechanisms for
1440Sstevel@tonic-gate * streams drivers. The hid streams enter points are protected by
1450Sstevel@tonic-gate * a per module perimeter. If the locking in hid is a bottleneck
1460Sstevel@tonic-gate * per queue pair or per queue locking may be used. Since warlock
1470Sstevel@tonic-gate * is not aware of the streams perimeters, these notes have been added.
1480Sstevel@tonic-gate *
1490Sstevel@tonic-gate * Note that the perimeters do not protect the driver from callbacks
1500Sstevel@tonic-gate * happening while a streams entry point is executing. So, the hid_mutex
1510Sstevel@tonic-gate * has been created to protect the data.
1520Sstevel@tonic-gate */
1530Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
1540Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
1550Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", msgb))
1560Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", queue))
1570Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
1580Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_intr_req))
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate /* module information */
1610Sstevel@tonic-gate static struct module_info hid_mod_info = {
1620Sstevel@tonic-gate 0x0ffff, /* module id number */
1630Sstevel@tonic-gate "hid", /* module name */
1640Sstevel@tonic-gate 0, /* min packet size accepted */
1650Sstevel@tonic-gate INFPSZ, /* max packet size accepted */
1660Sstevel@tonic-gate 512, /* hi-water mark */
1670Sstevel@tonic-gate 128 /* lo-water mark */
1680Sstevel@tonic-gate };
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /* read queue information structure */
1710Sstevel@tonic-gate static struct qinit rinit = {
1720Sstevel@tonic-gate NULL, /* put procedure not needed */
1730Sstevel@tonic-gate NULL, /* service procedure not needed */
1740Sstevel@tonic-gate hid_open, /* called on startup */
1750Sstevel@tonic-gate hid_close, /* called on finish */
1760Sstevel@tonic-gate NULL, /* for future use */
1770Sstevel@tonic-gate &hid_mod_info, /* module information structure */
1780Sstevel@tonic-gate NULL /* module statistics structure */
1790Sstevel@tonic-gate };
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate /* write queue information structure */
1820Sstevel@tonic-gate static struct qinit winit = {
1830Sstevel@tonic-gate hid_wput, /* put procedure */
1840Sstevel@tonic-gate hid_wsrv, /* service procedure */
1850Sstevel@tonic-gate NULL, /* open not used on write side */
1860Sstevel@tonic-gate NULL, /* close not used on write side */
1870Sstevel@tonic-gate NULL, /* for future use */
1880Sstevel@tonic-gate &hid_mod_info, /* module information structure */
1890Sstevel@tonic-gate NULL /* module statistics structure */
1900Sstevel@tonic-gate };
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate struct streamtab hid_streamtab = {
1930Sstevel@tonic-gate &rinit,
1940Sstevel@tonic-gate &winit,
1950Sstevel@tonic-gate NULL, /* not a MUX */
1960Sstevel@tonic-gate NULL /* not a MUX */
1970Sstevel@tonic-gate };
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate struct cb_ops hid_cb_ops = {
2000Sstevel@tonic-gate nulldev, /* open */
2010Sstevel@tonic-gate nulldev, /* close */
2020Sstevel@tonic-gate nulldev, /* strategy */
2030Sstevel@tonic-gate nulldev, /* print */
2040Sstevel@tonic-gate nulldev, /* dump */
2050Sstevel@tonic-gate nulldev, /* read */
2060Sstevel@tonic-gate nulldev, /* write */
2070Sstevel@tonic-gate nulldev, /* ioctl */
2080Sstevel@tonic-gate nulldev, /* devmap */
2090Sstevel@tonic-gate nulldev, /* mmap */
2100Sstevel@tonic-gate nulldev, /* segmap */
2110Sstevel@tonic-gate nochpoll, /* poll */
2120Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
2130Sstevel@tonic-gate &hid_streamtab, /* streamtab */
2140Sstevel@tonic-gate D_MP | D_MTPERQ
2150Sstevel@tonic-gate };
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate static struct dev_ops hid_ops = {
2190Sstevel@tonic-gate DEVO_REV, /* devo_rev, */
2200Sstevel@tonic-gate 0, /* refcnt */
2210Sstevel@tonic-gate hid_info, /* info */
2220Sstevel@tonic-gate nulldev, /* identify */
2230Sstevel@tonic-gate nulldev, /* probe */
2240Sstevel@tonic-gate hid_attach, /* attach */
2250Sstevel@tonic-gate hid_detach, /* detach */
2260Sstevel@tonic-gate nodev, /* reset */
2270Sstevel@tonic-gate &hid_cb_ops, /* driver operations */
2280Sstevel@tonic-gate NULL, /* bus operations */
2297656SSherry.Moore@Sun.COM hid_power, /* power */
2307656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
2310Sstevel@tonic-gate };
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate static struct modldrv hidmodldrv = {
2340Sstevel@tonic-gate &mod_driverops,
2357425SGongtian.Zhao@Sun.COM "USB HID Client Driver",
2360Sstevel@tonic-gate &hid_ops /* driver ops */
2370Sstevel@tonic-gate };
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate static struct modlinkage modlinkage = {
2400Sstevel@tonic-gate MODREV_1,
2410Sstevel@tonic-gate &hidmodldrv,
2420Sstevel@tonic-gate NULL,
2430Sstevel@tonic-gate };
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate static usb_event_t hid_events = {
2460Sstevel@tonic-gate hid_disconnect_event_callback,
2470Sstevel@tonic-gate hid_restore_state_event_callback,
2480Sstevel@tonic-gate NULL,
2490Sstevel@tonic-gate NULL,
2500Sstevel@tonic-gate };
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate int
_init(void)2540Sstevel@tonic-gate _init(void)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate int rval;
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate if (((rval = ddi_soft_state_init(&hid_statep, sizeof (hid_state_t),
2590Sstevel@tonic-gate HID_INITIAL_SOFT_SPACE)) != 0)) {
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate return (rval);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) {
2650Sstevel@tonic-gate ddi_soft_state_fini(&hid_statep);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate return (rval);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate int
_fini(void)2730Sstevel@tonic-gate _fini(void)
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate int rval;
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate if ((rval = mod_remove(&modlinkage)) != 0) {
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate return (rval);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate ddi_soft_state_fini(&hid_statep);
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate return (rval);
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2890Sstevel@tonic-gate _info(struct modinfo *modinfop)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate /*
2960Sstevel@tonic-gate * hid_info :
2970Sstevel@tonic-gate * Get minor number, soft state structure etc.
2980Sstevel@tonic-gate */
2990Sstevel@tonic-gate /*ARGSUSED*/
3000Sstevel@tonic-gate static int
hid_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)3010Sstevel@tonic-gate hid_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
3020Sstevel@tonic-gate void *arg, void **result)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate hid_state_t *hidp = NULL;
3050Sstevel@tonic-gate int error = DDI_FAILURE;
3060Sstevel@tonic-gate minor_t minor = getminor((dev_t)arg);
3070Sstevel@tonic-gate int instance = HID_MINOR_TO_INSTANCE(minor);
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate switch (infocmd) {
3100Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
3110Sstevel@tonic-gate if ((hidp = ddi_get_soft_state(hid_statep, instance)) != NULL) {
3120Sstevel@tonic-gate *result = hidp->hid_dip;
3130Sstevel@tonic-gate if (*result != NULL) {
3140Sstevel@tonic-gate error = DDI_SUCCESS;
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate } else
3170Sstevel@tonic-gate *result = NULL;
3180Sstevel@tonic-gate break;
3190Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
3200Sstevel@tonic-gate *result = (void *)(uintptr_t)instance;
3210Sstevel@tonic-gate error = DDI_SUCCESS;
3220Sstevel@tonic-gate break;
3230Sstevel@tonic-gate default:
3240Sstevel@tonic-gate break;
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate return (error);
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate /*
3320Sstevel@tonic-gate * hid_attach :
3330Sstevel@tonic-gate * Gets called at the time of attach. Do allocation,
3340Sstevel@tonic-gate * and initialization of the software structure.
3350Sstevel@tonic-gate * Get all the descriptors, setup the
3360Sstevel@tonic-gate * report descriptor tree by calling hidparser
3370Sstevel@tonic-gate * function.
3380Sstevel@tonic-gate */
3390Sstevel@tonic-gate static int
hid_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3400Sstevel@tonic-gate hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate int instance = ddi_get_instance(dip);
3440Sstevel@tonic-gate int parse_hid_descr_error = 0;
3450Sstevel@tonic-gate hid_state_t *hidp = NULL;
3460Sstevel@tonic-gate uint32_t usage_page;
3470Sstevel@tonic-gate uint32_t usage;
3480Sstevel@tonic-gate usb_client_dev_data_t *dev_data;
3490Sstevel@tonic-gate usb_alt_if_data_t *altif_data;
3500Sstevel@tonic-gate char minor_name[HID_MINOR_NAME_LEN];
3510Sstevel@tonic-gate usb_ep_data_t *ep_data;
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate switch (cmd) {
3540Sstevel@tonic-gate case DDI_ATTACH:
3550Sstevel@tonic-gate break;
3560Sstevel@tonic-gate case DDI_RESUME:
3570Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
3580Sstevel@tonic-gate hid_cpr_resume(hidp);
3590Sstevel@tonic-gate return (DDI_SUCCESS);
3600Sstevel@tonic-gate default:
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate return (DDI_FAILURE);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate * Allocate softstate information and get softstate pointer
3670Sstevel@tonic-gate */
3680Sstevel@tonic-gate if (ddi_soft_state_zalloc(hid_statep, instance) == DDI_SUCCESS) {
3690Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate if (hidp == NULL) {
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate goto fail;
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate hidp->hid_log_handle = usb_alloc_log_hdl(dip, NULL, &hid_errlevel,
3776898Sfb209375 &hid_errmask, &hid_instance_debug, 0);
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate hidp->hid_instance = instance;
3800Sstevel@tonic-gate hidp->hid_dip = dip;
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate /*
3830Sstevel@tonic-gate * Register with USBA. Just retrieve interface descriptor
3840Sstevel@tonic-gate */
3850Sstevel@tonic-gate if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
3860Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
3870Sstevel@tonic-gate "hid_attach: client attach failed");
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate goto fail;
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) !=
3930Sstevel@tonic-gate USB_SUCCESS) {
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
3960Sstevel@tonic-gate "hid_attach: usb_get_dev_data() failed");
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate goto fail;
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate /* initialize mutex */
4020Sstevel@tonic-gate mutex_init(&hidp->hid_mutex, NULL, MUTEX_DRIVER,
4036898Sfb209375 dev_data->dev_iblock_cookie);
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate hidp->hid_attach_flags |= HID_LOCK_INIT;
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate /* get interface data for alternate 0 */
4080Sstevel@tonic-gate altif_data = &dev_data->dev_curr_cfg->
4096898Sfb209375 cfg_if[dev_data->dev_curr_if].if_alt[0];
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
4120Sstevel@tonic-gate hidp->hid_dev_data = dev_data;
4130Sstevel@tonic-gate hidp->hid_dev_descr = dev_data->dev_descr;
4140Sstevel@tonic-gate hidp->hid_interfaceno = dev_data->dev_curr_if;
4150Sstevel@tonic-gate hidp->hid_if_descr = altif_data->altif_descr;
4161418Sqz150045 /*
4171418Sqz150045 * Make sure that the bInterfaceProtocol only has meaning to
4181418Sqz150045 * Boot Interface Subclass.
4191418Sqz150045 */
4201418Sqz150045 if (hidp->hid_if_descr.bInterfaceSubClass != BOOT_INTERFACE)
4211418Sqz150045 hidp->hid_if_descr.bInterfaceProtocol = NONE_PROTOCOL;
4220Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate if ((ep_data = usb_lookup_ep_data(dip, dev_data,
4250Sstevel@tonic-gate hidp->hid_interfaceno, 0, 0,
4260Sstevel@tonic-gate (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) {
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
4290Sstevel@tonic-gate "no interrupt IN endpoint found");
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate goto fail;
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
4350Sstevel@tonic-gate hidp->hid_ep_intr_descr = ep_data->ep_descr;
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate * Attempt to find the hid descriptor, it could be after interface
4390Sstevel@tonic-gate * or after endpoint descriptors
4400Sstevel@tonic-gate */
4410Sstevel@tonic-gate if (hid_parse_hid_descr(&hidp->hid_hid_descr, USB_HID_DESCR_SIZE,
4420Sstevel@tonic-gate altif_data, ep_data) != USB_HID_DESCR_SIZE) {
4430Sstevel@tonic-gate /*
4440Sstevel@tonic-gate * If parsing of hid descriptor failed and
4450Sstevel@tonic-gate * the device is a keyboard or mouse, use predefined
4460Sstevel@tonic-gate * length and packet size.
4470Sstevel@tonic-gate */
4480Sstevel@tonic-gate if (hid_parse_hid_descr_failure(hidp) == USB_FAILURE) {
4490Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate goto fail;
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate * hid descriptor was bad but since
4560Sstevel@tonic-gate * the device is a keyboard or mouse,
4570Sstevel@tonic-gate * we will use the default length
4580Sstevel@tonic-gate * and packet size.
4590Sstevel@tonic-gate */
4600Sstevel@tonic-gate parse_hid_descr_error = HID_BAD_DESCR;
4610Sstevel@tonic-gate } else {
4620Sstevel@tonic-gate /* Parse hid descriptor successful */
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
4650Sstevel@tonic-gate "Hid descriptor:\n\t"
4660Sstevel@tonic-gate "bLength = 0x%x bDescriptorType = 0x%x "
4670Sstevel@tonic-gate "bcdHID = 0x%x\n\t"
4680Sstevel@tonic-gate "bCountryCode = 0x%x bNumDescriptors = 0x%x\n\t"
4690Sstevel@tonic-gate "bReportDescriptorType = 0x%x\n\t"
4700Sstevel@tonic-gate "wReportDescriptorLength = 0x%x",
4710Sstevel@tonic-gate hidp->hid_hid_descr.bLength,
4720Sstevel@tonic-gate hidp->hid_hid_descr.bDescriptorType,
4730Sstevel@tonic-gate hidp->hid_hid_descr.bcdHID,
4740Sstevel@tonic-gate hidp->hid_hid_descr.bCountryCode,
4750Sstevel@tonic-gate hidp->hid_hid_descr.bNumDescriptors,
4760Sstevel@tonic-gate hidp->hid_hid_descr.bReportDescriptorType,
4770Sstevel@tonic-gate hidp->hid_hid_descr.wReportDescriptorLength);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate /*
4810Sstevel@tonic-gate * Save a copy of the default pipe for easy reference
4820Sstevel@tonic-gate */
4830Sstevel@tonic-gate hidp->hid_default_pipe = hidp->hid_dev_data->dev_default_ph;
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate /* we copied the descriptors we need, free the dev_data */
4860Sstevel@tonic-gate usb_free_dev_data(dip, dev_data);
4870Sstevel@tonic-gate hidp->hid_dev_data = NULL;
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate /*
4900Sstevel@tonic-gate * Don't get the report descriptor if parsing hid descriptor earlier
4910Sstevel@tonic-gate * failed since device probably won't return valid report descriptor
4920Sstevel@tonic-gate * either. Though parsing of hid descriptor failed, we have reached
4930Sstevel@tonic-gate * this point because the device has been identified as a
4940Sstevel@tonic-gate * keyboard or a mouse successfully and the default packet
4950Sstevel@tonic-gate * size and layout(in case of keyboard only) will be used, so it
4960Sstevel@tonic-gate * is ok to go ahead even if parsing of hid descriptor failed and
4970Sstevel@tonic-gate * we will not try to get the report descriptor.
4980Sstevel@tonic-gate */
4990Sstevel@tonic-gate if (parse_hid_descr_error != HID_BAD_DESCR) {
5000Sstevel@tonic-gate /*
5010Sstevel@tonic-gate * Sun mouse rev 105 is a bit slow in responding to this
5020Sstevel@tonic-gate * request and requires multiple retries
5030Sstevel@tonic-gate */
5040Sstevel@tonic-gate int retry;
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate /*
5070Sstevel@tonic-gate * Get and parse the report descriptor.
5080Sstevel@tonic-gate * Set the packet size if parsing is successful.
5090Sstevel@tonic-gate * Note that we start retry at 1 to have a delay
5100Sstevel@tonic-gate * in the first iteration.
5110Sstevel@tonic-gate */
5120Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
5130Sstevel@tonic-gate for (retry = 1; retry < HID_RETRY; retry++) {
5140Sstevel@tonic-gate if (hid_handle_report_descriptor(hidp,
5150Sstevel@tonic-gate hidp->hid_interfaceno) == USB_SUCCESS) {
5160Sstevel@tonic-gate break;
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate delay(retry * drv_usectohz(1000));
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate if (retry >= HID_RETRY) {
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate goto fail;
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate /*
5270Sstevel@tonic-gate * If packet size is zero, but the device is identified
5280Sstevel@tonic-gate * as a mouse or a keyboard, use predefined packet
5290Sstevel@tonic-gate * size.
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate if (hidp->hid_packet_size == 0) {
5320Sstevel@tonic-gate if (hidp->hid_if_descr.bInterfaceProtocol ==
5330Sstevel@tonic-gate KEYBOARD_PROTOCOL) {
5340Sstevel@tonic-gate /* device is a keyboard */
5350Sstevel@tonic-gate hidp->hid_packet_size = USBKPSZ;
5360Sstevel@tonic-gate } else if (hidp->
5370Sstevel@tonic-gate hid_if_descr.bInterfaceProtocol ==
5380Sstevel@tonic-gate MOUSE_PROTOCOL) {
5390Sstevel@tonic-gate /* device is a mouse */
5400Sstevel@tonic-gate hidp->hid_packet_size = USBMSSZ;
5410Sstevel@tonic-gate } else {
5420Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
5430Sstevel@tonic-gate hidp->hid_log_handle,
5440Sstevel@tonic-gate "Failed to find hid packet size");
5450Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate goto fail;
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate /*
5530Sstevel@tonic-gate * initialize the pipe policy for the interrupt pipe.
5540Sstevel@tonic-gate */
5550Sstevel@tonic-gate hidp->hid_intr_pipe_policy.pp_max_async_reqs = 1;
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate /*
5580Sstevel@tonic-gate * Make a clas specific request to SET_IDLE
5590Sstevel@tonic-gate * In this case send no reports if state has not changed.
5600Sstevel@tonic-gate * See HID 7.2.4.
5610Sstevel@tonic-gate */
5620Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
5630Sstevel@tonic-gate hid_set_idle(hidp);
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate /* always initialize to report protocol */
5660Sstevel@tonic-gate hid_set_protocol(hidp, SET_REPORT_PROTOCOL);
5670Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
5680Sstevel@tonic-gate
5690Sstevel@tonic-gate /*
5700Sstevel@tonic-gate * Create minor node based on information from the
5710Sstevel@tonic-gate * descriptors
5720Sstevel@tonic-gate */
5730Sstevel@tonic-gate switch (hidp->hid_if_descr.bInterfaceProtocol) {
5740Sstevel@tonic-gate case KEYBOARD_PROTOCOL:
5750Sstevel@tonic-gate (void) strcpy(minor_name, "keyboard");
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate break;
5780Sstevel@tonic-gate case MOUSE_PROTOCOL:
5790Sstevel@tonic-gate (void) strcpy(minor_name, "mouse");
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate break;
5820Sstevel@tonic-gate default:
5839237SStrony.Zhang@Sun.COM /*
5849237SStrony.Zhang@Sun.COM * If the report descriptor has the GD mouse collection in
5859237SStrony.Zhang@Sun.COM * its multiple collection, create a minor node and support it.
5869237SStrony.Zhang@Sun.COM * It is used on some advanced keyboard/mouse set.
5879237SStrony.Zhang@Sun.COM */
5889237SStrony.Zhang@Sun.COM if (hidparser_lookup_usage_collection(
5899237SStrony.Zhang@Sun.COM hidp->hid_report_descr, HID_GENERIC_DESKTOP,
5909237SStrony.Zhang@Sun.COM HID_GD_MOUSE) != HIDPARSER_FAILURE) {
5919237SStrony.Zhang@Sun.COM (void) strcpy(minor_name, "mouse");
5929237SStrony.Zhang@Sun.COM
5939237SStrony.Zhang@Sun.COM break;
5949237SStrony.Zhang@Sun.COM }
5959237SStrony.Zhang@Sun.COM
5960Sstevel@tonic-gate if (hidparser_get_top_level_collection_usage(
5970Sstevel@tonic-gate hidp->hid_report_descr, &usage_page, &usage) !=
5980Sstevel@tonic-gate HIDPARSER_FAILURE) {
5990Sstevel@tonic-gate switch (usage_page) {
6000Sstevel@tonic-gate case HID_CONSUMER:
6010Sstevel@tonic-gate switch (usage) {
6020Sstevel@tonic-gate case HID_CONSUMER_CONTROL:
6030Sstevel@tonic-gate (void) strcpy(minor_name,
6040Sstevel@tonic-gate "consumer_control");
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate break;
6070Sstevel@tonic-gate default:
6080Sstevel@tonic-gate (void) sprintf(minor_name,
6090Sstevel@tonic-gate "hid_%d_%d", usage_page, usage);
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate break;
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate break;
6150Sstevel@tonic-gate case HID_GENERIC_DESKTOP:
6160Sstevel@tonic-gate switch (usage) {
6170Sstevel@tonic-gate case HID_GD_POINTER:
6180Sstevel@tonic-gate (void) strcpy(minor_name,
6190Sstevel@tonic-gate "pointer");
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate break;
6220Sstevel@tonic-gate case HID_GD_MOUSE:
6230Sstevel@tonic-gate (void) strcpy(minor_name,
6240Sstevel@tonic-gate "mouse");
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate break;
6270Sstevel@tonic-gate case HID_GD_KEYBOARD:
6280Sstevel@tonic-gate (void) strcpy(minor_name,
6290Sstevel@tonic-gate "keyboard");
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate break;
6320Sstevel@tonic-gate default:
6330Sstevel@tonic-gate (void) sprintf(minor_name,
6340Sstevel@tonic-gate "hid_%d_%d", usage_page, usage);
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate break;
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate
6390Sstevel@tonic-gate break;
6400Sstevel@tonic-gate default:
6410Sstevel@tonic-gate (void) sprintf(minor_name,
6420Sstevel@tonic-gate "hid_%d_%d", usage_page, usage);
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate break;
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate } else {
6470Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
6480Sstevel@tonic-gate "hid_attach: Unsupported HID device");
6490Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate goto fail;
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate break;
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate if ((ddi_create_minor_node(dip, minor_name, S_IFCHR,
6600Sstevel@tonic-gate HID_CONSTRUCT_EXTERNAL_MINOR(instance),
6610Sstevel@tonic-gate DDI_PSEUDO, 0)) != DDI_SUCCESS) {
662978Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
6630Sstevel@tonic-gate "hid_attach: Could not create minor node");
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate goto fail;
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate /* create internal path for virtual */
6690Sstevel@tonic-gate if (strcmp(minor_name, "mouse") == 0) {
6700Sstevel@tonic-gate if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR,
6710Sstevel@tonic-gate HID_CONSTRUCT_INTERNAL_MINOR(instance)) != DDI_SUCCESS) {
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate goto fail;
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate if (strcmp(minor_name, "keyboard") == 0) {
6780Sstevel@tonic-gate if (ddi_create_internal_pathname(dip, "internal_keyboard",
6790Sstevel@tonic-gate S_IFCHR, HID_CONSTRUCT_INTERNAL_MINOR(instance)) !=
6800Sstevel@tonic-gate DDI_SUCCESS) {
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate goto fail;
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
6870Sstevel@tonic-gate hidp->hid_attach_flags |= HID_MINOR_NODES;
6880Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_ONLINE;
6890Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate /* register for all events */
6920Sstevel@tonic-gate if (usb_register_event_cbs(dip, &hid_events, 0) != USB_SUCCESS) {
693978Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
6940Sstevel@tonic-gate "usb_register_event_cbs failed");
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate goto fail;
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate /* now create components to power manage this device */
7000Sstevel@tonic-gate hid_create_pm_components(dip, hidp);
7010Sstevel@tonic-gate hid_pm_busy_component(hidp);
7020Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
7030Sstevel@tonic-gate hid_pm_idle_component(hidp);
7040Sstevel@tonic-gate
70510153SAaron.Zang@Sun.COM hidp->hid_internal_rq = hidp->hid_external_rq = NULL;
70610153SAaron.Zang@Sun.COM hidp->hid_internal_flag = hidp->hid_external_flag = 0;
70710153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = NULL;
70810153SAaron.Zang@Sun.COM
7090Sstevel@tonic-gate /*
7100Sstevel@tonic-gate * report device
7110Sstevel@tonic-gate */
7120Sstevel@tonic-gate ddi_report_dev(dip);
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
7150Sstevel@tonic-gate "hid_attach: End");
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate return (DDI_SUCCESS);
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate fail:
7200Sstevel@tonic-gate if (hidp) {
7210Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
7220Sstevel@tonic-gate "hid_attach: fail");
7230Sstevel@tonic-gate hid_detach_cleanup(dip, hidp);
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate return (DDI_FAILURE);
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate
7300Sstevel@tonic-gate /*
7310Sstevel@tonic-gate * hid_detach :
7320Sstevel@tonic-gate * Gets called at the time of detach.
7330Sstevel@tonic-gate */
7340Sstevel@tonic-gate static int
hid_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)7350Sstevel@tonic-gate hid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7360Sstevel@tonic-gate {
7370Sstevel@tonic-gate int instance = ddi_get_instance(dip);
7380Sstevel@tonic-gate hid_state_t *hidp;
7390Sstevel@tonic-gate int rval = DDI_FAILURE;
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle, "hid_detach");
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate switch (cmd) {
7460Sstevel@tonic-gate case DDI_DETACH:
7470Sstevel@tonic-gate /*
7480Sstevel@tonic-gate * Undo what we did in client_attach, freeing resources
7490Sstevel@tonic-gate * and removing things we installed. The system
7500Sstevel@tonic-gate * framework guarantees we are not active with this devinfo
7510Sstevel@tonic-gate * node in any other entry points at this time.
7520Sstevel@tonic-gate */
7530Sstevel@tonic-gate hid_detach_cleanup(dip, hidp);
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate return (DDI_SUCCESS);
7560Sstevel@tonic-gate case DDI_SUSPEND:
7570Sstevel@tonic-gate rval = hid_cpr_suspend(hidp);
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate return (rval == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
7600Sstevel@tonic-gate default:
7610Sstevel@tonic-gate break;
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate
7640Sstevel@tonic-gate return (rval);
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate /*
7680Sstevel@tonic-gate * hid_open :
7690Sstevel@tonic-gate * Open entry point: Opens the interrupt pipe. Sets up queues.
7700Sstevel@tonic-gate */
7710Sstevel@tonic-gate /*ARGSUSED*/
7720Sstevel@tonic-gate static int
hid_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)7730Sstevel@tonic-gate hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate int no_of_ep = 0;
7760Sstevel@tonic-gate int rval;
7770Sstevel@tonic-gate int instance;
7780Sstevel@tonic-gate hid_state_t *hidp;
7790Sstevel@tonic-gate minor_t minor = getminor(*devp);
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate instance = HID_MINOR_TO_INSTANCE(minor);
7820Sstevel@tonic-gate
7830Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
7840Sstevel@tonic-gate if (hidp == NULL) {
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate return (ENXIO);
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate
7890Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle,
7900Sstevel@tonic-gate "hid_open: Begin");
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate if (sflag) {
7930Sstevel@tonic-gate /* clone open NOT supported here */
7940Sstevel@tonic-gate return (ENXIO);
7950Sstevel@tonic-gate }
7960Sstevel@tonic-gate
7979432SPengcheng.Chen@Sun.COM if (!(flag & FREAD)) {
7989432SPengcheng.Chen@Sun.COM return (EIO);
7999432SPengcheng.Chen@Sun.COM }
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate /*
8020Sstevel@tonic-gate * This is a workaround:
8030Sstevel@tonic-gate * Currently, if we open an already disconnected device, and send
8040Sstevel@tonic-gate * a CONSOPENPOLL ioctl to it, the system will panic, please refer
8050Sstevel@tonic-gate * to the processing HID_OPEN_POLLED_INPUT ioctl in the routine
8060Sstevel@tonic-gate * hid_mctl_receive().
8070Sstevel@tonic-gate * The consconfig_dacf module need this interface to detect if the
8080Sstevel@tonic-gate * device is already disconnnected.
8090Sstevel@tonic-gate */
8109432SPengcheng.Chen@Sun.COM mutex_enter(&hidp->hid_mutex);
8119666SPengcheng.Chen@Sun.COM if (HID_IS_INTERNAL_OPEN(minor) &&
8129666SPengcheng.Chen@Sun.COM (hidp->hid_dev_state == USB_DEV_DISCONNECTED)) {
8130Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
8140Sstevel@tonic-gate return (ENODEV);
8150Sstevel@tonic-gate }
8160Sstevel@tonic-gate
81710153SAaron.Zang@Sun.COM if (HID_IS_INTERNAL_OPEN(minor) &&
81810153SAaron.Zang@Sun.COM (hidp->hid_internal_rq != NULL)) {
81910153SAaron.Zang@Sun.COM ASSERT(hidp->hid_internal_rq == q);
82010153SAaron.Zang@Sun.COM
82110153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
82210153SAaron.Zang@Sun.COM return (0);
8239432SPengcheng.Chen@Sun.COM }
82410153SAaron.Zang@Sun.COM
82510153SAaron.Zang@Sun.COM if ((!HID_IS_INTERNAL_OPEN(minor)) &&
82610153SAaron.Zang@Sun.COM (hidp->hid_external_rq != NULL)) {
82710153SAaron.Zang@Sun.COM ASSERT(hidp->hid_external_rq == q);
82810153SAaron.Zang@Sun.COM
82910153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
83010153SAaron.Zang@Sun.COM return (0);
83110153SAaron.Zang@Sun.COM }
83210153SAaron.Zang@Sun.COM
8339432SPengcheng.Chen@Sun.COM mutex_exit(&hidp->hid_mutex);
8349432SPengcheng.Chen@Sun.COM
83510153SAaron.Zang@Sun.COM q->q_ptr = hidp;
83610153SAaron.Zang@Sun.COM WR(q)->q_ptr = hidp;
8379432SPengcheng.Chen@Sun.COM
8389432SPengcheng.Chen@Sun.COM mutex_enter(&hidp->hid_mutex);
83910153SAaron.Zang@Sun.COM if (hidp->hid_inuse_rq != NULL) {
84010153SAaron.Zang@Sun.COM /* Pipe has already been setup */
84110153SAaron.Zang@Sun.COM
84210153SAaron.Zang@Sun.COM if (HID_IS_INTERNAL_OPEN(minor)) {
84310153SAaron.Zang@Sun.COM hidp->hid_internal_flag = HID_STREAMS_OPEN;
84410153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = hidp->hid_internal_rq = q;
84510153SAaron.Zang@Sun.COM } else {
84610153SAaron.Zang@Sun.COM hidp->hid_external_flag = HID_STREAMS_OPEN;
84710153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = hidp->hid_external_rq = q;
84810153SAaron.Zang@Sun.COM }
84910153SAaron.Zang@Sun.COM
8500Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
85110153SAaron.Zang@Sun.COM
8529432SPengcheng.Chen@Sun.COM qprocson(q);
85310153SAaron.Zang@Sun.COM
8549432SPengcheng.Chen@Sun.COM return (0);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate
85710153SAaron.Zang@Sun.COM /* Pipe only needs to be opened once */
8589432SPengcheng.Chen@Sun.COM hidp->hid_interrupt_pipe = NULL;
8599432SPengcheng.Chen@Sun.COM no_of_ep = hidp->hid_if_descr.bNumEndpoints;
8609432SPengcheng.Chen@Sun.COM mutex_exit(&hidp->hid_mutex);
8619432SPengcheng.Chen@Sun.COM
8629432SPengcheng.Chen@Sun.COM /* Check if interrupt endpoint exists */
8639432SPengcheng.Chen@Sun.COM if (no_of_ep > 0) {
8649432SPengcheng.Chen@Sun.COM /* Open the interrupt pipe */
8659432SPengcheng.Chen@Sun.COM if (usb_pipe_open(hidp->hid_dip,
8669432SPengcheng.Chen@Sun.COM &hidp->hid_ep_intr_descr,
8679432SPengcheng.Chen@Sun.COM &hidp->hid_intr_pipe_policy, USB_FLAGS_SLEEP,
8689432SPengcheng.Chen@Sun.COM &hidp->hid_interrupt_pipe) !=
8699432SPengcheng.Chen@Sun.COM USB_SUCCESS) {
8709432SPengcheng.Chen@Sun.COM
8719432SPengcheng.Chen@Sun.COM q->q_ptr = NULL;
8729432SPengcheng.Chen@Sun.COM WR(q)->q_ptr = NULL;
8739432SPengcheng.Chen@Sun.COM return (EIO);
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate hid_pm_busy_component(hidp);
8780Sstevel@tonic-gate (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
88110153SAaron.Zang@Sun.COM if (HID_IS_INTERNAL_OPEN(minor)) {
88210153SAaron.Zang@Sun.COM hidp->hid_internal_flag = HID_STREAMS_OPEN;
88310153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = hidp->hid_internal_rq = q;
88410153SAaron.Zang@Sun.COM } else {
88510153SAaron.Zang@Sun.COM hidp->hid_external_flag = HID_STREAMS_OPEN;
88610153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = hidp->hid_external_rq = q;
88710153SAaron.Zang@Sun.COM }
88810153SAaron.Zang@Sun.COM
8890Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate qprocson(q);
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate if ((rval = hid_start_intr_polling(hidp)) != USB_SUCCESS) {
8960Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_OPEN, hidp->hid_log_handle,
8970Sstevel@tonic-gate "unable to start intr pipe polling. rval = %d", rval);
8980Sstevel@tonic-gate
89910153SAaron.Zang@Sun.COM if (HID_IS_INTERNAL_OPEN(minor))
90010153SAaron.Zang@Sun.COM hidp->hid_internal_flag = HID_STREAMS_DISMANTLING;
90110153SAaron.Zang@Sun.COM else
90210153SAaron.Zang@Sun.COM hidp->hid_external_flag = HID_STREAMS_DISMANTLING;
9030Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate usb_pipe_close(hidp->hid_dip, hidp->hid_interrupt_pipe,
9060Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL);
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
9090Sstevel@tonic-gate hidp->hid_interrupt_pipe = NULL;
9100Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate qprocsoff(q);
91310153SAaron.Zang@Sun.COM
91410153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
91510153SAaron.Zang@Sun.COM if (HID_IS_INTERNAL_OPEN(minor)) {
91610153SAaron.Zang@Sun.COM hidp->hid_internal_flag = 0;
91710153SAaron.Zang@Sun.COM hidp->hid_internal_rq = NULL;
91810153SAaron.Zang@Sun.COM if (hidp->hid_external_flag == HID_STREAMS_OPEN)
91910153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = hidp->hid_external_rq;
92010153SAaron.Zang@Sun.COM else
92110153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = NULL;
92210153SAaron.Zang@Sun.COM } else {
92310153SAaron.Zang@Sun.COM hidp->hid_external_flag = 0;
92410153SAaron.Zang@Sun.COM hidp->hid_external_rq = NULL;
92510153SAaron.Zang@Sun.COM if (hidp->hid_internal_flag == HID_STREAMS_OPEN)
92610153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = hidp->hid_internal_rq;
92710153SAaron.Zang@Sun.COM else
92810153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = NULL;
92910153SAaron.Zang@Sun.COM }
93010153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
93110153SAaron.Zang@Sun.COM
9329432SPengcheng.Chen@Sun.COM q->q_ptr = NULL;
9339432SPengcheng.Chen@Sun.COM WR(q)->q_ptr = NULL;
9349432SPengcheng.Chen@Sun.COM
9350Sstevel@tonic-gate hid_pm_idle_component(hidp);
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate return (EIO);
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle, "hid_open: End");
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate /*
9440Sstevel@tonic-gate * Keyboard and mouse is Power managed by device activity.
9450Sstevel@tonic-gate * All other devices go busy on open and idle on close.
9460Sstevel@tonic-gate */
9470Sstevel@tonic-gate switch (hidp->hid_pm->hid_pm_strategy) {
9480Sstevel@tonic-gate case HID_PM_ACTIVITY:
9490Sstevel@tonic-gate hid_pm_idle_component(hidp);
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate break;
9520Sstevel@tonic-gate default:
9530Sstevel@tonic-gate
9540Sstevel@tonic-gate break;
9550Sstevel@tonic-gate }
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate return (0);
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate /*
9620Sstevel@tonic-gate * hid_close :
9630Sstevel@tonic-gate * Close entry point.
9640Sstevel@tonic-gate */
9650Sstevel@tonic-gate /*ARGSUSED*/
9660Sstevel@tonic-gate static int
hid_close(queue_t * q,int flag,cred_t * credp)9670Sstevel@tonic-gate hid_close(queue_t *q, int flag, cred_t *credp)
9680Sstevel@tonic-gate {
96910153SAaron.Zang@Sun.COM hid_state_t *hidp = (hid_state_t *)q->q_ptr;
9700Sstevel@tonic-gate queue_t *wq;
9710Sstevel@tonic-gate mblk_t *mp;
9720Sstevel@tonic-gate
9730Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle, "hid_close:");
9740Sstevel@tonic-gate
9750Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
97610153SAaron.Zang@Sun.COM
97710153SAaron.Zang@Sun.COM ASSERT((hidp->hid_internal_rq == q) ||
97810153SAaron.Zang@Sun.COM (hidp->hid_external_rq == q));
97910153SAaron.Zang@Sun.COM
98010153SAaron.Zang@Sun.COM if (hidp->hid_internal_rq == q)
98110153SAaron.Zang@Sun.COM hidp->hid_internal_flag = HID_STREAMS_DISMANTLING;
98210153SAaron.Zang@Sun.COM else
98310153SAaron.Zang@Sun.COM hidp->hid_external_flag = HID_STREAMS_DISMANTLING;
98410153SAaron.Zang@Sun.COM
9850Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
9860Sstevel@tonic-gate
9870Sstevel@tonic-gate /*
9880Sstevel@tonic-gate * In case there are any outstanding requests on
9890Sstevel@tonic-gate * the default pipe, wait forever for them to complete.
9900Sstevel@tonic-gate */
9910Sstevel@tonic-gate (void) usb_pipe_drain_reqs(hidp->hid_dip,
9920Sstevel@tonic-gate hidp->hid_default_pipe, 0, USB_FLAGS_SLEEP, NULL, 0);
9930Sstevel@tonic-gate
9949432SPengcheng.Chen@Sun.COM mutex_enter(&hidp->hid_mutex);
9959432SPengcheng.Chen@Sun.COM wq = WR(q);
9960Sstevel@tonic-gate /* drain any M_CTLS on the WQ */
9970Sstevel@tonic-gate while (mp = getq(wq)) {
9980Sstevel@tonic-gate hid_qreply_merror(wq, mp, EIO);
9990Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
10000Sstevel@tonic-gate hid_pm_idle_component(hidp);
10010Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate qprocsoff(q);
10069432SPengcheng.Chen@Sun.COM
10070Sstevel@tonic-gate q->q_ptr = NULL;
10089432SPengcheng.Chen@Sun.COM wq->q_ptr = NULL;
10099432SPengcheng.Chen@Sun.COM
101010153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
101110153SAaron.Zang@Sun.COM
101210153SAaron.Zang@Sun.COM if (hidp->hid_internal_rq == q) {
101310153SAaron.Zang@Sun.COM hidp->hid_internal_rq = NULL;
101410153SAaron.Zang@Sun.COM hidp->hid_internal_flag = 0;
101510153SAaron.Zang@Sun.COM if (hidp->hid_inuse_rq == q) {
101610153SAaron.Zang@Sun.COM /* We are closing the active stream */
101710153SAaron.Zang@Sun.COM if (hidp->hid_external_flag == HID_STREAMS_OPEN)
101810153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = hidp->hid_external_rq;
101910153SAaron.Zang@Sun.COM else
102010153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = NULL;
102110153SAaron.Zang@Sun.COM }
10229432SPengcheng.Chen@Sun.COM } else {
102310153SAaron.Zang@Sun.COM hidp->hid_external_rq = NULL;
102410153SAaron.Zang@Sun.COM hidp->hid_external_flag = 0;
102510153SAaron.Zang@Sun.COM if (hidp->hid_inuse_rq == q) {
102610153SAaron.Zang@Sun.COM /* We are closing the active stream */
102710153SAaron.Zang@Sun.COM if (hidp->hid_internal_flag == HID_STREAMS_OPEN)
102810153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = hidp->hid_internal_rq;
102910153SAaron.Zang@Sun.COM else
103010153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = NULL;
103110153SAaron.Zang@Sun.COM }
10329432SPengcheng.Chen@Sun.COM }
103310153SAaron.Zang@Sun.COM
103410153SAaron.Zang@Sun.COM if (hidp->hid_inuse_rq != NULL) {
10359432SPengcheng.Chen@Sun.COM mutex_exit(&hidp->hid_mutex);
10369432SPengcheng.Chen@Sun.COM return (0);
10379432SPengcheng.Chen@Sun.COM }
10389432SPengcheng.Chen@Sun.COM
10399432SPengcheng.Chen@Sun.COM /* all queues are closed, close USB pipes */
10409432SPengcheng.Chen@Sun.COM hid_close_intr_pipe(hidp);
10419432SPengcheng.Chen@Sun.COM mutex_exit(&hidp->hid_mutex);
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate /*
10440Sstevel@tonic-gate * Devices other than keyboard/mouse go idle on close.
10450Sstevel@tonic-gate */
10460Sstevel@tonic-gate switch (hidp->hid_pm->hid_pm_strategy) {
10470Sstevel@tonic-gate case HID_PM_ACTIVITY:
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate break;
10500Sstevel@tonic-gate default:
10510Sstevel@tonic-gate hid_pm_idle_component(hidp);
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate break;
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
10560Sstevel@tonic-gate "hid_close: End");
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate return (0);
10590Sstevel@tonic-gate }
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate /*
10630Sstevel@tonic-gate * hid_wput :
10640Sstevel@tonic-gate * write put routine for the hid module
10650Sstevel@tonic-gate */
10660Sstevel@tonic-gate static int
hid_wput(queue_t * q,mblk_t * mp)10670Sstevel@tonic-gate hid_wput(queue_t *q, mblk_t *mp)
10680Sstevel@tonic-gate {
106910153SAaron.Zang@Sun.COM hid_state_t *hidp = (hid_state_t *)q->q_ptr;
10700Sstevel@tonic-gate int error = USB_SUCCESS;
107110153SAaron.Zang@Sun.COM struct iocblk *iocbp;
107210153SAaron.Zang@Sun.COM mblk_t *datap;
107310153SAaron.Zang@Sun.COM int direction;
107410153SAaron.Zang@Sun.COM struct copyresp *crp;
107510153SAaron.Zang@Sun.COM queue_t *tmpq;
107610153SAaron.Zang@Sun.COM int flag;
10770Sstevel@tonic-gate
10780Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
10790Sstevel@tonic-gate "hid_wput: Begin");
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate /* See if the upper module is passing the right thing */
10820Sstevel@tonic-gate ASSERT(mp != NULL);
10830Sstevel@tonic-gate ASSERT(mp->b_datap != NULL);
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate switch (mp->b_datap->db_type) {
10860Sstevel@tonic-gate case M_FLUSH: /* Canonical flush handling */
10870Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
10880Sstevel@tonic-gate flushq(q, FLUSHDATA);
10890Sstevel@tonic-gate }
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate /* read queue not used so just send up */
10920Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
10930Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
10940Sstevel@tonic-gate qreply(q, mp);
10950Sstevel@tonic-gate } else {
10960Sstevel@tonic-gate freemsg(mp);
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate break;
11000Sstevel@tonic-gate case M_IOCTL:
110110153SAaron.Zang@Sun.COM iocbp = (struct iocblk *)mp->b_rptr;
110210153SAaron.Zang@Sun.COM
110310153SAaron.Zang@Sun.COM /* Only accept transparent ioctls */
110410153SAaron.Zang@Sun.COM if (iocbp->ioc_count != TRANSPARENT) {
110510153SAaron.Zang@Sun.COM miocnak(q, mp, 0, EINVAL);
110610153SAaron.Zang@Sun.COM break;
110710153SAaron.Zang@Sun.COM }
110810153SAaron.Zang@Sun.COM
110910153SAaron.Zang@Sun.COM switch (iocbp->ioc_cmd) {
111010153SAaron.Zang@Sun.COM case HIDIOCKMGDIRECT:
111110153SAaron.Zang@Sun.COM
111210153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
111310153SAaron.Zang@Sun.COM ASSERT(hidp->hid_inuse_rq != NULL);
111410153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
111510153SAaron.Zang@Sun.COM
111610153SAaron.Zang@Sun.COM if ((datap = allocb(sizeof (int), BPRI_MED)) == NULL) {
111710153SAaron.Zang@Sun.COM miocnak(q, mp, 0, ENOMEM);
111810153SAaron.Zang@Sun.COM break;
111910153SAaron.Zang@Sun.COM }
112010153SAaron.Zang@Sun.COM
112110153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
112210153SAaron.Zang@Sun.COM if (hidp->hid_inuse_rq == hidp->hid_internal_rq) {
112310153SAaron.Zang@Sun.COM *(int *)datap->b_wptr = 0;
112410153SAaron.Zang@Sun.COM datap->b_wptr += sizeof (int);
112510153SAaron.Zang@Sun.COM } else {
112610153SAaron.Zang@Sun.COM ASSERT(hidp->hid_inuse_rq ==
112710153SAaron.Zang@Sun.COM hidp->hid_external_rq);
112810153SAaron.Zang@Sun.COM *(int *)datap->b_wptr = 1;
112910153SAaron.Zang@Sun.COM datap->b_wptr += sizeof (int);
113010153SAaron.Zang@Sun.COM }
113110153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
113210153SAaron.Zang@Sun.COM
113310153SAaron.Zang@Sun.COM mcopyout(mp, NULL, sizeof (int), NULL, datap);
113410153SAaron.Zang@Sun.COM qreply(q, mp);
113510153SAaron.Zang@Sun.COM break;
113610153SAaron.Zang@Sun.COM
113710153SAaron.Zang@Sun.COM case HIDIOCKMSDIRECT:
113810153SAaron.Zang@Sun.COM mcopyin(mp, NULL, sizeof (int), NULL);
113910153SAaron.Zang@Sun.COM qreply(q, mp);
114010153SAaron.Zang@Sun.COM break;
114110153SAaron.Zang@Sun.COM
114210153SAaron.Zang@Sun.COM default:
114310153SAaron.Zang@Sun.COM miocnak(q, mp, 0, ENOTTY);
114410153SAaron.Zang@Sun.COM }
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate break;
114710153SAaron.Zang@Sun.COM
114810153SAaron.Zang@Sun.COM case M_IOCDATA:
114910153SAaron.Zang@Sun.COM
115010153SAaron.Zang@Sun.COM crp = (void *)mp->b_rptr;
115110153SAaron.Zang@Sun.COM
115210153SAaron.Zang@Sun.COM if (crp->cp_rval != 0) {
115310153SAaron.Zang@Sun.COM miocnak(q, mp, 0, EIO);
115410153SAaron.Zang@Sun.COM break;
115510153SAaron.Zang@Sun.COM }
115610153SAaron.Zang@Sun.COM
115710153SAaron.Zang@Sun.COM switch (crp->cp_cmd) {
115810153SAaron.Zang@Sun.COM case HIDIOCKMGDIRECT:
115910153SAaron.Zang@Sun.COM miocack(q, mp, 0, 0);
116010153SAaron.Zang@Sun.COM break;
116110153SAaron.Zang@Sun.COM
116210153SAaron.Zang@Sun.COM case HIDIOCKMSDIRECT:
116310153SAaron.Zang@Sun.COM direction = *(int *)mp->b_cont->b_rptr;
116410153SAaron.Zang@Sun.COM
116510153SAaron.Zang@Sun.COM if ((direction != 0) && (direction != 1)) {
116610153SAaron.Zang@Sun.COM miocnak(q, mp, 0, EINVAL);
116710153SAaron.Zang@Sun.COM break;
116810153SAaron.Zang@Sun.COM }
116910153SAaron.Zang@Sun.COM
117010153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
117110153SAaron.Zang@Sun.COM
117210153SAaron.Zang@Sun.COM if (direction == 0) {
117310153SAaron.Zang@Sun.COM /* The internal stream is made active */
117410153SAaron.Zang@Sun.COM flag = hidp->hid_internal_flag;
117510153SAaron.Zang@Sun.COM tmpq = hidp->hid_internal_rq;
117610153SAaron.Zang@Sun.COM } else {
117710153SAaron.Zang@Sun.COM /* The external stream is made active */
117810153SAaron.Zang@Sun.COM flag = hidp->hid_external_flag;
117910153SAaron.Zang@Sun.COM tmpq = hidp->hid_external_rq;
118010153SAaron.Zang@Sun.COM }
118110153SAaron.Zang@Sun.COM
118210153SAaron.Zang@Sun.COM if (flag != HID_STREAMS_OPEN) {
118310153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
118410153SAaron.Zang@Sun.COM miocnak(q, mp, 0, EIO);
118510153SAaron.Zang@Sun.COM break;
118610153SAaron.Zang@Sun.COM }
118710153SAaron.Zang@Sun.COM
118810153SAaron.Zang@Sun.COM hidp->hid_inuse_rq = tmpq;
118910153SAaron.Zang@Sun.COM
119010153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
119110153SAaron.Zang@Sun.COM miocack(q, mp, 0, 0);
119210153SAaron.Zang@Sun.COM break;
119310153SAaron.Zang@Sun.COM
119410153SAaron.Zang@Sun.COM default:
119510153SAaron.Zang@Sun.COM miocnak(q, mp, 0, ENOTTY);
119610153SAaron.Zang@Sun.COM break;
119710153SAaron.Zang@Sun.COM }
119810153SAaron.Zang@Sun.COM
119910153SAaron.Zang@Sun.COM break;
120010153SAaron.Zang@Sun.COM
12010Sstevel@tonic-gate case M_CTL:
12020Sstevel@tonic-gate /* we are busy now */
12030Sstevel@tonic-gate hid_pm_busy_component(hidp);
12040Sstevel@tonic-gate
12050Sstevel@tonic-gate if (q->q_first) {
12060Sstevel@tonic-gate (void) putq(q, mp);
12070Sstevel@tonic-gate } else {
12080Sstevel@tonic-gate error = hid_mctl_receive(q, mp);
12090Sstevel@tonic-gate switch (error) {
12100Sstevel@tonic-gate case HID_ENQUEUE:
12110Sstevel@tonic-gate /*
12120Sstevel@tonic-gate * put this mblk on the WQ for the wsrv to
12130Sstevel@tonic-gate * process
12140Sstevel@tonic-gate */
12150Sstevel@tonic-gate (void) putq(q, mp);
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate break;
12180Sstevel@tonic-gate case HID_INPROGRESS:
12190Sstevel@tonic-gate /* request has been queued to the device */
12200Sstevel@tonic-gate
12210Sstevel@tonic-gate break;
12220Sstevel@tonic-gate case HID_SUCCESS:
12230Sstevel@tonic-gate /*
12240Sstevel@tonic-gate * returned by M_CTLS that are processed
12250Sstevel@tonic-gate * immediately
12260Sstevel@tonic-gate */
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate /* FALLTHRU */
12290Sstevel@tonic-gate case HID_FAILURE:
12300Sstevel@tonic-gate default:
12310Sstevel@tonic-gate hid_pm_idle_component(hidp);
12320Sstevel@tonic-gate break;
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate break;
12360Sstevel@tonic-gate default:
12370Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
12380Sstevel@tonic-gate error = USB_FAILURE;
12390Sstevel@tonic-gate break;
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate
12420Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
12430Sstevel@tonic-gate "hid_wput: End");
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate return (DDI_SUCCESS);
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate /*
12500Sstevel@tonic-gate * hid_wsrv :
12510Sstevel@tonic-gate * Write service routine for hid. When a message arrives through
12520Sstevel@tonic-gate * hid_wput(), it is kept in write queue to be serviced later.
12530Sstevel@tonic-gate */
12540Sstevel@tonic-gate static int
hid_wsrv(queue_t * q)12550Sstevel@tonic-gate hid_wsrv(queue_t *q)
12560Sstevel@tonic-gate {
125710153SAaron.Zang@Sun.COM hid_state_t *hidp = (hid_state_t *)q->q_ptr;
12580Sstevel@tonic-gate int error;
12590Sstevel@tonic-gate mblk_t *mp;
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
12620Sstevel@tonic-gate "hid_wsrv: Begin");
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
12650Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
12660Sstevel@tonic-gate "hid_wsrv: dev_state: %s",
12670Sstevel@tonic-gate usb_str_dev_state(hidp->hid_dev_state));
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate /*
12700Sstevel@tonic-gate * raise power if we are powered down. It is OK to block here since
12710Sstevel@tonic-gate * we have a separate thread to process this STREAM
12720Sstevel@tonic-gate */
12730Sstevel@tonic-gate if (hidp->hid_dev_state == USB_DEV_PWRED_DOWN) {
12740Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
12750Sstevel@tonic-gate (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
12760Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
12770Sstevel@tonic-gate }
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate /*
12800Sstevel@tonic-gate * continue servicing all the M_CTL's till the queue is empty
12810Sstevel@tonic-gate * or the device gets disconnected or till a hid_close()
12820Sstevel@tonic-gate */
12830Sstevel@tonic-gate while ((hidp->hid_dev_state == USB_DEV_ONLINE) &&
128410153SAaron.Zang@Sun.COM (HID_STREAMS_FLAG(q, hidp) != HID_STREAMS_DISMANTLING) &&
12850Sstevel@tonic-gate ((mp = getq(q)) != NULL)) {
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate /* Send a message down */
12880Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
12890Sstevel@tonic-gate error = hid_mctl_receive(q, mp);
12900Sstevel@tonic-gate switch (error) {
12910Sstevel@tonic-gate case HID_ENQUEUE:
12920Sstevel@tonic-gate /* put this mblk back on q to preserve order */
12930Sstevel@tonic-gate (void) putbq(q, mp);
12940Sstevel@tonic-gate
12950Sstevel@tonic-gate break;
12960Sstevel@tonic-gate case HID_INPROGRESS:
12970Sstevel@tonic-gate /* request has been queued to the device */
12980Sstevel@tonic-gate
12990Sstevel@tonic-gate break;
13000Sstevel@tonic-gate case HID_SUCCESS:
13010Sstevel@tonic-gate case HID_FAILURE:
13020Sstevel@tonic-gate default:
13030Sstevel@tonic-gate hid_pm_idle_component(hidp);
13040Sstevel@tonic-gate
13050Sstevel@tonic-gate break;
13060Sstevel@tonic-gate }
13070Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
13080Sstevel@tonic-gate }
13090Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
13100Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
13110Sstevel@tonic-gate "hid_wsrv: End");
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate return (DDI_SUCCESS);
13140Sstevel@tonic-gate }
13150Sstevel@tonic-gate
13160Sstevel@tonic-gate
13170Sstevel@tonic-gate /*
13180Sstevel@tonic-gate * hid_power:
13190Sstevel@tonic-gate * power entry point
13200Sstevel@tonic-gate */
13210Sstevel@tonic-gate static int
hid_power(dev_info_t * dip,int comp,int level)13220Sstevel@tonic-gate hid_power(dev_info_t *dip, int comp, int level)
13230Sstevel@tonic-gate {
13240Sstevel@tonic-gate int instance = ddi_get_instance(dip);
13250Sstevel@tonic-gate hid_state_t *hidp;
13260Sstevel@tonic-gate hid_power_t *hidpm;
13270Sstevel@tonic-gate int retval;
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate hidp = ddi_get_soft_state(hid_statep, instance);
13300Sstevel@tonic-gate
13310Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_PM, hidp->hid_log_handle, "hid_power:"
13320Sstevel@tonic-gate " hid_state: comp=%d level=%d", comp, level);
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate /* check if we are transitioning to a legal power level */
13350Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
13360Sstevel@tonic-gate hidpm = hidp->hid_pm;
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate if (USB_DEV_PWRSTATE_OK(hidpm->hid_pwr_states, level)) {
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM, hidp->hid_log_handle,
13410Sstevel@tonic-gate "hid_power: illegal level=%d hid_pwr_states=%d",
13420Sstevel@tonic-gate level, hidpm->hid_pwr_states);
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
13450Sstevel@tonic-gate
13460Sstevel@tonic-gate return (DDI_FAILURE);
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate switch (level) {
13500Sstevel@tonic-gate case USB_DEV_OS_PWR_OFF:
13510Sstevel@tonic-gate retval = hid_pwrlvl0(hidp);
13520Sstevel@tonic-gate break;
13530Sstevel@tonic-gate case USB_DEV_OS_PWR_1:
13540Sstevel@tonic-gate retval = hid_pwrlvl1(hidp);
13550Sstevel@tonic-gate break;
13560Sstevel@tonic-gate case USB_DEV_OS_PWR_2:
13570Sstevel@tonic-gate retval = hid_pwrlvl2(hidp);
13580Sstevel@tonic-gate break;
13590Sstevel@tonic-gate case USB_DEV_OS_FULL_PWR:
13600Sstevel@tonic-gate retval = hid_pwrlvl3(hidp);
13610Sstevel@tonic-gate break;
13620Sstevel@tonic-gate default:
13630Sstevel@tonic-gate retval = USB_FAILURE;
13640Sstevel@tonic-gate break;
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate
13670Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
13700Sstevel@tonic-gate }
13710Sstevel@tonic-gate
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate /*
13740Sstevel@tonic-gate * hid_interrupt_pipe_callback:
13750Sstevel@tonic-gate * Callback function for the hid intr pipe. This function is called by
13760Sstevel@tonic-gate * USBA when a buffer has been filled. This driver does not cook the data,
13770Sstevel@tonic-gate * it just sends the message up.
13780Sstevel@tonic-gate */
13790Sstevel@tonic-gate static void
hid_interrupt_pipe_callback(usb_pipe_handle_t pipe,usb_intr_req_t * req)13800Sstevel@tonic-gate hid_interrupt_pipe_callback(usb_pipe_handle_t pipe, usb_intr_req_t *req)
13810Sstevel@tonic-gate {
13820Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)req->intr_client_private;
13830Sstevel@tonic-gate queue_t *q;
13840Sstevel@tonic-gate
13850Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
13866898Sfb209375 "hid_interrupt_pipe_callback: ph = 0x%p req = 0x%p",
13876898Sfb209375 (void *)pipe, (void *)req);
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate hid_pm_busy_component(hidp);
13900Sstevel@tonic-gate
13910Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
13920Sstevel@tonic-gate
13930Sstevel@tonic-gate /*
13940Sstevel@tonic-gate * If hid_close() is in progress, we shouldn't try accessing queue
13950Sstevel@tonic-gate * Otherwise indicate that a putnext is going to happen, so
13960Sstevel@tonic-gate * if close after this, that should wait for the putnext to finish.
13970Sstevel@tonic-gate */
139810153SAaron.Zang@Sun.COM if (HID_STREAMS_FLAG(hidp->hid_inuse_rq, hidp) ==
139910153SAaron.Zang@Sun.COM HID_STREAMS_OPEN) {
14000Sstevel@tonic-gate /*
14010Sstevel@tonic-gate * Check if data can be put to the next queue.
14020Sstevel@tonic-gate */
140310153SAaron.Zang@Sun.COM if (!canputnext(hidp->hid_inuse_rq)) {
14040Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
14050Sstevel@tonic-gate "Buffer flushed when overflowed.");
14060Sstevel@tonic-gate
14070Sstevel@tonic-gate /* Flush the queue above */
140810153SAaron.Zang@Sun.COM hid_flush(hidp->hid_inuse_rq);
14090Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
14100Sstevel@tonic-gate } else {
141110153SAaron.Zang@Sun.COM q = hidp->hid_inuse_rq;
14120Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
14130Sstevel@tonic-gate
14140Sstevel@tonic-gate /* Put data upstream */
14150Sstevel@tonic-gate putnext(q, req->intr_data);
14160Sstevel@tonic-gate
14170Sstevel@tonic-gate /* usb_free_intr_req should not free data */
14180Sstevel@tonic-gate req->intr_data = NULL;
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate } else {
14210Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
14220Sstevel@tonic-gate }
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate /* free request and data */
14250Sstevel@tonic-gate usb_free_intr_req(req);
14260Sstevel@tonic-gate hid_pm_idle_component(hidp);
14270Sstevel@tonic-gate }
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate /*
14310Sstevel@tonic-gate * hid_default_pipe_callback :
14320Sstevel@tonic-gate * Callback routine for the asynchronous control transfer
14330Sstevel@tonic-gate * Called from hid_send_async_ctrl_request() where we open
14340Sstevel@tonic-gate * the pipe in exclusive mode
14350Sstevel@tonic-gate */
14360Sstevel@tonic-gate static void
hid_default_pipe_callback(usb_pipe_handle_t pipe,usb_ctrl_req_t * req)14370Sstevel@tonic-gate hid_default_pipe_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *req)
14380Sstevel@tonic-gate {
14390Sstevel@tonic-gate hid_default_pipe_arg_t *hid_default_pipe_arg =
14400Sstevel@tonic-gate (hid_default_pipe_arg_t *)req->ctrl_client_private;
14419432SPengcheng.Chen@Sun.COM queue_t *wq = hid_default_pipe_arg->hid_default_pipe_arg_queue;
14429432SPengcheng.Chen@Sun.COM queue_t *rq = RD(wq);
144310153SAaron.Zang@Sun.COM hid_state_t *hidp = (hid_state_t *)rq->q_ptr;
14440Sstevel@tonic-gate mblk_t *mctl_mp;
14450Sstevel@tonic-gate mblk_t *data = NULL;
14460Sstevel@tonic-gate
14470Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14480Sstevel@tonic-gate "hid_default_pipe_callback: "
14496898Sfb209375 "ph = 0x%p, req = 0x%p, data= 0x%p",
14506898Sfb209375 (void *)pipe, (void *)req, (void *)data);
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate ASSERT((req->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0);
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate if (req->ctrl_data) {
14550Sstevel@tonic-gate data = req->ctrl_data;
14560Sstevel@tonic-gate req->ctrl_data = NULL;
14570Sstevel@tonic-gate }
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate /*
14600Sstevel@tonic-gate * Free the b_cont of the original message that was sent down.
14610Sstevel@tonic-gate */
14620Sstevel@tonic-gate mctl_mp = hid_default_pipe_arg->hid_default_pipe_arg_mblk;
14630Sstevel@tonic-gate freemsg(mctl_mp->b_cont);
14640Sstevel@tonic-gate
14650Sstevel@tonic-gate /* chain the mblk received to the original & send it up */
14660Sstevel@tonic-gate mctl_mp->b_cont = data;
14679432SPengcheng.Chen@Sun.COM
14689432SPengcheng.Chen@Sun.COM if (canputnext(rq)) {
14699432SPengcheng.Chen@Sun.COM putnext(rq, mctl_mp);
14700Sstevel@tonic-gate } else {
14710Sstevel@tonic-gate freemsg(mctl_mp); /* avoid leak */
14720Sstevel@tonic-gate }
14730Sstevel@tonic-gate
14740Sstevel@tonic-gate /*
14750Sstevel@tonic-gate * Free the argument for the asynchronous callback
14760Sstevel@tonic-gate */
14770Sstevel@tonic-gate kmem_free(hid_default_pipe_arg, sizeof (hid_default_pipe_arg_t));
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate * Free the control pipe request structure.
14810Sstevel@tonic-gate */
14820Sstevel@tonic-gate usb_free_ctrl_req(req);
14830Sstevel@tonic-gate
14840Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
14850Sstevel@tonic-gate hidp->hid_default_pipe_req--;
14860Sstevel@tonic-gate ASSERT(hidp->hid_default_pipe_req >= 0);
14870Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate hid_pm_idle_component(hidp);
14909432SPengcheng.Chen@Sun.COM qenable(wq);
14910Sstevel@tonic-gate }
14920Sstevel@tonic-gate
14930Sstevel@tonic-gate
14940Sstevel@tonic-gate /*
14950Sstevel@tonic-gate * hid_interrupt_pipe_exception_callback:
14960Sstevel@tonic-gate * Exception callback routine for interrupt pipe. If there is any data,
14970Sstevel@tonic-gate * destroy it. No threads are waiting for the exception callback.
14980Sstevel@tonic-gate */
14990Sstevel@tonic-gate /*ARGSUSED*/
15000Sstevel@tonic-gate static void
hid_interrupt_pipe_exception_callback(usb_pipe_handle_t pipe,usb_intr_req_t * req)15010Sstevel@tonic-gate hid_interrupt_pipe_exception_callback(usb_pipe_handle_t pipe,
15020Sstevel@tonic-gate usb_intr_req_t *req)
15030Sstevel@tonic-gate {
15040Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)req->intr_client_private;
15050Sstevel@tonic-gate mblk_t *data = req->intr_data;
15060Sstevel@tonic-gate usb_cb_flags_t flags = req->intr_cb_flags;
15070Sstevel@tonic-gate int rval;
15080Sstevel@tonic-gate
15090Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
15100Sstevel@tonic-gate "hid_interrupt_pipe_exception_callback: "
15110Sstevel@tonic-gate "completion_reason = 0x%x, data = 0x%p, flag = 0x%x",
15120Sstevel@tonic-gate req->intr_completion_reason, (void *)data, req->intr_cb_flags);
15130Sstevel@tonic-gate
15140Sstevel@tonic-gate ASSERT((req->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0);
15150Sstevel@tonic-gate
15160Sstevel@tonic-gate if (((flags & USB_CB_FUNCTIONAL_STALL) != 0) &&
15170Sstevel@tonic-gate ((flags & USB_CB_STALL_CLEARED) == 0)) {
15180Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
15190Sstevel@tonic-gate hidp->hid_log_handle,
15200Sstevel@tonic-gate "hid_interrupt_pipe_exception_callback: "
15210Sstevel@tonic-gate "unable to clear stall. flags = 0x%x",
15220Sstevel@tonic-gate req->intr_cb_flags);
15230Sstevel@tonic-gate }
15240Sstevel@tonic-gate
15250Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate switch (req->intr_completion_reason) {
15280Sstevel@tonic-gate case USB_CR_STOPPED_POLLING:
15290Sstevel@tonic-gate case USB_CR_PIPE_CLOSING:
15300Sstevel@tonic-gate default:
15310Sstevel@tonic-gate
15320Sstevel@tonic-gate break;
15330Sstevel@tonic-gate case USB_CR_PIPE_RESET:
15340Sstevel@tonic-gate case USB_CR_NO_RESOURCES:
15350Sstevel@tonic-gate if ((hidp->hid_dev_state == USB_DEV_ONLINE) &&
15360Sstevel@tonic-gate ((rval = hid_start_intr_polling(hidp)) !=
15370Sstevel@tonic-gate USB_SUCCESS)) {
15380Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
15390Sstevel@tonic-gate "unable to restart interrupt poll. rval = %d",
15400Sstevel@tonic-gate rval);
15410Sstevel@tonic-gate }
15420Sstevel@tonic-gate
15430Sstevel@tonic-gate break;
15440Sstevel@tonic-gate }
15450Sstevel@tonic-gate
15460Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
15470Sstevel@tonic-gate
15480Sstevel@tonic-gate usb_free_intr_req(req);
15490Sstevel@tonic-gate }
15500Sstevel@tonic-gate
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate /*
15530Sstevel@tonic-gate * hid_default_pipe_exception_callback:
15540Sstevel@tonic-gate * Exception callback routine for default pipe.
15550Sstevel@tonic-gate */
15560Sstevel@tonic-gate /*ARGSUSED*/
15570Sstevel@tonic-gate static void
hid_default_pipe_exception_callback(usb_pipe_handle_t pipe,usb_ctrl_req_t * req)15580Sstevel@tonic-gate hid_default_pipe_exception_callback(usb_pipe_handle_t pipe,
15590Sstevel@tonic-gate usb_ctrl_req_t *req)
15600Sstevel@tonic-gate {
15610Sstevel@tonic-gate hid_default_pipe_arg_t *hid_default_pipe_arg =
15620Sstevel@tonic-gate (hid_default_pipe_arg_t *)req->ctrl_client_private;
15639432SPengcheng.Chen@Sun.COM queue_t *wq = hid_default_pipe_arg->hid_default_pipe_arg_queue;
15649432SPengcheng.Chen@Sun.COM queue_t *rq = RD(wq);
156510153SAaron.Zang@Sun.COM hid_state_t *hidp = (hid_state_t *)rq->q_ptr;
15660Sstevel@tonic-gate usb_cr_t ctrl_completion_reason = req->ctrl_completion_reason;
15679432SPengcheng.Chen@Sun.COM mblk_t *mp, *data = NULL;
15680Sstevel@tonic-gate
15690Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
15700Sstevel@tonic-gate "hid_default_pipe_exception_callback: "
15710Sstevel@tonic-gate "completion_reason = 0x%x, data = 0x%p, flag = 0x%x",
15720Sstevel@tonic-gate ctrl_completion_reason, (void *)data, req->ctrl_cb_flags);
15730Sstevel@tonic-gate
15740Sstevel@tonic-gate ASSERT((req->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0);
15750Sstevel@tonic-gate
15769432SPengcheng.Chen@Sun.COM mp = hid_default_pipe_arg->hid_default_pipe_arg_mblk;
15770Sstevel@tonic-gate
15780Sstevel@tonic-gate /*
15790Sstevel@tonic-gate * Pass an error message up. Reuse existing mblk.
15800Sstevel@tonic-gate */
15819432SPengcheng.Chen@Sun.COM if (canputnext(rq)) {
15820Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR;
15830Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base;
15840Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char);
15850Sstevel@tonic-gate *mp->b_rptr = EIO;
15869432SPengcheng.Chen@Sun.COM putnext(rq, mp);
15870Sstevel@tonic-gate } else {
15889432SPengcheng.Chen@Sun.COM freemsg(mp);
15890Sstevel@tonic-gate }
15909432SPengcheng.Chen@Sun.COM
15910Sstevel@tonic-gate kmem_free(hid_default_pipe_arg, sizeof (hid_default_pipe_arg_t));
15920Sstevel@tonic-gate
15930Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
15940Sstevel@tonic-gate hidp->hid_default_pipe_req--;
15950Sstevel@tonic-gate ASSERT(hidp->hid_default_pipe_req >= 0);
15960Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
15970Sstevel@tonic-gate
15989432SPengcheng.Chen@Sun.COM qenable(wq);
15990Sstevel@tonic-gate usb_free_ctrl_req(req);
16000Sstevel@tonic-gate hid_pm_idle_component(hidp);
16010Sstevel@tonic-gate }
16020Sstevel@tonic-gate
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate /*
16050Sstevel@tonic-gate * event handling:
16060Sstevel@tonic-gate *
16070Sstevel@tonic-gate * hid_reconnect_event_callback:
16080Sstevel@tonic-gate * the device was disconnected but this instance not detached, probably
16090Sstevel@tonic-gate * because the device was busy
16100Sstevel@tonic-gate *
16110Sstevel@tonic-gate * If the same device, continue with restoring state
16120Sstevel@tonic-gate */
16130Sstevel@tonic-gate static int
hid_restore_state_event_callback(dev_info_t * dip)16140Sstevel@tonic-gate hid_restore_state_event_callback(dev_info_t *dip)
16150Sstevel@tonic-gate {
16160Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)ddi_get_soft_state(hid_statep,
16176898Sfb209375 ddi_get_instance(dip));
16180Sstevel@tonic-gate
16190Sstevel@tonic-gate ASSERT(hidp != NULL);
16200Sstevel@tonic-gate
16210Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_EVENTS, hidp->hid_log_handle,
16226898Sfb209375 "hid_restore_state_event_callback: dip=0x%p", (void *)dip);
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate hid_restore_device_state(dip, hidp);
16250Sstevel@tonic-gate
16260Sstevel@tonic-gate return (USB_SUCCESS);
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate
16290Sstevel@tonic-gate
16300Sstevel@tonic-gate /*
16310Sstevel@tonic-gate * hid_cpr_suspend
16320Sstevel@tonic-gate * Fail suspend if we can't finish outstanding i/o activity.
16330Sstevel@tonic-gate */
16340Sstevel@tonic-gate static int
hid_cpr_suspend(hid_state_t * hidp)16350Sstevel@tonic-gate hid_cpr_suspend(hid_state_t *hidp)
16360Sstevel@tonic-gate {
16370Sstevel@tonic-gate int rval, prev_state;
16380Sstevel@tonic-gate int retval = USB_FAILURE;
16390Sstevel@tonic-gate
16400Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
16416898Sfb209375 "hid_cpr_suspend: dip=0x%p", (void *)hidp->hid_dip);
16420Sstevel@tonic-gate
16430Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
16440Sstevel@tonic-gate switch (hidp->hid_dev_state) {
16450Sstevel@tonic-gate case USB_DEV_ONLINE:
16460Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
16470Sstevel@tonic-gate prev_state = hidp->hid_dev_state;
16480Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_SUSPENDED;
16490Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
16500Sstevel@tonic-gate
16510Sstevel@tonic-gate /* drain all request outstanding on the default control pipe */
16520Sstevel@tonic-gate rval = usb_pipe_drain_reqs(hidp->hid_dip,
16530Sstevel@tonic-gate hidp->hid_default_pipe, hid_default_pipe_drain_timeout,
16540Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, 0);
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate /* fail checkpoint if we haven't finished the job yet */
16570Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
16580Sstevel@tonic-gate if ((rval != USB_SUCCESS) || (hidp->hid_default_pipe_req > 0)) {
16590Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
16600Sstevel@tonic-gate "hid_cpr_suspend: "
16610Sstevel@tonic-gate "device busy - can't checkpoint");
16620Sstevel@tonic-gate
16630Sstevel@tonic-gate /* fall back to previous state */
16640Sstevel@tonic-gate hidp->hid_dev_state = prev_state;
16650Sstevel@tonic-gate } else {
16660Sstevel@tonic-gate retval = USB_SUCCESS;
16670Sstevel@tonic-gate hid_save_device_state(hidp);
16680Sstevel@tonic-gate }
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate break;
167112419SFei.Feng@Sun.COM case USB_DEV_DISCONNECTED:
167212419SFei.Feng@Sun.COM hidp->hid_dev_state = USB_DEV_SUSPENDED;
167312419SFei.Feng@Sun.COM hid_save_device_state(hidp);
167412419SFei.Feng@Sun.COM retval = USB_SUCCESS;
167512419SFei.Feng@Sun.COM break;
16760Sstevel@tonic-gate case USB_DEV_SUSPENDED:
16770Sstevel@tonic-gate default:
16780Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
16790Sstevel@tonic-gate "hid_cpr_suspend: Illegal dev state: %d",
16800Sstevel@tonic-gate hidp->hid_dev_state);
16810Sstevel@tonic-gate
16820Sstevel@tonic-gate break;
16830Sstevel@tonic-gate }
16840Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate return (retval);
16870Sstevel@tonic-gate }
16880Sstevel@tonic-gate
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate static void
hid_cpr_resume(hid_state_t * hidp)16910Sstevel@tonic-gate hid_cpr_resume(hid_state_t *hidp)
16920Sstevel@tonic-gate {
16930Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
16946898Sfb209375 "hid_cpr_resume: dip=0x%p", (void *)hidp->hid_dip);
16950Sstevel@tonic-gate
16960Sstevel@tonic-gate hid_restore_device_state(hidp->hid_dip, hidp);
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate
16990Sstevel@tonic-gate
17000Sstevel@tonic-gate /*
17010Sstevel@tonic-gate * hid_disconnect_event_callback:
17020Sstevel@tonic-gate * The device has been disconnected. We either wait for
17030Sstevel@tonic-gate * detach or a reconnect event. Close all pipes and timeouts.
17040Sstevel@tonic-gate */
17050Sstevel@tonic-gate static int
hid_disconnect_event_callback(dev_info_t * dip)17060Sstevel@tonic-gate hid_disconnect_event_callback(dev_info_t *dip)
17070Sstevel@tonic-gate {
17080Sstevel@tonic-gate hid_state_t *hidp;
17099432SPengcheng.Chen@Sun.COM mblk_t *mp;
17100Sstevel@tonic-gate
17110Sstevel@tonic-gate hidp = (hid_state_t *)ddi_get_soft_state(hid_statep,
17120Sstevel@tonic-gate ddi_get_instance(dip));
17130Sstevel@tonic-gate ASSERT(hidp != NULL);
17140Sstevel@tonic-gate
17150Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
17166898Sfb209375 "hid_disconnect_event_callback: dip=0x%p", (void *)dip);
17170Sstevel@tonic-gate
17180Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
17190Sstevel@tonic-gate switch (hidp->hid_dev_state) {
17200Sstevel@tonic-gate case USB_DEV_ONLINE:
17210Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
17220Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_DISCONNECTED;
172310153SAaron.Zang@Sun.COM if (HID_IS_OPEN(hidp)) {
17240Sstevel@tonic-gate
17250Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
17260Sstevel@tonic-gate "busy device has been disconnected");
17270Sstevel@tonic-gate }
17280Sstevel@tonic-gate hid_save_device_state(hidp);
17290Sstevel@tonic-gate
17309432SPengcheng.Chen@Sun.COM /*
17319432SPengcheng.Chen@Sun.COM * Notify applications about device removal, this only
17329432SPengcheng.Chen@Sun.COM * applies to an external (aka. physical) open. For an
17339432SPengcheng.Chen@Sun.COM * internal open, consconfig_dacf closes the queue.
17349432SPengcheng.Chen@Sun.COM */
173510153SAaron.Zang@Sun.COM if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
173610153SAaron.Zang@Sun.COM queue_t *q = hidp->hid_external_rq;
173710153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
173810153SAaron.Zang@Sun.COM mp = allocb(sizeof (uchar_t), BPRI_HI);
173910153SAaron.Zang@Sun.COM if (mp != NULL) {
174010153SAaron.Zang@Sun.COM mp->b_datap->db_type = M_ERROR;
174110153SAaron.Zang@Sun.COM mp->b_rptr = mp->b_datap->db_base;
174210153SAaron.Zang@Sun.COM mp->b_wptr = mp->b_rptr + sizeof (char);
174310153SAaron.Zang@Sun.COM *mp->b_rptr = ENODEV;
174410153SAaron.Zang@Sun.COM putnext(q, mp);
17459432SPengcheng.Chen@Sun.COM }
174610153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
17479432SPengcheng.Chen@Sun.COM }
17489432SPengcheng.Chen@Sun.COM
17490Sstevel@tonic-gate break;
17500Sstevel@tonic-gate case USB_DEV_SUSPENDED:
17510Sstevel@tonic-gate /* we remain suspended */
17520Sstevel@tonic-gate
17530Sstevel@tonic-gate break;
17540Sstevel@tonic-gate default:
17550Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
17560Sstevel@tonic-gate "hid_disconnect_event_callback: Illegal dev state: %d",
17570Sstevel@tonic-gate hidp->hid_dev_state);
17580Sstevel@tonic-gate
17590Sstevel@tonic-gate break;
17600Sstevel@tonic-gate }
17610Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
17620Sstevel@tonic-gate
17630Sstevel@tonic-gate return (USB_SUCCESS);
17640Sstevel@tonic-gate }
17650Sstevel@tonic-gate
17660Sstevel@tonic-gate
17670Sstevel@tonic-gate /*
17680Sstevel@tonic-gate * hid_power_change_callback:
17690Sstevel@tonic-gate * Async callback function to notify pm_raise_power completion
17700Sstevel@tonic-gate * after hid_power entry point is called.
17710Sstevel@tonic-gate */
17720Sstevel@tonic-gate static void
hid_power_change_callback(void * arg,int rval)17730Sstevel@tonic-gate hid_power_change_callback(void *arg, int rval)
17740Sstevel@tonic-gate {
17750Sstevel@tonic-gate hid_state_t *hidp;
17760Sstevel@tonic-gate queue_t *wq;
17770Sstevel@tonic-gate
17780Sstevel@tonic-gate hidp = (hid_state_t *)arg;
17790Sstevel@tonic-gate
17800Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
17810Sstevel@tonic-gate "hid_power_change_callback - rval: %d", rval);
17820Sstevel@tonic-gate
17830Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
17840Sstevel@tonic-gate hidp->hid_pm->hid_raise_power = B_FALSE;
17850Sstevel@tonic-gate
17860Sstevel@tonic-gate if (hidp->hid_dev_state == USB_DEV_ONLINE) {
178710153SAaron.Zang@Sun.COM wq = WR(hidp->hid_inuse_rq);
17880Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
17890Sstevel@tonic-gate
17900Sstevel@tonic-gate qenable(wq);
17910Sstevel@tonic-gate
17920Sstevel@tonic-gate } else {
17930Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
17940Sstevel@tonic-gate }
17950Sstevel@tonic-gate }
17960Sstevel@tonic-gate
17970Sstevel@tonic-gate
17980Sstevel@tonic-gate /*
17990Sstevel@tonic-gate * hid_parse_hid_descr:
18000Sstevel@tonic-gate * Parse the hid descriptor, check after interface and after
18010Sstevel@tonic-gate * endpoint descriptor
18020Sstevel@tonic-gate */
18030Sstevel@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)18040Sstevel@tonic-gate hid_parse_hid_descr(
18050Sstevel@tonic-gate usb_hid_descr_t *ret_descr,
18060Sstevel@tonic-gate size_t ret_buf_len,
18070Sstevel@tonic-gate usb_alt_if_data_t *altif_data,
18080Sstevel@tonic-gate usb_ep_data_t *ep_data)
18090Sstevel@tonic-gate {
18100Sstevel@tonic-gate usb_cvs_data_t *cvs;
18110Sstevel@tonic-gate int which_cvs;
18120Sstevel@tonic-gate
18130Sstevel@tonic-gate for (which_cvs = 0; which_cvs < altif_data->altif_n_cvs; which_cvs++) {
18140Sstevel@tonic-gate cvs = &altif_data->altif_cvs[which_cvs];
18150Sstevel@tonic-gate if (cvs->cvs_buf == NULL) {
18160Sstevel@tonic-gate continue;
18170Sstevel@tonic-gate }
18180Sstevel@tonic-gate if (cvs->cvs_buf[1] == USB_DESCR_TYPE_HID) {
18190Sstevel@tonic-gate return (usb_parse_data("ccscccs",
18206898Sfb209375 cvs->cvs_buf, cvs->cvs_buf_len,
18216898Sfb209375 (void *)ret_descr,
18226898Sfb209375 (size_t)ret_buf_len));
18230Sstevel@tonic-gate }
18240Sstevel@tonic-gate }
18250Sstevel@tonic-gate
18260Sstevel@tonic-gate /* now try after endpoint */
18270Sstevel@tonic-gate for (which_cvs = 0; which_cvs < ep_data->ep_n_cvs; which_cvs++) {
18280Sstevel@tonic-gate cvs = &ep_data->ep_cvs[which_cvs];
18290Sstevel@tonic-gate if (cvs->cvs_buf == NULL) {
18300Sstevel@tonic-gate continue;
18310Sstevel@tonic-gate }
18320Sstevel@tonic-gate if (cvs->cvs_buf[1] == USB_DESCR_TYPE_HID) {
18330Sstevel@tonic-gate return (usb_parse_data("ccscccs",
18346898Sfb209375 cvs->cvs_buf, cvs->cvs_buf_len,
18356898Sfb209375 (void *)ret_descr,
18366898Sfb209375 (size_t)ret_buf_len));
18370Sstevel@tonic-gate }
18380Sstevel@tonic-gate }
18390Sstevel@tonic-gate
18400Sstevel@tonic-gate return (USB_PARSE_ERROR);
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate
18430Sstevel@tonic-gate
18440Sstevel@tonic-gate /*
18450Sstevel@tonic-gate * hid_parse_hid_descr_failure:
18460Sstevel@tonic-gate * If parsing of hid descriptor failed and the device is
18470Sstevel@tonic-gate * a keyboard or mouse, use predefined length and packet size.
18480Sstevel@tonic-gate */
18490Sstevel@tonic-gate static int
hid_parse_hid_descr_failure(hid_state_t * hidp)18500Sstevel@tonic-gate hid_parse_hid_descr_failure(hid_state_t *hidp)
18510Sstevel@tonic-gate {
18520Sstevel@tonic-gate /*
18530Sstevel@tonic-gate * Parsing hid descriptor failed, probably because the
18540Sstevel@tonic-gate * device did not return a valid hid descriptor. Check to
18550Sstevel@tonic-gate * see if this is a keyboard or mouse. If so, use the
18560Sstevel@tonic-gate * predefined hid descriptor length and packet size.
18570Sstevel@tonic-gate * Otherwise, detach and return failure.
18580Sstevel@tonic-gate */
18590Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
18600Sstevel@tonic-gate "Parsing of hid descriptor failed");
18610Sstevel@tonic-gate
18620Sstevel@tonic-gate if (hidp->hid_if_descr.bInterfaceProtocol == KEYBOARD_PROTOCOL) {
18630Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
18640Sstevel@tonic-gate "Set hid descriptor length to predefined "
18650Sstevel@tonic-gate "USB_KB_HID_DESCR_LENGTH for keyboard.");
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate /* device is a keyboard */
18680Sstevel@tonic-gate hidp->hid_hid_descr.wReportDescriptorLength =
18696898Sfb209375 USB_KB_HID_DESCR_LENGTH;
18700Sstevel@tonic-gate
18710Sstevel@tonic-gate hidp->hid_packet_size = USBKPSZ;
18720Sstevel@tonic-gate
18730Sstevel@tonic-gate } else if (hidp->hid_if_descr.bInterfaceProtocol ==
18740Sstevel@tonic-gate MOUSE_PROTOCOL) {
18750Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
18760Sstevel@tonic-gate "Set hid descriptor length to predefined "
18770Sstevel@tonic-gate "USB_MS_HID_DESCR_LENGTH for mouse.");
18780Sstevel@tonic-gate
18790Sstevel@tonic-gate /* device is a mouse */
18800Sstevel@tonic-gate hidp->hid_hid_descr.wReportDescriptorLength =
18816898Sfb209375 USB_MS_HID_DESCR_LENGTH;
18820Sstevel@tonic-gate
18830Sstevel@tonic-gate hidp->hid_packet_size = USBMSSZ;
18840Sstevel@tonic-gate } else {
18850Sstevel@tonic-gate
18860Sstevel@tonic-gate return (USB_FAILURE);
18870Sstevel@tonic-gate }
18880Sstevel@tonic-gate
18890Sstevel@tonic-gate return (USB_SUCCESS);
18900Sstevel@tonic-gate }
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate
18930Sstevel@tonic-gate /*
18940Sstevel@tonic-gate * hid_handle_report_descriptor:
18950Sstevel@tonic-gate * Get the report descriptor, call hidparser routine to parse
18960Sstevel@tonic-gate * it and query the hidparser tree to get the packet size
18970Sstevel@tonic-gate */
18980Sstevel@tonic-gate static int
hid_handle_report_descriptor(hid_state_t * hidp,int interface)18990Sstevel@tonic-gate hid_handle_report_descriptor(hid_state_t *hidp,
19000Sstevel@tonic-gate int interface)
19010Sstevel@tonic-gate {
19020Sstevel@tonic-gate usb_cr_t completion_reason;
19030Sstevel@tonic-gate usb_cb_flags_t cb_flags;
19040Sstevel@tonic-gate mblk_t *data = NULL;
19050Sstevel@tonic-gate hidparser_packet_info_t hpack;
19060Sstevel@tonic-gate int i;
19070Sstevel@tonic-gate usb_ctrl_setup_t setup = {
19080Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | /* bmRequestType */
19096898Sfb209375 USB_DEV_REQ_RCPT_IF,
19100Sstevel@tonic-gate USB_REQ_GET_DESCR, /* bRequest */
19110Sstevel@tonic-gate USB_CLASS_DESCR_TYPE_REPORT, /* wValue */
19120Sstevel@tonic-gate 0, /* wIndex: interface, fill in later */
19130Sstevel@tonic-gate 0, /* wLength, fill in later */
19140Sstevel@tonic-gate 0 /* attributes */
19156898Sfb209375 };
19160Sstevel@tonic-gate
19170Sstevel@tonic-gate /*
19180Sstevel@tonic-gate * Parsing hid desciptor was successful earlier.
19190Sstevel@tonic-gate * Get Report Descriptor
19200Sstevel@tonic-gate */
19210Sstevel@tonic-gate setup.wIndex = (uint16_t)interface;
19220Sstevel@tonic-gate setup.wLength = hidp->hid_hid_descr.wReportDescriptorLength;
19230Sstevel@tonic-gate if (usb_pipe_ctrl_xfer_wait(hidp->hid_default_pipe,
19240Sstevel@tonic-gate &setup,
19250Sstevel@tonic-gate &data, /* data */
19260Sstevel@tonic-gate &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
19270Sstevel@tonic-gate
1928978Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
19296898Sfb209375 "Failed to receive the Report Descriptor");
19300Sstevel@tonic-gate freemsg(data);
19310Sstevel@tonic-gate
19320Sstevel@tonic-gate return (USB_FAILURE);
19330Sstevel@tonic-gate
19340Sstevel@tonic-gate } else {
19350Sstevel@tonic-gate int n = hidp->hid_hid_descr.wReportDescriptorLength;
19360Sstevel@tonic-gate
19370Sstevel@tonic-gate ASSERT(data);
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate /* Print the report descriptor */
19400Sstevel@tonic-gate for (i = 0; i < n; i++) {
19410Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
19426898Sfb209375 "Index = %d\tvalue =0x%x", i,
19436898Sfb209375 (int)(data->b_rptr[i]));
19440Sstevel@tonic-gate }
19450Sstevel@tonic-gate
19460Sstevel@tonic-gate /* Get Report Descriptor was successful */
19470Sstevel@tonic-gate if (hidparser_parse_report_descriptor(
19480Sstevel@tonic-gate data->b_rptr,
19490Sstevel@tonic-gate hidp->hid_hid_descr.wReportDescriptorLength,
19500Sstevel@tonic-gate &hidp->hid_hid_descr,
19510Sstevel@tonic-gate &hidp->hid_report_descr) == HIDPARSER_SUCCESS) {
19520Sstevel@tonic-gate
19530Sstevel@tonic-gate /* find max intr-in xfer length */
19540Sstevel@tonic-gate hidparser_find_max_packet_size_from_report_descriptor(
19550Sstevel@tonic-gate hidp->hid_report_descr, &hpack);
19560Sstevel@tonic-gate /* round up to the nearest byte */
19570Sstevel@tonic-gate hidp->hid_packet_size = (hpack.max_packet_size + 7) / 8;
19580Sstevel@tonic-gate
19590Sstevel@tonic-gate /* if report id is used, add more more byte for it */
19600Sstevel@tonic-gate if (hpack.report_id != HID_REPORT_ID_UNDEFINED) {
19610Sstevel@tonic-gate hidp->hid_packet_size++;
19620Sstevel@tonic-gate }
19630Sstevel@tonic-gate } else {
19640Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
19650Sstevel@tonic-gate "Invalid Report Descriptor");
19660Sstevel@tonic-gate freemsg(data);
19670Sstevel@tonic-gate
19680Sstevel@tonic-gate return (USB_FAILURE);
19690Sstevel@tonic-gate }
19700Sstevel@tonic-gate
19710Sstevel@tonic-gate freemsg(data);
19720Sstevel@tonic-gate
19730Sstevel@tonic-gate return (USB_SUCCESS);
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate
19770Sstevel@tonic-gate
19780Sstevel@tonic-gate /*
19790Sstevel@tonic-gate * hid_set_idle:
19800Sstevel@tonic-gate * Make a clas specific request to SET_IDLE.
19810Sstevel@tonic-gate * In this case send no reports if state has not changed.
19820Sstevel@tonic-gate * See HID 7.2.4.
19830Sstevel@tonic-gate */
19840Sstevel@tonic-gate /*ARGSUSED*/
19850Sstevel@tonic-gate static void
hid_set_idle(hid_state_t * hidp)19860Sstevel@tonic-gate hid_set_idle(hid_state_t *hidp)
19870Sstevel@tonic-gate {
19880Sstevel@tonic-gate usb_cr_t completion_reason;
19890Sstevel@tonic-gate usb_cb_flags_t cb_flags;
19900Sstevel@tonic-gate usb_ctrl_setup_t setup = {
19910Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV | /* bmRequestType */
19926898Sfb209375 USB_DEV_REQ_TYPE_CLASS |
19936898Sfb209375 USB_DEV_REQ_RCPT_IF,
19940Sstevel@tonic-gate SET_IDLE, /* bRequest */
19950Sstevel@tonic-gate DURATION, /* wValue */
19960Sstevel@tonic-gate 0, /* wIndex: interface, fill in later */
19970Sstevel@tonic-gate 0, /* wLength */
19980Sstevel@tonic-gate 0 /* attributes */
19996898Sfb209375 };
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
20020Sstevel@tonic-gate "hid_set_idle: Begin");
20030Sstevel@tonic-gate
20040Sstevel@tonic-gate setup.wIndex = hidp->hid_if_descr.bInterfaceNumber;
20050Sstevel@tonic-gate if (usb_pipe_ctrl_xfer_wait(
20060Sstevel@tonic-gate hidp->hid_default_pipe,
20070Sstevel@tonic-gate &setup,
20080Sstevel@tonic-gate NULL, /* no data to send. */
20090Sstevel@tonic-gate &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
20100Sstevel@tonic-gate
20110Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
20120Sstevel@tonic-gate "Failed while trying to set idle,"
20130Sstevel@tonic-gate "cr = %d, cb_flags = 0x%x\n",
20140Sstevel@tonic-gate completion_reason, cb_flags);
20150Sstevel@tonic-gate }
20160Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
20176898Sfb209375 "hid_set_idle: End");
20180Sstevel@tonic-gate }
20190Sstevel@tonic-gate
20200Sstevel@tonic-gate
20210Sstevel@tonic-gate /*
20220Sstevel@tonic-gate * hid_set_protocol:
20230Sstevel@tonic-gate * Initialize the device to set the preferred protocol
20240Sstevel@tonic-gate */
20250Sstevel@tonic-gate /*ARGSUSED*/
20260Sstevel@tonic-gate static void
hid_set_protocol(hid_state_t * hidp,int protocol)20270Sstevel@tonic-gate hid_set_protocol(hid_state_t *hidp, int protocol)
20280Sstevel@tonic-gate {
20290Sstevel@tonic-gate usb_cr_t completion_reason;
20300Sstevel@tonic-gate usb_cb_flags_t cb_flags;
20310Sstevel@tonic-gate usb_ctrl_setup_t setup;
20320Sstevel@tonic-gate
20330Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
20340Sstevel@tonic-gate "hid_set_protocol(%d): Begin", protocol);
20350Sstevel@tonic-gate
20360Sstevel@tonic-gate /* initialize the setup request */
20370Sstevel@tonic-gate setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
20380Sstevel@tonic-gate USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
20390Sstevel@tonic-gate setup.bRequest = SET_PROTOCOL;
20407492SZhigang.Lu@Sun.COM setup.wValue = (uint16_t)protocol;
20410Sstevel@tonic-gate setup.wIndex = hidp->hid_if_descr.bInterfaceNumber;
20420Sstevel@tonic-gate setup.wLength = 0;
20430Sstevel@tonic-gate setup.attrs = 0;
20440Sstevel@tonic-gate if (usb_pipe_ctrl_xfer_wait(
20450Sstevel@tonic-gate hidp->hid_default_pipe, /* bmRequestType */
20460Sstevel@tonic-gate &setup,
20470Sstevel@tonic-gate NULL, /* no data to send */
20480Sstevel@tonic-gate &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
20490Sstevel@tonic-gate /*
20500Sstevel@tonic-gate * Some devices fail to follow the specification
20510Sstevel@tonic-gate * and instead of STALLing, they continously
20520Sstevel@tonic-gate * NAK the SET_IDLE command. We need to reset
20530Sstevel@tonic-gate * the pipe then, so that ohci doesn't panic.
20540Sstevel@tonic-gate */
20550Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
20560Sstevel@tonic-gate "Failed while trying to set protocol:%d,"
20570Sstevel@tonic-gate "cr = %d cb_flags = 0x%x\n",
20580Sstevel@tonic-gate completion_reason, cb_flags, protocol);
20590Sstevel@tonic-gate }
20600Sstevel@tonic-gate
20610Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
20626898Sfb209375 "hid_set_protocol: End");
20630Sstevel@tonic-gate }
20640Sstevel@tonic-gate
20650Sstevel@tonic-gate
20660Sstevel@tonic-gate /*
20670Sstevel@tonic-gate * hid_detach_cleanup:
20680Sstevel@tonic-gate * called by attach and detach for cleanup.
20690Sstevel@tonic-gate */
20700Sstevel@tonic-gate static void
hid_detach_cleanup(dev_info_t * dip,hid_state_t * hidp)20710Sstevel@tonic-gate hid_detach_cleanup(dev_info_t *dip, hid_state_t *hidp)
20720Sstevel@tonic-gate {
20730Sstevel@tonic-gate int flags = hidp->hid_attach_flags;
20740Sstevel@tonic-gate int rval;
20750Sstevel@tonic-gate hid_power_t *hidpm;
20760Sstevel@tonic-gate
20770Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
20780Sstevel@tonic-gate "hid_detach_cleanup: Begin");
20790Sstevel@tonic-gate
20800Sstevel@tonic-gate if ((hidp->hid_attach_flags & HID_LOCK_INIT) == 0) {
20810Sstevel@tonic-gate
20820Sstevel@tonic-gate goto done;
20830Sstevel@tonic-gate }
20840Sstevel@tonic-gate
20850Sstevel@tonic-gate /*
20860Sstevel@tonic-gate * Disable the event callbacks first, after this point, event
20870Sstevel@tonic-gate * callbacks will never get called. Note we shouldn't hold
20880Sstevel@tonic-gate * mutex while unregistering events because there may be a
20890Sstevel@tonic-gate * competing event callback thread. Event callbacks are done
20900Sstevel@tonic-gate * with ndi mutex held and this can cause a potential deadlock.
20910Sstevel@tonic-gate */
20920Sstevel@tonic-gate usb_unregister_event_cbs(dip, &hid_events);
20930Sstevel@tonic-gate
20940Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate hidpm = hidp->hid_pm;
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
20996898Sfb209375 "hid_detach_cleanup: hidpm=0x%p", (void *)hidpm);
21000Sstevel@tonic-gate
21010Sstevel@tonic-gate if (hidpm && (hidp->hid_dev_state != USB_DEV_DISCONNECTED)) {
21020Sstevel@tonic-gate
21030Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
21040Sstevel@tonic-gate hid_pm_busy_component(hidp);
21050Sstevel@tonic-gate if (hid_is_pm_enabled(dip) == USB_SUCCESS) {
21060Sstevel@tonic-gate
21070Sstevel@tonic-gate if (hidpm->hid_wakeup_enabled) {
21080Sstevel@tonic-gate
21090Sstevel@tonic-gate /* First bring the device to full power */
21100Sstevel@tonic-gate (void) pm_raise_power(dip, 0,
21110Sstevel@tonic-gate USB_DEV_OS_FULL_PWR);
21120Sstevel@tonic-gate
21130Sstevel@tonic-gate /* Disable remote wakeup */
21140Sstevel@tonic-gate rval = usb_handle_remote_wakeup(dip,
21150Sstevel@tonic-gate USB_REMOTE_WAKEUP_DISABLE);
21160Sstevel@tonic-gate
21170Sstevel@tonic-gate if (rval != DDI_SUCCESS) {
21180Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
21190Sstevel@tonic-gate hidp->hid_log_handle,
21200Sstevel@tonic-gate "hid_detach_cleanup: "
21210Sstevel@tonic-gate "disble remote wakeup failed, "
21220Sstevel@tonic-gate "rval= %d", rval);
21230Sstevel@tonic-gate }
21240Sstevel@tonic-gate }
21250Sstevel@tonic-gate
21260Sstevel@tonic-gate (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
21270Sstevel@tonic-gate }
21280Sstevel@tonic-gate hid_pm_idle_component(hidp);
21290Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
21300Sstevel@tonic-gate }
21310Sstevel@tonic-gate
21320Sstevel@tonic-gate if (hidpm) {
21330Sstevel@tonic-gate freemsg(hidpm->hid_pm_pwrup);
21340Sstevel@tonic-gate kmem_free(hidpm, sizeof (hid_power_t));
21350Sstevel@tonic-gate hidp->hid_pm = NULL;
21360Sstevel@tonic-gate }
21370Sstevel@tonic-gate
21380Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
21390Sstevel@tonic-gate
21400Sstevel@tonic-gate if (hidp->hid_report_descr != NULL) {
21410Sstevel@tonic-gate (void) hidparser_free_report_descriptor_handle(
21426898Sfb209375 hidp->hid_report_descr);
21430Sstevel@tonic-gate }
21440Sstevel@tonic-gate
21450Sstevel@tonic-gate if (flags & HID_MINOR_NODES) {
21460Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL);
21470Sstevel@tonic-gate }
21480Sstevel@tonic-gate
21490Sstevel@tonic-gate mutex_destroy(&hidp->hid_mutex);
21500Sstevel@tonic-gate
21510Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
21520Sstevel@tonic-gate "hid_detach_cleanup: End");
21530Sstevel@tonic-gate
21540Sstevel@tonic-gate done:
21550Sstevel@tonic-gate usb_client_detach(dip, hidp->hid_dev_data);
21560Sstevel@tonic-gate usb_free_log_hdl(hidp->hid_log_handle);
21570Sstevel@tonic-gate ddi_soft_state_free(hid_statep, hidp->hid_instance);
21580Sstevel@tonic-gate
21590Sstevel@tonic-gate ddi_prop_remove_all(dip);
21600Sstevel@tonic-gate }
21610Sstevel@tonic-gate
21620Sstevel@tonic-gate
21630Sstevel@tonic-gate /*
21640Sstevel@tonic-gate * hid_start_intr_polling:
21650Sstevel@tonic-gate * Allocate an interrupt request structure, initialize,
21660Sstevel@tonic-gate * and start interrupt transfers.
21670Sstevel@tonic-gate */
21680Sstevel@tonic-gate static int
hid_start_intr_polling(hid_state_t * hidp)21690Sstevel@tonic-gate hid_start_intr_polling(hid_state_t *hidp)
21700Sstevel@tonic-gate {
21710Sstevel@tonic-gate usb_intr_req_t *req;
21720Sstevel@tonic-gate int rval = USB_SUCCESS;
21730Sstevel@tonic-gate
21740Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
21750Sstevel@tonic-gate "hid_start_intr_polling: "
217610153SAaron.Zang@Sun.COM "dev_state=%s internal_str_flag=%d external_str_flag=%d ph=0x%p",
217710153SAaron.Zang@Sun.COM usb_str_dev_state(hidp->hid_dev_state), hidp->hid_internal_flag,
217810153SAaron.Zang@Sun.COM hidp->hid_external_flag, (void *)hidp->hid_interrupt_pipe);
217910153SAaron.Zang@Sun.COM
218010153SAaron.Zang@Sun.COM if (HID_IS_OPEN(hidp) && (hidp->hid_interrupt_pipe != NULL)) {
21810Sstevel@tonic-gate /*
21820Sstevel@tonic-gate * initialize interrupt pipe request structure
21830Sstevel@tonic-gate */
21840Sstevel@tonic-gate req = usb_alloc_intr_req(hidp->hid_dip, 0, USB_FLAGS_SLEEP);
21850Sstevel@tonic-gate req->intr_client_private = (usb_opaque_t)hidp;
21860Sstevel@tonic-gate req->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
21876898Sfb209375 USB_ATTRS_AUTOCLEARING;
21880Sstevel@tonic-gate req->intr_len = hidp->hid_packet_size;
21890Sstevel@tonic-gate req->intr_cb = hid_interrupt_pipe_callback;
21900Sstevel@tonic-gate req->intr_exc_cb = hid_interrupt_pipe_exception_callback;
21910Sstevel@tonic-gate
21920Sstevel@tonic-gate /*
21930Sstevel@tonic-gate * Start polling on the interrupt pipe.
21940Sstevel@tonic-gate */
21950Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
21960Sstevel@tonic-gate
21970Sstevel@tonic-gate if ((rval = usb_pipe_intr_xfer(hidp->hid_interrupt_pipe, req,
21980Sstevel@tonic-gate USB_FLAGS_SLEEP)) != USB_SUCCESS) {
21990Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM, hidp->hid_log_handle,
22000Sstevel@tonic-gate "hid_start_intr_polling failed: rval = %d",
22010Sstevel@tonic-gate rval);
22020Sstevel@tonic-gate usb_free_intr_req(req);
22030Sstevel@tonic-gate }
22040Sstevel@tonic-gate
22050Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
22060Sstevel@tonic-gate }
22070Sstevel@tonic-gate
22080Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
22090Sstevel@tonic-gate "hid_start_intr_polling: done, rval = %d", rval);
22100Sstevel@tonic-gate
22110Sstevel@tonic-gate return (rval);
22120Sstevel@tonic-gate }
22130Sstevel@tonic-gate
22140Sstevel@tonic-gate
22150Sstevel@tonic-gate /*
22160Sstevel@tonic-gate * hid_close_intr_pipe:
22170Sstevel@tonic-gate * close the interrupt pipe after draining all callbacks
22180Sstevel@tonic-gate */
22190Sstevel@tonic-gate static void
hid_close_intr_pipe(hid_state_t * hidp)22200Sstevel@tonic-gate hid_close_intr_pipe(hid_state_t *hidp)
22210Sstevel@tonic-gate {
22220Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
22230Sstevel@tonic-gate "hid_close_intr_pipe: Begin");
22240Sstevel@tonic-gate
22250Sstevel@tonic-gate if (hidp->hid_interrupt_pipe) {
22260Sstevel@tonic-gate /*
22270Sstevel@tonic-gate * Close the interrupt pipe
22280Sstevel@tonic-gate */
22290Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
22300Sstevel@tonic-gate usb_pipe_close(hidp->hid_dip, hidp->hid_interrupt_pipe,
22310Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL);
22320Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
22330Sstevel@tonic-gate hidp->hid_interrupt_pipe = NULL;
22340Sstevel@tonic-gate }
22350Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
22360Sstevel@tonic-gate "hid_close_intr_pipe: End");
22370Sstevel@tonic-gate }
22380Sstevel@tonic-gate
22390Sstevel@tonic-gate
22400Sstevel@tonic-gate /*
22410Sstevel@tonic-gate * hid_mctl_receive:
22420Sstevel@tonic-gate * Handle M_CTL messages from upper stream. If
22430Sstevel@tonic-gate * we don't understand the command, free message.
22440Sstevel@tonic-gate */
22450Sstevel@tonic-gate static int
hid_mctl_receive(register queue_t * q,register mblk_t * mp)22460Sstevel@tonic-gate hid_mctl_receive(register queue_t *q, register mblk_t *mp)
22470Sstevel@tonic-gate {
224810153SAaron.Zang@Sun.COM hid_state_t *hidp = (hid_state_t *)q->q_ptr;
22490Sstevel@tonic-gate struct iocblk *iocp;
22500Sstevel@tonic-gate int error = HID_FAILURE;
22510Sstevel@tonic-gate uchar_t request_type;
22520Sstevel@tonic-gate hid_req_t *hid_req_data = NULL;
22530Sstevel@tonic-gate hid_polled_input_callback_t hid_polled_input;
2254918Sqz150045 hid_vid_pid_t hid_vid_pid;
22550Sstevel@tonic-gate
22560Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
22570Sstevel@tonic-gate "hid_mctl_receive");
22580Sstevel@tonic-gate
22590Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate switch (iocp->ioc_cmd) {
22620Sstevel@tonic-gate case HID_SET_REPORT:
22630Sstevel@tonic-gate /* FALLTHRU */
22640Sstevel@tonic-gate case HID_SET_IDLE:
22650Sstevel@tonic-gate /* FALLTHRU */
22660Sstevel@tonic-gate case HID_SET_PROTOCOL:
22670Sstevel@tonic-gate request_type = USB_DEV_REQ_HOST_TO_DEV |
22680Sstevel@tonic-gate USB_DEV_REQ_RCPT_IF | USB_DEV_REQ_TYPE_CLASS;
22690Sstevel@tonic-gate
22700Sstevel@tonic-gate break;
22710Sstevel@tonic-gate case HID_GET_REPORT:
22720Sstevel@tonic-gate /* FALLTHRU */
22730Sstevel@tonic-gate case HID_GET_IDLE:
22740Sstevel@tonic-gate /* FALLTHRU */
22750Sstevel@tonic-gate case HID_GET_PROTOCOL:
22760Sstevel@tonic-gate request_type = USB_DEV_REQ_DEV_TO_HOST |
22770Sstevel@tonic-gate USB_DEV_REQ_RCPT_IF | USB_DEV_REQ_TYPE_CLASS;
22780Sstevel@tonic-gate
22790Sstevel@tonic-gate break;
22800Sstevel@tonic-gate case HID_GET_PARSER_HANDLE:
22810Sstevel@tonic-gate if (canputnext(RD(q))) {
22820Sstevel@tonic-gate freemsg(mp->b_cont);
22830Sstevel@tonic-gate mp->b_cont = hid_data2mblk(
22840Sstevel@tonic-gate (uchar_t *)&hidp->hid_report_descr,
22850Sstevel@tonic-gate sizeof (hidp->hid_report_descr));
22860Sstevel@tonic-gate if (mp->b_cont == NULL) {
22870Sstevel@tonic-gate /*
22880Sstevel@tonic-gate * can't allocate mblk, indicate
22890Sstevel@tonic-gate * that nothing is returned
22900Sstevel@tonic-gate */
22910Sstevel@tonic-gate iocp->ioc_count = 0;
22920Sstevel@tonic-gate } else {
22930Sstevel@tonic-gate iocp->ioc_count =
22940Sstevel@tonic-gate sizeof (hidp->hid_report_descr);
22950Sstevel@tonic-gate }
22960Sstevel@tonic-gate qreply(q, mp);
22970Sstevel@tonic-gate
22980Sstevel@tonic-gate return (HID_SUCCESS);
22990Sstevel@tonic-gate } else {
23000Sstevel@tonic-gate
23010Sstevel@tonic-gate /* retry */
23020Sstevel@tonic-gate return (HID_ENQUEUE);
23030Sstevel@tonic-gate }
2304918Sqz150045 case HID_GET_VID_PID:
2305918Sqz150045 if (canputnext(RD(q))) {
2306918Sqz150045 freemsg(mp->b_cont);
2307918Sqz150045
2308918Sqz150045 hid_vid_pid.VendorId =
23096898Sfb209375 hidp->hid_dev_descr->idVendor;
2310918Sqz150045 hid_vid_pid.ProductId =
23116898Sfb209375 hidp->hid_dev_descr->idProduct;
2312918Sqz150045
2313918Sqz150045 mp->b_cont = hid_data2mblk(
2314918Sqz150045 (uchar_t *)&hid_vid_pid, sizeof (hid_vid_pid_t));
2315918Sqz150045 if (mp->b_cont == NULL) {
2316918Sqz150045 /*
2317918Sqz150045 * can't allocate mblk, indicate that nothing
2318918Sqz150045 * is being returned.
2319918Sqz150045 */
2320918Sqz150045 iocp->ioc_count = 0;
2321918Sqz150045 } else {
2322918Sqz150045 iocp->ioc_count =
2323918Sqz150045 sizeof (hid_vid_pid_t);
2324918Sqz150045 }
2325918Sqz150045 qreply(q, mp);
2326918Sqz150045
2327918Sqz150045 return (HID_SUCCESS);
2328918Sqz150045 } else {
2329918Sqz150045
2330918Sqz150045 /* retry */
2331918Sqz150045 return (HID_ENQUEUE);
2332918Sqz150045 }
23330Sstevel@tonic-gate case HID_OPEN_POLLED_INPUT:
23340Sstevel@tonic-gate if (canputnext(RD(q))) {
23350Sstevel@tonic-gate freemsg(mp->b_cont);
23360Sstevel@tonic-gate
23370Sstevel@tonic-gate /* Initialize the structure */
23380Sstevel@tonic-gate hid_polled_input.hid_polled_version =
23396898Sfb209375 HID_POLLED_INPUT_V0;
23400Sstevel@tonic-gate hid_polled_input.hid_polled_read = hid_polled_read;
23410Sstevel@tonic-gate hid_polled_input.hid_polled_input_enter =
23426898Sfb209375 hid_polled_input_enter;
23430Sstevel@tonic-gate hid_polled_input.hid_polled_input_exit =
23446898Sfb209375 hid_polled_input_exit;
23450Sstevel@tonic-gate hid_polled_input.hid_polled_input_handle =
23466898Sfb209375 (hid_polled_handle_t)hidp;
23470Sstevel@tonic-gate
23480Sstevel@tonic-gate mp->b_cont = hid_data2mblk(
23490Sstevel@tonic-gate (uchar_t *)&hid_polled_input,
23500Sstevel@tonic-gate sizeof (hid_polled_input_callback_t));
23510Sstevel@tonic-gate if (mp->b_cont == NULL) {
23520Sstevel@tonic-gate /*
23530Sstevel@tonic-gate * can't allocate mblk, indicate that nothing
23540Sstevel@tonic-gate * is being returned.
23550Sstevel@tonic-gate */
23560Sstevel@tonic-gate iocp->ioc_count = 0;
23570Sstevel@tonic-gate } else {
23580Sstevel@tonic-gate /* Call down into USBA */
23590Sstevel@tonic-gate (void) hid_polled_input_init(hidp);
23600Sstevel@tonic-gate
23610Sstevel@tonic-gate iocp->ioc_count =
23620Sstevel@tonic-gate sizeof (hid_polled_input_callback_t);
23630Sstevel@tonic-gate }
23640Sstevel@tonic-gate qreply(q, mp);
23650Sstevel@tonic-gate
23660Sstevel@tonic-gate return (HID_SUCCESS);
23670Sstevel@tonic-gate } else {
23680Sstevel@tonic-gate
23690Sstevel@tonic-gate /* retry */
23700Sstevel@tonic-gate return (HID_ENQUEUE);
23710Sstevel@tonic-gate }
23720Sstevel@tonic-gate case HID_CLOSE_POLLED_INPUT:
23730Sstevel@tonic-gate /* Call down into USBA */
23740Sstevel@tonic-gate (void) hid_polled_input_fini(hidp);
23750Sstevel@tonic-gate
23760Sstevel@tonic-gate iocp->ioc_count = 0;
23770Sstevel@tonic-gate qreply(q, mp);
23780Sstevel@tonic-gate
23790Sstevel@tonic-gate return (HID_SUCCESS);
23800Sstevel@tonic-gate default:
23810Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
23820Sstevel@tonic-gate
23830Sstevel@tonic-gate return (HID_FAILURE);
23840Sstevel@tonic-gate }
23850Sstevel@tonic-gate
23860Sstevel@tonic-gate /*
23870Sstevel@tonic-gate * These (device executable) commands require a hid_req_t.
23880Sstevel@tonic-gate * Make sure one is present
23890Sstevel@tonic-gate */
23900Sstevel@tonic-gate if (mp->b_cont == NULL) {
23910Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
23920Sstevel@tonic-gate
23930Sstevel@tonic-gate return (error);
23940Sstevel@tonic-gate } else {
23950Sstevel@tonic-gate hid_req_data = (hid_req_t *)mp->b_cont->b_rptr;
23960Sstevel@tonic-gate if ((iocp->ioc_cmd == HID_SET_REPORT) &&
23972278Sgc161489 (hid_req_data->hid_req_wLength == 0)) {
23980Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
23990Sstevel@tonic-gate
24000Sstevel@tonic-gate return (error);
24010Sstevel@tonic-gate }
24020Sstevel@tonic-gate }
24030Sstevel@tonic-gate
24040Sstevel@tonic-gate /*
24050Sstevel@tonic-gate * Check is version no. is correct. This
24060Sstevel@tonic-gate * is coming from the user
24070Sstevel@tonic-gate */
24080Sstevel@tonic-gate if (hid_req_data->hid_req_version_no != HID_VERSION_V_0) {
24090Sstevel@tonic-gate hid_qreply_merror(q, mp, EINVAL);
24100Sstevel@tonic-gate
24110Sstevel@tonic-gate return (error);
24120Sstevel@tonic-gate }
24130Sstevel@tonic-gate
24140Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
24150Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
24160Sstevel@tonic-gate "hid_mctl_receive: dev_state=%s",
24170Sstevel@tonic-gate usb_str_dev_state(hidp->hid_dev_state));
24180Sstevel@tonic-gate
24190Sstevel@tonic-gate switch (hidp->hid_dev_state) {
24200Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
24210Sstevel@tonic-gate /*
24220Sstevel@tonic-gate * get the device full powered. We get a callback
24230Sstevel@tonic-gate * which enables the WQ and kicks off IO
24240Sstevel@tonic-gate */
24250Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_HID_POWER_CHANGE;
24260Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
24270Sstevel@tonic-gate if (usb_req_raise_power(hidp->hid_dip, 0,
24280Sstevel@tonic-gate USB_DEV_OS_FULL_PWR, hid_power_change_callback,
24290Sstevel@tonic-gate hidp, 0) != USB_SUCCESS) {
24300Sstevel@tonic-gate /* we retry raising power in wsrv */
24310Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
24320Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_PWRED_DOWN;
24330Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
24340Sstevel@tonic-gate }
24350Sstevel@tonic-gate error = HID_ENQUEUE;
24360Sstevel@tonic-gate
24370Sstevel@tonic-gate break;
24380Sstevel@tonic-gate case USB_DEV_HID_POWER_CHANGE:
24390Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
24400Sstevel@tonic-gate error = HID_ENQUEUE;
24410Sstevel@tonic-gate
24420Sstevel@tonic-gate break;
24430Sstevel@tonic-gate case USB_DEV_ONLINE:
244410153SAaron.Zang@Sun.COM if (HID_STREAMS_FLAG(q, hidp) != HID_STREAMS_DISMANTLING) {
24450Sstevel@tonic-gate /* Send a message down */
24460Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
24479432SPengcheng.Chen@Sun.COM error = hid_mctl_execute_cmd(q, request_type,
24480Sstevel@tonic-gate hid_req_data, mp);
24490Sstevel@tonic-gate if (error == HID_FAILURE) {
24500Sstevel@tonic-gate hid_qreply_merror(q, mp, EIO);
24510Sstevel@tonic-gate }
24520Sstevel@tonic-gate } else {
24530Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
24540Sstevel@tonic-gate hid_qreply_merror(q, mp, EIO);
24550Sstevel@tonic-gate }
24560Sstevel@tonic-gate
24570Sstevel@tonic-gate break;
24580Sstevel@tonic-gate default:
24590Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
24600Sstevel@tonic-gate hid_qreply_merror(q, mp, EIO);
24610Sstevel@tonic-gate
24620Sstevel@tonic-gate break;
24630Sstevel@tonic-gate }
24640Sstevel@tonic-gate
24650Sstevel@tonic-gate return (error);
24660Sstevel@tonic-gate }
24670Sstevel@tonic-gate
24680Sstevel@tonic-gate
24690Sstevel@tonic-gate /*
24700Sstevel@tonic-gate * hid_mctl_execute_cmd:
24710Sstevel@tonic-gate * Send the command to the device.
24720Sstevel@tonic-gate */
24730Sstevel@tonic-gate static int
hid_mctl_execute_cmd(queue_t * q,int request_type,hid_req_t * hid_req_data,mblk_t * mp)24749432SPengcheng.Chen@Sun.COM hid_mctl_execute_cmd(queue_t *q, int request_type, hid_req_t *hid_req_data,
24759432SPengcheng.Chen@Sun.COM mblk_t *mp)
24760Sstevel@tonic-gate {
24770Sstevel@tonic-gate int request_index;
24780Sstevel@tonic-gate struct iocblk *iocp;
24790Sstevel@tonic-gate hid_default_pipe_arg_t *def_pipe_arg;
248010153SAaron.Zang@Sun.COM hid_state_t *hidp = (hid_state_t *)q->q_ptr;
24810Sstevel@tonic-gate
24820Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
24830Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
24846898Sfb209375 "hid_mctl_execute_cmd: iocp=0x%p", (void *)iocp);
24850Sstevel@tonic-gate
24860Sstevel@tonic-gate request_index = hidp->hid_if_descr.bInterfaceNumber;
24870Sstevel@tonic-gate
24880Sstevel@tonic-gate /*
24890Sstevel@tonic-gate * Set up the argument to be passed back to hid
24900Sstevel@tonic-gate * when the asynchronous control callback is
24910Sstevel@tonic-gate * executed.
24920Sstevel@tonic-gate */
24930Sstevel@tonic-gate def_pipe_arg = kmem_zalloc(sizeof (hid_default_pipe_arg_t), 0);
24940Sstevel@tonic-gate
24950Sstevel@tonic-gate if (def_pipe_arg == NULL) {
24960Sstevel@tonic-gate
24970Sstevel@tonic-gate return (HID_FAILURE);
24980Sstevel@tonic-gate }
24990Sstevel@tonic-gate
25009432SPengcheng.Chen@Sun.COM def_pipe_arg->hid_default_pipe_arg_queue = q;
25010Sstevel@tonic-gate def_pipe_arg->hid_default_pipe_arg_mctlmsg.ioc_cmd = iocp->ioc_cmd;
25020Sstevel@tonic-gate def_pipe_arg->hid_default_pipe_arg_mctlmsg.ioc_count = 0;
25030Sstevel@tonic-gate def_pipe_arg->hid_default_pipe_arg_mblk = mp;
25040Sstevel@tonic-gate
25050Sstevel@tonic-gate /*
25060Sstevel@tonic-gate * Send the command down to USBA through default
25070Sstevel@tonic-gate * pipe.
25080Sstevel@tonic-gate */
25099432SPengcheng.Chen@Sun.COM if (hid_send_async_ctrl_request(def_pipe_arg, hid_req_data,
25109432SPengcheng.Chen@Sun.COM request_type, iocp->ioc_cmd, request_index) != USB_SUCCESS) {
25110Sstevel@tonic-gate
25120Sstevel@tonic-gate kmem_free(def_pipe_arg, sizeof (hid_default_pipe_arg_t));
25130Sstevel@tonic-gate
25140Sstevel@tonic-gate return (HID_FAILURE);
25150Sstevel@tonic-gate }
25160Sstevel@tonic-gate
25170Sstevel@tonic-gate return (HID_INPROGRESS);
25180Sstevel@tonic-gate }
25190Sstevel@tonic-gate
25200Sstevel@tonic-gate
25210Sstevel@tonic-gate /*
25220Sstevel@tonic-gate * hid_send_async_ctrl_request:
25230Sstevel@tonic-gate * Send an asynchronous control request to USBA. Since hid is a STREAMS
25240Sstevel@tonic-gate * driver, it is not allowed to wait in its entry points except for the
25250Sstevel@tonic-gate * open and close entry points. Therefore, hid must use the asynchronous
25260Sstevel@tonic-gate * USBA calls.
25270Sstevel@tonic-gate */
25280Sstevel@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)25299432SPengcheng.Chen@Sun.COM hid_send_async_ctrl_request(hid_default_pipe_arg_t *hid_default_pipe_arg,
25309432SPengcheng.Chen@Sun.COM hid_req_t *hid_request,
25310Sstevel@tonic-gate uchar_t request_type, int request_request,
25329432SPengcheng.Chen@Sun.COM ushort_t request_index)
25330Sstevel@tonic-gate {
25349432SPengcheng.Chen@Sun.COM queue_t *q = hid_default_pipe_arg->hid_default_pipe_arg_queue;
253510153SAaron.Zang@Sun.COM hid_state_t *hidp = (hid_state_t *)q->q_ptr;
25360Sstevel@tonic-gate usb_ctrl_req_t *ctrl_req;
25370Sstevel@tonic-gate int rval;
25380Sstevel@tonic-gate size_t length = 0;
25390Sstevel@tonic-gate
25400Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
25410Sstevel@tonic-gate "hid_send_async_ctrl_request: "
25420Sstevel@tonic-gate "rq_type=%d rq_rq=%d index=%d",
25430Sstevel@tonic-gate request_type, request_request, request_index);
25440Sstevel@tonic-gate
25450Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
25460Sstevel@tonic-gate hidp->hid_default_pipe_req++;
25470Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
25480Sstevel@tonic-gate
25490Sstevel@tonic-gate /*
25500Sstevel@tonic-gate * Note that ctrl_req->ctrl_data should be allocated by usba
25510Sstevel@tonic-gate * only for IN requests. OUT request(e.g SET_REPORT) can have a
25520Sstevel@tonic-gate * non-zero wLength value but ctrl_data would be allocated by
25530Sstevel@tonic-gate * client for them.
25540Sstevel@tonic-gate */
25552278Sgc161489 if (hid_request->hid_req_wLength >= MAX_REPORT_DATA) {
25562278Sgc161489 USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
25572278Sgc161489 "hid_req_wLength is exceeded");
25582278Sgc161489 return (USB_FAILURE);
25592278Sgc161489 }
25602278Sgc161489 if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_DEV_TO_HOST) {
25612278Sgc161489 length = hid_request->hid_req_wLength;
25620Sstevel@tonic-gate }
25630Sstevel@tonic-gate
25640Sstevel@tonic-gate if ((ctrl_req = usb_alloc_ctrl_req(hidp->hid_dip, length, 0)) == NULL) {
25650Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
25660Sstevel@tonic-gate "unable to alloc ctrl req. async trans failed");
25670Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
25680Sstevel@tonic-gate hidp->hid_default_pipe_req--;
25690Sstevel@tonic-gate ASSERT(hidp->hid_default_pipe_req >= 0);
25700Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
25710Sstevel@tonic-gate
25720Sstevel@tonic-gate return (USB_FAILURE);
25730Sstevel@tonic-gate }
25740Sstevel@tonic-gate
25752278Sgc161489 if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_HOST_TO_DEV) {
25760Sstevel@tonic-gate ASSERT((length == 0) && (ctrl_req->ctrl_data == NULL));
25770Sstevel@tonic-gate }
25780Sstevel@tonic-gate
25790Sstevel@tonic-gate ctrl_req->ctrl_bmRequestType = request_type;
25800Sstevel@tonic-gate ctrl_req->ctrl_bRequest = (uint8_t)request_request;
25810Sstevel@tonic-gate ctrl_req->ctrl_wValue = hid_request->hid_req_wValue;
25820Sstevel@tonic-gate ctrl_req->ctrl_wIndex = request_index;
25830Sstevel@tonic-gate ctrl_req->ctrl_wLength = hid_request->hid_req_wLength;
25842278Sgc161489 /* host to device: create a msg from hid_req_data */
25852278Sgc161489 if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_HOST_TO_DEV) {
25862278Sgc161489 mblk_t *pblk = allocb(hid_request->hid_req_wLength, BPRI_HI);
25872278Sgc161489 if (pblk == NULL) {
25882278Sgc161489 usb_free_ctrl_req(ctrl_req);
25892278Sgc161489 return (USB_FAILURE);
25902278Sgc161489 }
25912278Sgc161489 bcopy(hid_request->hid_req_data, pblk->b_wptr,
25926898Sfb209375 hid_request->hid_req_wLength);
25932278Sgc161489 pblk->b_wptr += hid_request->hid_req_wLength;
25942278Sgc161489 ctrl_req->ctrl_data = pblk;
25952278Sgc161489 }
25960Sstevel@tonic-gate ctrl_req->ctrl_attributes = USB_ATTRS_AUTOCLEARING;
25970Sstevel@tonic-gate ctrl_req->ctrl_client_private = (usb_opaque_t)hid_default_pipe_arg;
25980Sstevel@tonic-gate ctrl_req->ctrl_cb = hid_default_pipe_callback;
25990Sstevel@tonic-gate ctrl_req->ctrl_exc_cb = hid_default_pipe_exception_callback;
26000Sstevel@tonic-gate
26010Sstevel@tonic-gate if ((rval = usb_pipe_ctrl_xfer(hidp->hid_default_pipe,
26020Sstevel@tonic-gate ctrl_req, 0)) != USB_SUCCESS) {
26030Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
26040Sstevel@tonic-gate hidp->hid_default_pipe_req--;
26050Sstevel@tonic-gate ASSERT(hidp->hid_default_pipe_req >= 0);
26060Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
26070Sstevel@tonic-gate
26080Sstevel@tonic-gate usb_free_ctrl_req(ctrl_req);
26090Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
26100Sstevel@tonic-gate "usb_pipe_ctrl_xfer() failed. rval = %d", rval);
26110Sstevel@tonic-gate
26120Sstevel@tonic-gate return (USB_FAILURE);
26130Sstevel@tonic-gate }
26140Sstevel@tonic-gate
26150Sstevel@tonic-gate return (USB_SUCCESS);
26160Sstevel@tonic-gate }
26170Sstevel@tonic-gate
26180Sstevel@tonic-gate /*
26190Sstevel@tonic-gate * hid_create_pm_components:
26200Sstevel@tonic-gate * Create the pm components required for power management.
26210Sstevel@tonic-gate * For keyboard/mouse, the components is created only if the device
26220Sstevel@tonic-gate * supports a remote wakeup.
26230Sstevel@tonic-gate * For other hid devices they are created unconditionally.
26240Sstevel@tonic-gate */
26250Sstevel@tonic-gate static void
hid_create_pm_components(dev_info_t * dip,hid_state_t * hidp)26260Sstevel@tonic-gate hid_create_pm_components(dev_info_t *dip, hid_state_t *hidp)
26270Sstevel@tonic-gate {
26280Sstevel@tonic-gate hid_power_t *hidpm;
26290Sstevel@tonic-gate uint_t pwr_states;
26300Sstevel@tonic-gate
26310Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
26320Sstevel@tonic-gate "hid_create_pm_components: Begin");
26330Sstevel@tonic-gate
26340Sstevel@tonic-gate /* Allocate the state structure */
26350Sstevel@tonic-gate hidpm = kmem_zalloc(sizeof (hid_power_t), KM_SLEEP);
26360Sstevel@tonic-gate hidp->hid_pm = hidpm;
26370Sstevel@tonic-gate hidpm->hid_state = hidp;
26380Sstevel@tonic-gate hidpm->hid_raise_power = B_FALSE;
26390Sstevel@tonic-gate hidpm->hid_pm_capabilities = 0;
26400Sstevel@tonic-gate hidpm->hid_current_power = USB_DEV_OS_FULL_PWR;
26410Sstevel@tonic-gate
26420Sstevel@tonic-gate switch (hidp->hid_if_descr.bInterfaceProtocol) {
26430Sstevel@tonic-gate case KEYBOARD_PROTOCOL:
26440Sstevel@tonic-gate case MOUSE_PROTOCOL:
26450Sstevel@tonic-gate hidpm->hid_pm_strategy = HID_PM_ACTIVITY;
26460Sstevel@tonic-gate if ((hid_is_pm_enabled(dip) == USB_SUCCESS) &&
26470Sstevel@tonic-gate (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
26480Sstevel@tonic-gate USB_SUCCESS)) {
26490Sstevel@tonic-gate
26500Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_PM, hidp->hid_log_handle,
26510Sstevel@tonic-gate "hid_create_pm_components: Remote Wakeup Enabled");
26520Sstevel@tonic-gate
26530Sstevel@tonic-gate if (usb_create_pm_components(dip, &pwr_states) ==
26540Sstevel@tonic-gate USB_SUCCESS) {
26550Sstevel@tonic-gate hidpm->hid_wakeup_enabled = 1;
26560Sstevel@tonic-gate hidpm->hid_pwr_states = (uint8_t)pwr_states;
26570Sstevel@tonic-gate }
26580Sstevel@tonic-gate }
26590Sstevel@tonic-gate
26600Sstevel@tonic-gate break;
26610Sstevel@tonic-gate default:
26620Sstevel@tonic-gate hidpm->hid_pm_strategy = HID_PM_OPEN_CLOSE;
26630Sstevel@tonic-gate if ((hid_is_pm_enabled(dip) == USB_SUCCESS) &&
26640Sstevel@tonic-gate (usb_create_pm_components(dip, &pwr_states) ==
26650Sstevel@tonic-gate USB_SUCCESS)) {
26660Sstevel@tonic-gate hidpm->hid_wakeup_enabled = 0;
26670Sstevel@tonic-gate hidpm->hid_pwr_states = (uint8_t)pwr_states;
26680Sstevel@tonic-gate }
26690Sstevel@tonic-gate
26700Sstevel@tonic-gate break;
26710Sstevel@tonic-gate }
26720Sstevel@tonic-gate
26730Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
26746898Sfb209375 "hid_create_pm_components: END");
26750Sstevel@tonic-gate }
26760Sstevel@tonic-gate
26770Sstevel@tonic-gate
26780Sstevel@tonic-gate /*
26790Sstevel@tonic-gate * hid_is_pm_enabled
26800Sstevel@tonic-gate * Check if the device is pm enabled. Always enable
26810Sstevel@tonic-gate * pm on the new SUN mouse
26820Sstevel@tonic-gate */
26830Sstevel@tonic-gate static int
hid_is_pm_enabled(dev_info_t * dip)26840Sstevel@tonic-gate hid_is_pm_enabled(dev_info_t *dip)
26850Sstevel@tonic-gate {
26860Sstevel@tonic-gate hid_state_t *hidp = ddi_get_soft_state(hid_statep,
26876898Sfb209375 ddi_get_instance(dip));
26880Sstevel@tonic-gate
26890Sstevel@tonic-gate if (strcmp(ddi_node_name(dip), "mouse") == 0) {
2690880Sfrits /* check for overrides first */
2691880Sfrits if (hid_pm_mouse ||
2692880Sfrits (ddi_prop_exists(DDI_DEV_T_ANY, dip,
2693880Sfrits (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2694880Sfrits "hid-mouse-pm-enable") == 1)) {
2695880Sfrits
2696880Sfrits return (USB_SUCCESS);
2697880Sfrits }
2698880Sfrits
26990Sstevel@tonic-gate /*
2700880Sfrits * Always enable PM for 1.05 or greater SUN mouse
27010Sstevel@tonic-gate * hidp->hid_dev_descr won't be NULL.
27020Sstevel@tonic-gate */
2703880Sfrits if ((hidp->hid_dev_descr->idVendor ==
27040Sstevel@tonic-gate HID_SUN_MOUSE_VENDOR_ID) &&
27050Sstevel@tonic-gate (hidp->hid_dev_descr->idProduct ==
27060Sstevel@tonic-gate HID_SUN_MOUSE_PROD_ID) &&
27070Sstevel@tonic-gate (hidp->hid_dev_descr->bcdDevice >=
2708880Sfrits HID_SUN_MOUSE_BCDDEVICE)) {
27090Sstevel@tonic-gate
27100Sstevel@tonic-gate return (USB_SUCCESS);
27110Sstevel@tonic-gate }
27120Sstevel@tonic-gate } else {
27130Sstevel@tonic-gate
27140Sstevel@tonic-gate return (USB_SUCCESS);
27150Sstevel@tonic-gate }
27160Sstevel@tonic-gate
27170Sstevel@tonic-gate return (USB_FAILURE);
27180Sstevel@tonic-gate }
27190Sstevel@tonic-gate
27200Sstevel@tonic-gate
27210Sstevel@tonic-gate /*
27220Sstevel@tonic-gate * hid_save_device_state
27230Sstevel@tonic-gate * Save the current device/driver state.
27240Sstevel@tonic-gate */
27250Sstevel@tonic-gate static void
hid_save_device_state(hid_state_t * hidp)27260Sstevel@tonic-gate hid_save_device_state(hid_state_t *hidp)
27270Sstevel@tonic-gate {
27280Sstevel@tonic-gate struct iocblk *mctlmsg;
27290Sstevel@tonic-gate mblk_t *mp;
27300Sstevel@tonic-gate queue_t *q;
27310Sstevel@tonic-gate
27320Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
27330Sstevel@tonic-gate "hid_save_device_state");
27340Sstevel@tonic-gate
273510153SAaron.Zang@Sun.COM if (!(HID_IS_OPEN(hidp)))
273610153SAaron.Zang@Sun.COM return;
273710153SAaron.Zang@Sun.COM
273810153SAaron.Zang@Sun.COM if (hidp->hid_internal_flag == HID_STREAMS_OPEN) {
27390Sstevel@tonic-gate /*
27409432SPengcheng.Chen@Sun.COM * Send MCTLs up indicating that the device
27419432SPengcheng.Chen@Sun.COM * will loose its state
27420Sstevel@tonic-gate */
274310153SAaron.Zang@Sun.COM q = hidp->hid_internal_rq;
274410153SAaron.Zang@Sun.COM
274510153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
274610153SAaron.Zang@Sun.COM if (canputnext(q)) {
274710153SAaron.Zang@Sun.COM mp = allocb(sizeof (struct iocblk), BPRI_HI);
274810153SAaron.Zang@Sun.COM if (mp != NULL) {
274910153SAaron.Zang@Sun.COM mp->b_datap->db_type = M_CTL;
275010153SAaron.Zang@Sun.COM mctlmsg = (struct iocblk *)
275110153SAaron.Zang@Sun.COM mp->b_datap->db_base;
275210153SAaron.Zang@Sun.COM mctlmsg->ioc_cmd = HID_DISCONNECT_EVENT;
275310153SAaron.Zang@Sun.COM mctlmsg->ioc_count = 0;
275410153SAaron.Zang@Sun.COM putnext(q, mp);
27559432SPengcheng.Chen@Sun.COM }
27569432SPengcheng.Chen@Sun.COM }
27570Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
27580Sstevel@tonic-gate }
275910153SAaron.Zang@Sun.COM
276010153SAaron.Zang@Sun.COM if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
276110153SAaron.Zang@Sun.COM /*
276210153SAaron.Zang@Sun.COM * Send MCTLs up indicating that the device
276310153SAaron.Zang@Sun.COM * will loose its state
276410153SAaron.Zang@Sun.COM */
276510153SAaron.Zang@Sun.COM q = hidp->hid_external_rq;
276610153SAaron.Zang@Sun.COM
276710153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
276810153SAaron.Zang@Sun.COM if (canputnext(q)) {
276910153SAaron.Zang@Sun.COM mp = allocb(sizeof (struct iocblk), BPRI_HI);
277010153SAaron.Zang@Sun.COM if (mp != NULL) {
277110153SAaron.Zang@Sun.COM mp->b_datap->db_type = M_CTL;
277210153SAaron.Zang@Sun.COM mctlmsg = (struct iocblk *)
277310153SAaron.Zang@Sun.COM mp->b_datap->db_base;
277410153SAaron.Zang@Sun.COM mctlmsg->ioc_cmd = HID_DISCONNECT_EVENT;
277510153SAaron.Zang@Sun.COM mctlmsg->ioc_count = 0;
277610153SAaron.Zang@Sun.COM putnext(q, mp);
277710153SAaron.Zang@Sun.COM }
277810153SAaron.Zang@Sun.COM }
277910153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
278010153SAaron.Zang@Sun.COM }
278110153SAaron.Zang@Sun.COM
278210153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
278310153SAaron.Zang@Sun.COM /* stop polling on the intr pipe */
278410153SAaron.Zang@Sun.COM usb_pipe_stop_intr_polling(hidp->hid_interrupt_pipe, USB_FLAGS_SLEEP);
278510153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
27860Sstevel@tonic-gate }
27870Sstevel@tonic-gate
27880Sstevel@tonic-gate
27890Sstevel@tonic-gate /*
27900Sstevel@tonic-gate * hid_restore_device_state:
27910Sstevel@tonic-gate * Set original configuration of the device.
27920Sstevel@tonic-gate * Reopen intr pipe.
27930Sstevel@tonic-gate * Enable wrq - this starts new transactions on the control pipe.
27940Sstevel@tonic-gate */
27950Sstevel@tonic-gate static void
hid_restore_device_state(dev_info_t * dip,hid_state_t * hidp)27960Sstevel@tonic-gate hid_restore_device_state(dev_info_t *dip, hid_state_t *hidp)
27970Sstevel@tonic-gate {
27980Sstevel@tonic-gate int rval;
27990Sstevel@tonic-gate hid_power_t *hidpm;
28000Sstevel@tonic-gate struct iocblk *mctlmsg;
28010Sstevel@tonic-gate mblk_t *mp;
280210153SAaron.Zang@Sun.COM queue_t *q;
28030Sstevel@tonic-gate
28040Sstevel@tonic-gate hid_pm_busy_component(hidp);
28050Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
28060Sstevel@tonic-gate
28070Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
28080Sstevel@tonic-gate "hid_restore_device_state: %s",
28090Sstevel@tonic-gate usb_str_dev_state(hidp->hid_dev_state));
28100Sstevel@tonic-gate
28110Sstevel@tonic-gate hidpm = hidp->hid_pm;
28120Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
28130Sstevel@tonic-gate
28140Sstevel@tonic-gate /* First bring the device to full power */
28150Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
28160Sstevel@tonic-gate
28170Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
28180Sstevel@tonic-gate if (hidp->hid_dev_state == USB_DEV_ONLINE) {
28190Sstevel@tonic-gate /*
28200Sstevel@tonic-gate * We failed the checkpoint, there is no need to restore
28210Sstevel@tonic-gate * the device state
28220Sstevel@tonic-gate */
28230Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
28240Sstevel@tonic-gate hid_pm_idle_component(hidp);
28250Sstevel@tonic-gate
28260Sstevel@tonic-gate return;
28270Sstevel@tonic-gate }
28280Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
28290Sstevel@tonic-gate
28300Sstevel@tonic-gate
28310Sstevel@tonic-gate /* Check if we are talking to the same device */
28320Sstevel@tonic-gate if (usb_check_same_device(dip, hidp->hid_log_handle, USB_LOG_L2,
28330Sstevel@tonic-gate PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
28340Sstevel@tonic-gate
28350Sstevel@tonic-gate /* change the device state from suspended to disconnected */
28360Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
28370Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_DISCONNECTED;
28380Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
28390Sstevel@tonic-gate hid_pm_idle_component(hidp);
28409432SPengcheng.Chen@Sun.COM goto nodev;
28410Sstevel@tonic-gate }
28420Sstevel@tonic-gate
28430Sstevel@tonic-gate hid_set_idle(hidp);
28440Sstevel@tonic-gate hid_set_protocol(hidp, SET_REPORT_PROTOCOL);
28450Sstevel@tonic-gate
28460Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
28470Sstevel@tonic-gate /* if the device had remote wakeup earlier, enable it again */
28480Sstevel@tonic-gate if (hidpm->hid_wakeup_enabled) {
28490Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
28500Sstevel@tonic-gate
28510Sstevel@tonic-gate if ((rval = usb_handle_remote_wakeup(hidp->hid_dip,
28520Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE)) != USB_SUCCESS) {
28530Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
28540Sstevel@tonic-gate hidp->hid_log_handle,
28550Sstevel@tonic-gate "usb_handle_remote_wakeup failed (%d)", rval);
28560Sstevel@tonic-gate }
28570Sstevel@tonic-gate
28580Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
28590Sstevel@tonic-gate }
28600Sstevel@tonic-gate
28610Sstevel@tonic-gate /*
28620Sstevel@tonic-gate * restart polling on the interrupt pipe only if the device
28630Sstevel@tonic-gate * was previously operational (open)
28640Sstevel@tonic-gate */
286510153SAaron.Zang@Sun.COM if (HID_IS_OPEN(hidp)) {
28660Sstevel@tonic-gate if ((rval = hid_start_intr_polling(hidp)) != USB_SUCCESS) {
28670Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
28680Sstevel@tonic-gate "hid_restore_device_state:"
28690Sstevel@tonic-gate "unable to restart intr pipe poll"
28700Sstevel@tonic-gate " rval = %d ", rval);
28710Sstevel@tonic-gate /*
28720Sstevel@tonic-gate * change the device state from
28730Sstevel@tonic-gate * suspended to disconnected
28740Sstevel@tonic-gate */
28750Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_DISCONNECTED;
28760Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
28770Sstevel@tonic-gate hid_pm_idle_component(hidp);
28789432SPengcheng.Chen@Sun.COM goto nodev;
28790Sstevel@tonic-gate }
28800Sstevel@tonic-gate
28810Sstevel@tonic-gate if (hidp->hid_dev_state == USB_DEV_DISCONNECTED) {
28820Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
28830Sstevel@tonic-gate "device is being re-connected");
28840Sstevel@tonic-gate }
28850Sstevel@tonic-gate
28860Sstevel@tonic-gate /* set the device state ONLINE */
28870Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_ONLINE;
28880Sstevel@tonic-gate
28890Sstevel@tonic-gate /* inform upstream modules that the device is back */
289010153SAaron.Zang@Sun.COM if (hidp->hid_internal_flag == HID_STREAMS_OPEN) {
289110153SAaron.Zang@Sun.COM q = hidp->hid_internal_rq;
28929432SPengcheng.Chen@Sun.COM
28939432SPengcheng.Chen@Sun.COM mutex_exit(&hidp->hid_mutex);
289410153SAaron.Zang@Sun.COM if (canputnext(q)) {
28959432SPengcheng.Chen@Sun.COM mp = allocb(sizeof (struct iocblk), BPRI_HI);
28969432SPengcheng.Chen@Sun.COM if (mp != NULL) {
28979432SPengcheng.Chen@Sun.COM mp->b_datap->db_type = M_CTL;
28989432SPengcheng.Chen@Sun.COM mctlmsg = (struct iocblk *)
28999432SPengcheng.Chen@Sun.COM mp->b_datap->db_base;
29009432SPengcheng.Chen@Sun.COM mctlmsg->ioc_cmd = HID_CONNECT_EVENT;
29019432SPengcheng.Chen@Sun.COM mctlmsg->ioc_count = 0;
290210153SAaron.Zang@Sun.COM putnext(q, mp);
29039432SPengcheng.Chen@Sun.COM }
29040Sstevel@tonic-gate }
29059432SPengcheng.Chen@Sun.COM /* enable write side q */
290610153SAaron.Zang@Sun.COM qenable(WR(q));
29079432SPengcheng.Chen@Sun.COM mutex_enter(&hidp->hid_mutex);
290810153SAaron.Zang@Sun.COM }
290910153SAaron.Zang@Sun.COM
291010153SAaron.Zang@Sun.COM if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
291110153SAaron.Zang@Sun.COM q = hidp->hid_external_rq;
291210153SAaron.Zang@Sun.COM
291310153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
291410153SAaron.Zang@Sun.COM if (canputnext(q)) {
291510153SAaron.Zang@Sun.COM mp = allocb(sizeof (struct iocblk), BPRI_HI);
291610153SAaron.Zang@Sun.COM if (mp != NULL) {
291710153SAaron.Zang@Sun.COM mp->b_datap->db_type = M_CTL;
291810153SAaron.Zang@Sun.COM mctlmsg = (struct iocblk *)
291910153SAaron.Zang@Sun.COM mp->b_datap->db_base;
292010153SAaron.Zang@Sun.COM mctlmsg->ioc_cmd = HID_CONNECT_EVENT;
292110153SAaron.Zang@Sun.COM mctlmsg->ioc_count = 0;
292210153SAaron.Zang@Sun.COM putnext(q, mp);
292310153SAaron.Zang@Sun.COM }
292410153SAaron.Zang@Sun.COM }
292510153SAaron.Zang@Sun.COM /* enable write side q */
292610153SAaron.Zang@Sun.COM qenable(WR(q));
292710153SAaron.Zang@Sun.COM mutex_enter(&hidp->hid_mutex);
29280Sstevel@tonic-gate }
29290Sstevel@tonic-gate } else {
29300Sstevel@tonic-gate /* set the device state ONLINE */
29310Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_ONLINE;
29320Sstevel@tonic-gate }
29330Sstevel@tonic-gate
29340Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
29350Sstevel@tonic-gate hid_pm_idle_component(hidp);
29369432SPengcheng.Chen@Sun.COM return;
29379432SPengcheng.Chen@Sun.COM
29389432SPengcheng.Chen@Sun.COM nodev:
29399432SPengcheng.Chen@Sun.COM /*
29409432SPengcheng.Chen@Sun.COM * Notify applications about device removal. This only
29419432SPengcheng.Chen@Sun.COM * applies to an external (aka. physical) open. Not sure how to
29429432SPengcheng.Chen@Sun.COM * notify consconfig to close the internal minor node.
29439432SPengcheng.Chen@Sun.COM */
29449432SPengcheng.Chen@Sun.COM mutex_enter(&hidp->hid_mutex);
294510153SAaron.Zang@Sun.COM
294610153SAaron.Zang@Sun.COM if ((q = hidp->hid_external_rq) == NULL) {
294710153SAaron.Zang@Sun.COM mutex_exit(&hidp->hid_mutex);
294810153SAaron.Zang@Sun.COM return;
29499432SPengcheng.Chen@Sun.COM }
295010153SAaron.Zang@Sun.COM
29519432SPengcheng.Chen@Sun.COM mutex_exit(&hidp->hid_mutex);
295210153SAaron.Zang@Sun.COM mp = allocb(sizeof (uchar_t), BPRI_HI);
295310153SAaron.Zang@Sun.COM if (mp != NULL) {
295410153SAaron.Zang@Sun.COM mp->b_datap->db_type = M_ERROR;
295510153SAaron.Zang@Sun.COM mp->b_rptr = mp->b_datap->db_base;
295610153SAaron.Zang@Sun.COM mp->b_wptr = mp->b_rptr + sizeof (char);
295710153SAaron.Zang@Sun.COM *mp->b_rptr = ENODEV;
295810153SAaron.Zang@Sun.COM putnext(q, mp);
295910153SAaron.Zang@Sun.COM }
29600Sstevel@tonic-gate }
29610Sstevel@tonic-gate
29620Sstevel@tonic-gate
29630Sstevel@tonic-gate /*
29640Sstevel@tonic-gate * hid_qreply_merror:
29650Sstevel@tonic-gate * Pass an error message up.
29660Sstevel@tonic-gate */
29670Sstevel@tonic-gate static void
hid_qreply_merror(queue_t * q,mblk_t * mp,uchar_t errval)29680Sstevel@tonic-gate hid_qreply_merror(queue_t *q, mblk_t *mp, uchar_t errval)
29690Sstevel@tonic-gate {
29700Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR;
29710Sstevel@tonic-gate if (mp->b_cont) {
29720Sstevel@tonic-gate freemsg(mp->b_cont);
29730Sstevel@tonic-gate mp->b_cont = NULL;
29740Sstevel@tonic-gate }
29750Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base;
29760Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char);
29770Sstevel@tonic-gate *mp->b_rptr = errval;
29780Sstevel@tonic-gate
29790Sstevel@tonic-gate qreply(q, mp);
29800Sstevel@tonic-gate }
29810Sstevel@tonic-gate
29820Sstevel@tonic-gate
29830Sstevel@tonic-gate /*
29840Sstevel@tonic-gate * hid_data2mblk:
29850Sstevel@tonic-gate * Form an mblk from the given data
29860Sstevel@tonic-gate */
29870Sstevel@tonic-gate static mblk_t *
hid_data2mblk(uchar_t * buf,int len)29880Sstevel@tonic-gate hid_data2mblk(uchar_t *buf, int len)
29890Sstevel@tonic-gate {
29900Sstevel@tonic-gate mblk_t *mp = NULL;
29910Sstevel@tonic-gate
29920Sstevel@tonic-gate if (len >= 0) {
29930Sstevel@tonic-gate mp = allocb(len, BPRI_HI);
29940Sstevel@tonic-gate if (mp) {
29950Sstevel@tonic-gate bcopy(buf, mp->b_datap->db_base, len);
29960Sstevel@tonic-gate mp->b_wptr += len;
29970Sstevel@tonic-gate }
29980Sstevel@tonic-gate }
29990Sstevel@tonic-gate
30000Sstevel@tonic-gate return (mp);
30010Sstevel@tonic-gate }
30020Sstevel@tonic-gate
30030Sstevel@tonic-gate
30040Sstevel@tonic-gate /*
30050Sstevel@tonic-gate * hid_flush :
30060Sstevel@tonic-gate * Flush data already sent upstreams to client module.
30070Sstevel@tonic-gate */
30080Sstevel@tonic-gate static void
hid_flush(queue_t * q)30090Sstevel@tonic-gate hid_flush(queue_t *q)
30100Sstevel@tonic-gate {
30110Sstevel@tonic-gate /*
30120Sstevel@tonic-gate * Flush pending data already sent upstream
30130Sstevel@tonic-gate */
30140Sstevel@tonic-gate if ((q != NULL) && (q->q_next != NULL)) {
30150Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHR);
30160Sstevel@tonic-gate }
30170Sstevel@tonic-gate }
30180Sstevel@tonic-gate
30190Sstevel@tonic-gate
30200Sstevel@tonic-gate static void
hid_pm_busy_component(hid_state_t * hid_statep)30210Sstevel@tonic-gate hid_pm_busy_component(hid_state_t *hid_statep)
30220Sstevel@tonic-gate {
30230Sstevel@tonic-gate ASSERT(!mutex_owned(&hid_statep->hid_mutex));
30240Sstevel@tonic-gate
30250Sstevel@tonic-gate if (hid_statep->hid_pm != NULL) {
30260Sstevel@tonic-gate mutex_enter(&hid_statep->hid_mutex);
30270Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy++;
30280Sstevel@tonic-gate
30290Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, hid_statep->hid_log_handle,
30300Sstevel@tonic-gate "hid_pm_busy_component: %d",
30310Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy);
30320Sstevel@tonic-gate
30330Sstevel@tonic-gate mutex_exit(&hid_statep->hid_mutex);
30340Sstevel@tonic-gate if (pm_busy_component(hid_statep->hid_dip, 0) != DDI_SUCCESS) {
30350Sstevel@tonic-gate mutex_enter(&hid_statep->hid_mutex);
30360Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy--;
30370Sstevel@tonic-gate
30380Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM,
30390Sstevel@tonic-gate hid_statep->hid_log_handle,
30400Sstevel@tonic-gate "hid_pm_busy_component failed: %d",
30410Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy);
30420Sstevel@tonic-gate
30430Sstevel@tonic-gate mutex_exit(&hid_statep->hid_mutex);
30440Sstevel@tonic-gate }
30450Sstevel@tonic-gate
30460Sstevel@tonic-gate }
30470Sstevel@tonic-gate }
30480Sstevel@tonic-gate
30490Sstevel@tonic-gate
30500Sstevel@tonic-gate static void
hid_pm_idle_component(hid_state_t * hid_statep)30510Sstevel@tonic-gate hid_pm_idle_component(hid_state_t *hid_statep)
30520Sstevel@tonic-gate {
30530Sstevel@tonic-gate ASSERT(!mutex_owned(&hid_statep->hid_mutex));
30540Sstevel@tonic-gate
30550Sstevel@tonic-gate if (hid_statep->hid_pm != NULL) {
30560Sstevel@tonic-gate if (pm_idle_component(hid_statep->hid_dip, 0) == DDI_SUCCESS) {
30570Sstevel@tonic-gate mutex_enter(&hid_statep->hid_mutex);
30580Sstevel@tonic-gate ASSERT(hid_statep->hid_pm->hid_pm_busy > 0);
30590Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy--;
30600Sstevel@tonic-gate
30610Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM,
30620Sstevel@tonic-gate hid_statep->hid_log_handle,
30630Sstevel@tonic-gate "hid_pm_idle_component: %d",
30640Sstevel@tonic-gate hid_statep->hid_pm->hid_pm_busy);
30650Sstevel@tonic-gate
30660Sstevel@tonic-gate mutex_exit(&hid_statep->hid_mutex);
30670Sstevel@tonic-gate }
30680Sstevel@tonic-gate }
30690Sstevel@tonic-gate }
30700Sstevel@tonic-gate
30710Sstevel@tonic-gate
30720Sstevel@tonic-gate /*
30730Sstevel@tonic-gate * hid_pwrlvl0:
30740Sstevel@tonic-gate * Functions to handle power transition for various levels
30750Sstevel@tonic-gate * These functions act as place holders to issue USB commands
30760Sstevel@tonic-gate * to the devices to change their power levels
30770Sstevel@tonic-gate */
30780Sstevel@tonic-gate static int
hid_pwrlvl0(hid_state_t * hidp)30790Sstevel@tonic-gate hid_pwrlvl0(hid_state_t *hidp)
30800Sstevel@tonic-gate {
30810Sstevel@tonic-gate hid_power_t *hidpm;
30820Sstevel@tonic-gate int rval;
30830Sstevel@tonic-gate struct iocblk *mctlmsg;
30840Sstevel@tonic-gate mblk_t *mp_lowpwr, *mp_fullpwr;
30850Sstevel@tonic-gate queue_t *q;
30860Sstevel@tonic-gate
30870Sstevel@tonic-gate hidpm = hidp->hid_pm;
30880Sstevel@tonic-gate
30890Sstevel@tonic-gate switch (hidp->hid_dev_state) {
30900Sstevel@tonic-gate case USB_DEV_ONLINE:
30910Sstevel@tonic-gate /* Deny the powerdown request if the device is busy */
30920Sstevel@tonic-gate if (hidpm->hid_pm_busy != 0) {
30930Sstevel@tonic-gate
30940Sstevel@tonic-gate return (USB_FAILURE);
30950Sstevel@tonic-gate }
30960Sstevel@tonic-gate
309710153SAaron.Zang@Sun.COM if (HID_IS_OPEN(hidp)) {
309810153SAaron.Zang@Sun.COM q = hidp->hid_inuse_rq;
30990Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
31000Sstevel@tonic-gate if (canputnext(q)) {
31010Sstevel@tonic-gate /* try to preallocate mblks */
31020Sstevel@tonic-gate mp_lowpwr = allocb(
31030Sstevel@tonic-gate (int)sizeof (struct iocblk), BPRI_HI);
31040Sstevel@tonic-gate mp_fullpwr = allocb(
31050Sstevel@tonic-gate (int)sizeof (struct iocblk), BPRI_HI);
31060Sstevel@tonic-gate if ((mp_lowpwr != NULL) &&
31070Sstevel@tonic-gate (mp_fullpwr != NULL)) {
31080Sstevel@tonic-gate /* stop polling */
31090Sstevel@tonic-gate usb_pipe_stop_intr_polling(
31100Sstevel@tonic-gate hidp->hid_interrupt_pipe,
31110Sstevel@tonic-gate USB_FLAGS_SLEEP);
31120Sstevel@tonic-gate
31130Sstevel@tonic-gate /*
31140Sstevel@tonic-gate * Send an MCTL up indicating that
31150Sstevel@tonic-gate * we are powering off
31160Sstevel@tonic-gate */
31170Sstevel@tonic-gate mp_lowpwr->b_datap->db_type = M_CTL;
31180Sstevel@tonic-gate mctlmsg = (struct iocblk *)
31190Sstevel@tonic-gate mp_lowpwr->b_datap->db_base;
31200Sstevel@tonic-gate mctlmsg->ioc_cmd = HID_POWER_OFF;
31210Sstevel@tonic-gate mctlmsg->ioc_count = 0;
31220Sstevel@tonic-gate putnext(q, mp_lowpwr);
31230Sstevel@tonic-gate
31240Sstevel@tonic-gate /* save the full powr mblk */
31250Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
31260Sstevel@tonic-gate hidpm->hid_pm_pwrup = mp_fullpwr;
31270Sstevel@tonic-gate } else {
31280Sstevel@tonic-gate /*
31290Sstevel@tonic-gate * Since we failed to allocate one
31300Sstevel@tonic-gate * or more mblks, we fail attempt
31310Sstevel@tonic-gate * to go into low power this time
31320Sstevel@tonic-gate */
31330Sstevel@tonic-gate freemsg(mp_lowpwr);
31340Sstevel@tonic-gate freemsg(mp_fullpwr);
31350Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
31360Sstevel@tonic-gate
31370Sstevel@tonic-gate return (USB_FAILURE);
31380Sstevel@tonic-gate }
31390Sstevel@tonic-gate } else {
31400Sstevel@tonic-gate /*
31410Sstevel@tonic-gate * Since we can't send an mblk up,
31420Sstevel@tonic-gate * we fail this attempt to go to low power
31430Sstevel@tonic-gate */
31440Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
31450Sstevel@tonic-gate
31460Sstevel@tonic-gate return (USB_FAILURE);
31470Sstevel@tonic-gate }
31480Sstevel@tonic-gate }
314910153SAaron.Zang@Sun.COM
31500Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
31510Sstevel@tonic-gate /* Issue USB D3 command to the device here */
31520Sstevel@tonic-gate rval = usb_set_device_pwrlvl3(hidp->hid_dip);
31530Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
31540Sstevel@tonic-gate
31550Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
31560Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_PWRED_DOWN;
31570Sstevel@tonic-gate hidpm->hid_current_power = USB_DEV_OS_PWR_OFF;
31580Sstevel@tonic-gate
31590Sstevel@tonic-gate /* FALLTHRU */
31600Sstevel@tonic-gate case USB_DEV_DISCONNECTED:
31610Sstevel@tonic-gate case USB_DEV_SUSPENDED:
31620Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
31630Sstevel@tonic-gate default:
31640Sstevel@tonic-gate break;
31650Sstevel@tonic-gate }
31660Sstevel@tonic-gate
31670Sstevel@tonic-gate return (USB_SUCCESS);
31680Sstevel@tonic-gate }
31690Sstevel@tonic-gate
31700Sstevel@tonic-gate
31710Sstevel@tonic-gate /* ARGSUSED */
31720Sstevel@tonic-gate static int
hid_pwrlvl1(hid_state_t * hidp)31730Sstevel@tonic-gate hid_pwrlvl1(hid_state_t *hidp)
31740Sstevel@tonic-gate {
31750Sstevel@tonic-gate int rval;
31760Sstevel@tonic-gate
31770Sstevel@tonic-gate /* Issue USB D2 command to the device here */
31780Sstevel@tonic-gate rval = usb_set_device_pwrlvl2(hidp->hid_dip);
31790Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
31800Sstevel@tonic-gate
31810Sstevel@tonic-gate return (USB_FAILURE);
31820Sstevel@tonic-gate }
31830Sstevel@tonic-gate
31840Sstevel@tonic-gate
31850Sstevel@tonic-gate /* ARGSUSED */
31860Sstevel@tonic-gate static int
hid_pwrlvl2(hid_state_t * hidp)31870Sstevel@tonic-gate hid_pwrlvl2(hid_state_t *hidp)
31880Sstevel@tonic-gate {
31890Sstevel@tonic-gate int rval;
31900Sstevel@tonic-gate
31910Sstevel@tonic-gate rval = usb_set_device_pwrlvl1(hidp->hid_dip);
31920Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
31930Sstevel@tonic-gate
31940Sstevel@tonic-gate return (USB_FAILURE);
31950Sstevel@tonic-gate }
31960Sstevel@tonic-gate
31970Sstevel@tonic-gate
31980Sstevel@tonic-gate static int
hid_pwrlvl3(hid_state_t * hidp)31990Sstevel@tonic-gate hid_pwrlvl3(hid_state_t *hidp)
32000Sstevel@tonic-gate {
32010Sstevel@tonic-gate hid_power_t *hidpm;
32020Sstevel@tonic-gate int rval;
32030Sstevel@tonic-gate struct iocblk *mctlmsg;
32040Sstevel@tonic-gate mblk_t *mp;
32050Sstevel@tonic-gate queue_t *q;
32060Sstevel@tonic-gate
32070Sstevel@tonic-gate hidpm = hidp->hid_pm;
32080Sstevel@tonic-gate
32090Sstevel@tonic-gate switch (hidp->hid_dev_state) {
32100Sstevel@tonic-gate case USB_DEV_HID_POWER_CHANGE:
32110Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
32120Sstevel@tonic-gate /* Issue USB D0 command to the device here */
32130Sstevel@tonic-gate rval = usb_set_device_pwrlvl0(hidp->hid_dip);
32140Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
32150Sstevel@tonic-gate
321610153SAaron.Zang@Sun.COM if (HID_IS_OPEN(hidp)) {
32170Sstevel@tonic-gate /* restart polling on intr pipe */
32180Sstevel@tonic-gate rval = hid_start_intr_polling(hidp);
32190Sstevel@tonic-gate if (rval != USB_SUCCESS) {
32200Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS,
32210Sstevel@tonic-gate hidp->hid_log_handle,
32220Sstevel@tonic-gate "unable to restart intr polling rval = %d",
32230Sstevel@tonic-gate rval);
32240Sstevel@tonic-gate
32250Sstevel@tonic-gate return (USB_FAILURE);
32260Sstevel@tonic-gate }
32270Sstevel@tonic-gate
32280Sstevel@tonic-gate /* Send an MCTL up indicating device in full power */
322910153SAaron.Zang@Sun.COM q = hidp->hid_inuse_rq;
32300Sstevel@tonic-gate mp = hidpm->hid_pm_pwrup;
32310Sstevel@tonic-gate hidpm->hid_pm_pwrup = NULL;
32320Sstevel@tonic-gate mutex_exit(&hidp->hid_mutex);
32330Sstevel@tonic-gate if (canputnext(q)) {
32340Sstevel@tonic-gate mp->b_datap->db_type = M_CTL;
323510153SAaron.Zang@Sun.COM mctlmsg = (struct iocblk *)
323610153SAaron.Zang@Sun.COM mp->b_datap->db_base;
32370Sstevel@tonic-gate mctlmsg->ioc_cmd = HID_FULL_POWER;
32380Sstevel@tonic-gate mctlmsg->ioc_count = 0;
32390Sstevel@tonic-gate putnext(q, mp);
32400Sstevel@tonic-gate } else {
32410Sstevel@tonic-gate freemsg(mp);
32420Sstevel@tonic-gate }
32430Sstevel@tonic-gate mutex_enter(&hidp->hid_mutex);
32440Sstevel@tonic-gate }
324510153SAaron.Zang@Sun.COM
32460Sstevel@tonic-gate hidp->hid_dev_state = USB_DEV_ONLINE;
32470Sstevel@tonic-gate hidpm->hid_current_power = USB_DEV_OS_FULL_PWR;
32480Sstevel@tonic-gate
32490Sstevel@tonic-gate /* FALLTHRU */
32500Sstevel@tonic-gate case USB_DEV_DISCONNECTED:
32510Sstevel@tonic-gate case USB_DEV_SUSPENDED:
32520Sstevel@tonic-gate case USB_DEV_ONLINE:
32530Sstevel@tonic-gate
32540Sstevel@tonic-gate return (USB_SUCCESS);
32550Sstevel@tonic-gate default:
32560Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
32570Sstevel@tonic-gate "hid_pwrlvl3: Improper State");
32580Sstevel@tonic-gate
32590Sstevel@tonic-gate return (USB_FAILURE);
32600Sstevel@tonic-gate }
32610Sstevel@tonic-gate }
32620Sstevel@tonic-gate
32630Sstevel@tonic-gate
32640Sstevel@tonic-gate /*
32650Sstevel@tonic-gate * hid_polled_input_init :
32660Sstevel@tonic-gate * This routine calls down to the lower layers to initialize any state
32670Sstevel@tonic-gate * information. This routine initializes the lower layers for input.
32680Sstevel@tonic-gate */
32690Sstevel@tonic-gate static int
hid_polled_input_init(hid_state_t * hidp)32700Sstevel@tonic-gate hid_polled_input_init(hid_state_t *hidp)
32710Sstevel@tonic-gate {
32720Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
32730Sstevel@tonic-gate "hid_polled_input_init");
32740Sstevel@tonic-gate
32750Sstevel@tonic-gate /*
32760Sstevel@tonic-gate * Call the lower layers to intialize any state information
32770Sstevel@tonic-gate * that they will need to provide the polled characters.
32780Sstevel@tonic-gate */
32790Sstevel@tonic-gate if (usb_console_input_init(hidp->hid_dip, hidp->hid_interrupt_pipe,
32800Sstevel@tonic-gate &hidp->hid_polled_raw_buf,
32810Sstevel@tonic-gate &hidp->hid_polled_console_info) != USB_SUCCESS) {
32820Sstevel@tonic-gate /*
32830Sstevel@tonic-gate * If for some reason the lower layers cannot initialized, then
32840Sstevel@tonic-gate * bail.
32850Sstevel@tonic-gate */
32860Sstevel@tonic-gate (void) hid_polled_input_fini(hidp);
32870Sstevel@tonic-gate
32880Sstevel@tonic-gate return (USB_FAILURE);
32890Sstevel@tonic-gate }
32900Sstevel@tonic-gate
32910Sstevel@tonic-gate return (USB_SUCCESS);
32920Sstevel@tonic-gate }
32930Sstevel@tonic-gate
32940Sstevel@tonic-gate
32950Sstevel@tonic-gate /*
32960Sstevel@tonic-gate * hid_polled_input_fini:
32970Sstevel@tonic-gate * This routine is called when we are done using this device as an input
32980Sstevel@tonic-gate * device.
32990Sstevel@tonic-gate */
33000Sstevel@tonic-gate static int
hid_polled_input_fini(hid_state_t * hidp)33010Sstevel@tonic-gate hid_polled_input_fini(hid_state_t *hidp)
33020Sstevel@tonic-gate {
33030Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
33040Sstevel@tonic-gate "hid_polled_input_fini");
33050Sstevel@tonic-gate
33060Sstevel@tonic-gate /*
33070Sstevel@tonic-gate * Call the lower layers to free any state information
33080Sstevel@tonic-gate * only if polled input has been initialised.
33090Sstevel@tonic-gate */
33100Sstevel@tonic-gate if ((hidp->hid_polled_console_info) &&
33110Sstevel@tonic-gate (usb_console_input_fini(hidp->hid_polled_console_info) !=
33120Sstevel@tonic-gate USB_SUCCESS)) {
33130Sstevel@tonic-gate
33140Sstevel@tonic-gate return (USB_FAILURE);
33150Sstevel@tonic-gate }
33160Sstevel@tonic-gate hidp->hid_polled_console_info = NULL;
33170Sstevel@tonic-gate
33180Sstevel@tonic-gate return (USB_SUCCESS);
33190Sstevel@tonic-gate }
33200Sstevel@tonic-gate
33210Sstevel@tonic-gate
33220Sstevel@tonic-gate /*
33230Sstevel@tonic-gate * hid_polled_input_enter:
33240Sstevel@tonic-gate * This is the routine that is called in polled mode to save the USB
33250Sstevel@tonic-gate * state information before using the USB keyboard as an input device.
33260Sstevel@tonic-gate * This routine, and all of the routines that it calls, are responsible
33270Sstevel@tonic-gate * for saving any state information so that it can be restored when
33280Sstevel@tonic-gate * polling mode is over.
33290Sstevel@tonic-gate */
33300Sstevel@tonic-gate static int
33310Sstevel@tonic-gate /* ARGSUSED */
hid_polled_input_enter(hid_polled_handle_t hid_polled_inputp)33320Sstevel@tonic-gate hid_polled_input_enter(hid_polled_handle_t hid_polled_inputp)
33330Sstevel@tonic-gate {
33340Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)hid_polled_inputp;
33350Sstevel@tonic-gate
33360Sstevel@tonic-gate /*
33370Sstevel@tonic-gate * Call the lower layers to tell them to save any state information.
33380Sstevel@tonic-gate */
33390Sstevel@tonic-gate (void) usb_console_input_enter(hidp->hid_polled_console_info);
33400Sstevel@tonic-gate
33410Sstevel@tonic-gate return (USB_SUCCESS);
33420Sstevel@tonic-gate }
33430Sstevel@tonic-gate
33440Sstevel@tonic-gate
33450Sstevel@tonic-gate /*
33460Sstevel@tonic-gate * hid_polled_read :
33470Sstevel@tonic-gate * This is the routine that is called in polled mode when it wants to read
33480Sstevel@tonic-gate * a character. We will call to the lower layers to see if there is any
33490Sstevel@tonic-gate * input data available. If there is USB scancodes available, we will
33500Sstevel@tonic-gate * give them back.
33510Sstevel@tonic-gate */
33520Sstevel@tonic-gate static int
hid_polled_read(hid_polled_handle_t hid_polled_input,uchar_t ** buffer)33530Sstevel@tonic-gate hid_polled_read(hid_polled_handle_t hid_polled_input, uchar_t **buffer)
33540Sstevel@tonic-gate {
33550Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)hid_polled_input;
33560Sstevel@tonic-gate uint_t num_bytes;
33570Sstevel@tonic-gate
33580Sstevel@tonic-gate /*
33590Sstevel@tonic-gate * Call the lower layers to get the character from the controller.
33600Sstevel@tonic-gate * The lower layers will return the number of characters that
33610Sstevel@tonic-gate * were put in the raw buffer. The address of the raw buffer
33620Sstevel@tonic-gate * was passed down to the lower layers during hid_polled_init.
33630Sstevel@tonic-gate */
33640Sstevel@tonic-gate if (usb_console_read(hidp->hid_polled_console_info,
33650Sstevel@tonic-gate &num_bytes) != USB_SUCCESS) {
33660Sstevel@tonic-gate
33670Sstevel@tonic-gate return (0);
33680Sstevel@tonic-gate }
33690Sstevel@tonic-gate
33700Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW);
33710Sstevel@tonic-gate
33720Sstevel@tonic-gate *buffer = hidp->hid_polled_raw_buf;
33730Sstevel@tonic-gate
33740Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
33750Sstevel@tonic-gate
33760Sstevel@tonic-gate /*
33770Sstevel@tonic-gate * Return the number of characters that were copied into the
33780Sstevel@tonic-gate * polled buffer.
33790Sstevel@tonic-gate */
33800Sstevel@tonic-gate return (num_bytes);
33810Sstevel@tonic-gate }
33820Sstevel@tonic-gate
33830Sstevel@tonic-gate
33840Sstevel@tonic-gate /*
33850Sstevel@tonic-gate * hid_polled_input_exit :
33860Sstevel@tonic-gate * This is the routine that is called in polled mode when it is giving up
33870Sstevel@tonic-gate * control of the USB keyboard. This routine, and the lower layer routines
33880Sstevel@tonic-gate * that it calls, are responsible for restoring the controller state to the
33890Sstevel@tonic-gate * state it was in before polled mode.
33900Sstevel@tonic-gate */
33910Sstevel@tonic-gate static int
hid_polled_input_exit(hid_polled_handle_t hid_polled_inputp)33920Sstevel@tonic-gate hid_polled_input_exit(hid_polled_handle_t hid_polled_inputp)
33930Sstevel@tonic-gate {
33940Sstevel@tonic-gate hid_state_t *hidp = (hid_state_t *)hid_polled_inputp;
33950Sstevel@tonic-gate
33960Sstevel@tonic-gate /*
33970Sstevel@tonic-gate * Call the lower layers to restore any state information.
33980Sstevel@tonic-gate */
33990Sstevel@tonic-gate (void) usb_console_input_exit(hidp->hid_polled_console_info);
34000Sstevel@tonic-gate
34010Sstevel@tonic-gate return (0);
34020Sstevel@tonic-gate }
3403