17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*77e51571Sgongtian zhao - Sun Microsystems - Beijing China * Common Development and Distribution License (the "License"). 6*77e51571Sgongtian zhao - Sun Microsystems - Beijing China * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*77e51571Sgongtian zhao - Sun Microsystems - Beijing China * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Sample skeleton USB driver. 297c478bd9Sstevel@tonic-gate * This driver provides a framework for developing USB client drivers. 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * As a simplistic example, usbskel implements a data transfer by reading 327c478bd9Sstevel@tonic-gate * raw configuration data, which every USB device has. It is expected that 337c478bd9Sstevel@tonic-gate * the caller will issue an initial 4-byte read to get the total length of the 347c478bd9Sstevel@tonic-gate * first configuration, and follow up with a second read, passing the total 357c478bd9Sstevel@tonic-gate * length to read the entire configuration cloud. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * The device has four states (refer to usbai.h): 387c478bd9Sstevel@tonic-gate * USB_DEV_ONLINE: In action or ready for action. 397c478bd9Sstevel@tonic-gate * USB_DEV_DISCONNECTED: Hotplug removed, or device not present/correct on 407c478bd9Sstevel@tonic-gate * resume (CPR). 417c478bd9Sstevel@tonic-gate * USB_DEV_SUSPENDED: Device has been suspended along with the system. 427c478bd9Sstevel@tonic-gate * USB_DEV_PWRED_DOWN: Device has been powered down. (Note that this 437c478bd9Sstevel@tonic-gate * driver supports only two power states, powered down and 447c478bd9Sstevel@tonic-gate * full power.) 457c478bd9Sstevel@tonic-gate * 467c478bd9Sstevel@tonic-gate * In order to avoid race conditions between driver entry points, 477c478bd9Sstevel@tonic-gate * access to the device is serialized. Race conditions are an issue in 487c478bd9Sstevel@tonic-gate * particular between disconnect event callbacks, detach, power, open 497c478bd9Sstevel@tonic-gate * and data transfer callbacks. The functions usbskel_serialize/release_access 507c478bd9Sstevel@tonic-gate * are implemented for this purpose. 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * Mutexes should never be held when making calls into USBA or when 537c478bd9Sstevel@tonic-gate * sleeping. 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * pm_busy_component and pm_idle_component mark the device as busy or idle to 567c478bd9Sstevel@tonic-gate * the system. These functions are paired, and are called only from code 577c478bd9Sstevel@tonic-gate * bracketed by usbskel_serialize_access and usbskel_release_access. 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * NOTE: PM and CPR will be enabled at a later release of S10. 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG) 637c478bd9Sstevel@tonic-gate #define DEBUG 647c478bd9Sstevel@tonic-gate #endif 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #define USBDRV_MAJOR_VER 2 677c478bd9Sstevel@tonic-gate #define USBDRV_MINOR_VER 0 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* Uncomment to enable Power Management, when the OS PM framework is ready. */ 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * #ifndef USBSKEL_PM 727c478bd9Sstevel@tonic-gate * #define USBSKEL_PM 737c478bd9Sstevel@tonic-gate * #endif 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * Uncomment to enable Check Point Resume (system suspend and resume) when the 787c478bd9Sstevel@tonic-gate * OS CPR framework is ready. 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * #ifndef USBSKEL_CPR 827c478bd9Sstevel@tonic-gate * #define USBSKEL_CPR 837c478bd9Sstevel@tonic-gate * #endif 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h> 877c478bd9Sstevel@tonic-gate #include <sys/usb/clients/usbskel/usbskel.h> 887c478bd9Sstevel@tonic-gate 894610e4a0Sfrits int usbskel_errlevel = USBSKEL_LOG_LOG; 907c478bd9Sstevel@tonic-gate static char *name = "usbskl"; /* Driver name, used all over. */ 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * Boolean set to whether or not to dump the device's descriptor tree. 947c478bd9Sstevel@tonic-gate * Can be changed with the usblog_dumptree property in a usbskel.conf file. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate static boolean_t usbskel_dumptree; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * Function Prototypes 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate static int usbskel_attach(dev_info_t *, ddi_attach_cmd_t); 1027c478bd9Sstevel@tonic-gate static int usbskel_detach(dev_info_t *, ddi_detach_cmd_t); 1037c478bd9Sstevel@tonic-gate static int usbskel_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 1047c478bd9Sstevel@tonic-gate static int usbskel_cleanup(dev_info_t *, usbskel_state_t *); 1057c478bd9Sstevel@tonic-gate static int usbskel_open(dev_t *, int, int, cred_t *); 1067c478bd9Sstevel@tonic-gate static int usbskel_close(dev_t, int, int, cred_t *); 1077c478bd9Sstevel@tonic-gate static int usbskel_read(dev_t, struct uio *uip_p, cred_t *); 1087c478bd9Sstevel@tonic-gate static int usbskel_strategy(struct buf *); 1097c478bd9Sstevel@tonic-gate static void usbskel_minphys(struct buf *); 1107c478bd9Sstevel@tonic-gate static void usbskel_normal_callback(usb_pipe_handle_t, usb_ctrl_req_t *); 1117c478bd9Sstevel@tonic-gate static void usbskel_exception_callback(usb_pipe_handle_t, usb_ctrl_req_t *); 1127c478bd9Sstevel@tonic-gate static int usbskel_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1137c478bd9Sstevel@tonic-gate static int usbskel_disconnect_callback(dev_info_t *); 1147c478bd9Sstevel@tonic-gate static int usbskel_reconnect_callback(dev_info_t *); 1157c478bd9Sstevel@tonic-gate static void usbskel_restore_device_state(dev_info_t *, usbskel_state_t *); 1167c478bd9Sstevel@tonic-gate static int usbskel_cpr_suspend(dev_info_t *); 1177c478bd9Sstevel@tonic-gate static void usbskel_cpr_resume(dev_info_t *); 1187c478bd9Sstevel@tonic-gate static int usbskel_test_and_adjust_device_state(usbskel_state_t *); 1197c478bd9Sstevel@tonic-gate static int usbskel_open_pipes(usbskel_state_t *); 1207c478bd9Sstevel@tonic-gate static void usbskel_close_pipes(usbskel_state_t *); 1217c478bd9Sstevel@tonic-gate static int usbskel_pm_busy_component(usbskel_state_t *); 1227c478bd9Sstevel@tonic-gate static void usbskel_pm_idle_component(usbskel_state_t *); 1237c478bd9Sstevel@tonic-gate static int usbskel_power(dev_info_t *, int, int); 1247c478bd9Sstevel@tonic-gate #ifdef USBSKEL_PM 1257c478bd9Sstevel@tonic-gate static int usbskel_init_power_mgmt(usbskel_state_t *); 1267c478bd9Sstevel@tonic-gate static void usbskel_destroy_power_mgmt(usbskel_state_t *); 1277c478bd9Sstevel@tonic-gate #endif 1287c478bd9Sstevel@tonic-gate static int usbskel_serialize_access(usbskel_state_t *, boolean_t); 1297c478bd9Sstevel@tonic-gate static void usbskel_release_access(usbskel_state_t *); 1307c478bd9Sstevel@tonic-gate static int usbskel_check_same_device(usbskel_state_t *); 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 1337c478bd9Sstevel@tonic-gate static void usbskel_log(usbskel_state_t *, int, char *, ...); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* _NOTE is an advice for locklint. Locklint checks lock use for deadlocks. */ 1367c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req)) 1377c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf)) 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* module loading stuff */ 1407c478bd9Sstevel@tonic-gate struct cb_ops usbskel_cb_ops = { 1417c478bd9Sstevel@tonic-gate usbskel_open, /* open */ 1427c478bd9Sstevel@tonic-gate usbskel_close, /* close */ 1437c478bd9Sstevel@tonic-gate usbskel_strategy, /* strategy */ 1447c478bd9Sstevel@tonic-gate nulldev, /* print */ 1457c478bd9Sstevel@tonic-gate nulldev, /* dump */ 1467c478bd9Sstevel@tonic-gate usbskel_read, /* read */ 1477c478bd9Sstevel@tonic-gate nodev, /* write */ 1487c478bd9Sstevel@tonic-gate usbskel_ioctl, /* ioctl */ 1497c478bd9Sstevel@tonic-gate nulldev, /* devmap */ 1507c478bd9Sstevel@tonic-gate nodev, /* mmap */ 1517c478bd9Sstevel@tonic-gate nodev, /* segmap */ 1527c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 1537c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1547c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 1557c478bd9Sstevel@tonic-gate D_MP 1567c478bd9Sstevel@tonic-gate }; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static struct dev_ops usbskel_ops = { 1597c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1607c478bd9Sstevel@tonic-gate 0, /* refcnt */ 1617c478bd9Sstevel@tonic-gate usbskel_info, /* info */ 1627c478bd9Sstevel@tonic-gate nulldev, /* identify */ 1637c478bd9Sstevel@tonic-gate nulldev, /* probe */ 1647c478bd9Sstevel@tonic-gate usbskel_attach, /* attach */ 1657c478bd9Sstevel@tonic-gate usbskel_detach, /* detach */ 1667c478bd9Sstevel@tonic-gate nodev, /* reset */ 1677c478bd9Sstevel@tonic-gate &usbskel_cb_ops, /* driver operations */ 1687c478bd9Sstevel@tonic-gate NULL, /* bus operations */ 1697c478bd9Sstevel@tonic-gate usbskel_power /* power */ 1707c478bd9Sstevel@tonic-gate }; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static struct modldrv usbskel_modldrv = { 1737c478bd9Sstevel@tonic-gate &mod_driverops, 174*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "USB skeleton driver", 1757c478bd9Sstevel@tonic-gate &usbskel_ops 1767c478bd9Sstevel@tonic-gate }; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1797c478bd9Sstevel@tonic-gate MODREV_1, 1807c478bd9Sstevel@tonic-gate &usbskel_modldrv, 1817c478bd9Sstevel@tonic-gate NULL 1827c478bd9Sstevel@tonic-gate }; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* local variables */ 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* Soft state structures */ 1877c478bd9Sstevel@tonic-gate #define USBSKEL_INITIAL_SOFT_SPACE 1 1887c478bd9Sstevel@tonic-gate static void *usbskel_statep; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * Module-wide initialization routine. 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate int 1957c478bd9Sstevel@tonic-gate _init(void) 1967c478bd9Sstevel@tonic-gate { 1977c478bd9Sstevel@tonic-gate int rval; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _init"); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate if ((rval = ddi_soft_state_init(&usbskel_statep, 2027c478bd9Sstevel@tonic-gate sizeof (usbskel_state_t), USBSKEL_INITIAL_SOFT_SPACE)) != 0) { 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate return (rval); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) { 2087c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&usbskel_statep); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _init done"); 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate return (rval); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate /* 2187c478bd9Sstevel@tonic-gate * Module-wide tear-down routine. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate int 2217c478bd9Sstevel@tonic-gate _fini(void) 2227c478bd9Sstevel@tonic-gate { 2237c478bd9Sstevel@tonic-gate int rval; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _fini"); 2267c478bd9Sstevel@tonic-gate if ((rval = mod_remove(&modlinkage)) != 0) { 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate return (rval); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&usbskel_statep); 2327c478bd9Sstevel@tonic-gate usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _fini done"); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate return (rval); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate int 2397c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2407c478bd9Sstevel@tonic-gate { 2417c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * usbskel_info: 2477c478bd9Sstevel@tonic-gate * Get minor number, soft state structure, etc. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2507c478bd9Sstevel@tonic-gate static int 2517c478bd9Sstevel@tonic-gate usbskel_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 2527c478bd9Sstevel@tonic-gate void *arg, void **result) 2537c478bd9Sstevel@tonic-gate { 2547c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp; 2557c478bd9Sstevel@tonic-gate int error = DDI_FAILURE; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate switch (infocmd) { 2587c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2597c478bd9Sstevel@tonic-gate if ((usbskelp = ddi_get_soft_state(usbskel_statep, 2607c478bd9Sstevel@tonic-gate getminor((dev_t)arg))) != NULL) { 2617c478bd9Sstevel@tonic-gate *result = usbskelp->usbskel_dip; 2627c478bd9Sstevel@tonic-gate if (*result != NULL) { 2637c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate } else { 2667c478bd9Sstevel@tonic-gate *result = NULL; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate break; 2697c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2707c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)getminor((dev_t)arg); 2717c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 2727c478bd9Sstevel@tonic-gate break; 2737c478bd9Sstevel@tonic-gate default: 2747c478bd9Sstevel@tonic-gate break; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate return (error); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * usbskel_attach: 2837c478bd9Sstevel@tonic-gate * Attach or resume. 2847c478bd9Sstevel@tonic-gate * 2857c478bd9Sstevel@tonic-gate * For attach, initialize state and device, including: 2867c478bd9Sstevel@tonic-gate * state variables, locks, device node 2877c478bd9Sstevel@tonic-gate * device registration with system 2887c478bd9Sstevel@tonic-gate * power management, hotplugging 2897c478bd9Sstevel@tonic-gate * For resume, restore device and state 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate static int 2927c478bd9Sstevel@tonic-gate usbskel_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2937c478bd9Sstevel@tonic-gate { 2947c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 2957c478bd9Sstevel@tonic-gate char *devinst; 2967c478bd9Sstevel@tonic-gate int devinstlen; 2977c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = NULL; 2987c478bd9Sstevel@tonic-gate usb_reg_parse_lvl_t parse_level; 2997c478bd9Sstevel@tonic-gate usb_ep_data_t *ep_datap; 3007c478bd9Sstevel@tonic-gate int status; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate switch (cmd) { 3037c478bd9Sstevel@tonic-gate case DDI_ATTACH: 3047c478bd9Sstevel@tonic-gate break; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate case DDI_RESUME: 3077c478bd9Sstevel@tonic-gate usbskel_cpr_resume(dip); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * Always return success to work around enumeration failures. 3117c478bd9Sstevel@tonic-gate * This works around an issue where devices which are present 3127c478bd9Sstevel@tonic-gate * before a suspend and absent upon resume could cause a system 3137c478bd9Sstevel@tonic-gate * panic on resume. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3167c478bd9Sstevel@tonic-gate default: 3177c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(usbskel_statep, instance) == DDI_SUCCESS) { 3217c478bd9Sstevel@tonic-gate usbskelp = ddi_get_soft_state(usbskel_statep, instance); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate if (usbskelp == NULL) { 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip = dip; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 3317c478bd9Sstevel@tonic-gate devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ", 3327c478bd9Sstevel@tonic-gate ddi_driver_name(dip), instance); 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate usbskelp->usbskel_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP); 3357c478bd9Sstevel@tonic-gate (void) strncpy(usbskelp->usbskel_devinst, devinst, devinstlen); 3367c478bd9Sstevel@tonic-gate kmem_free(devinst, USB_MAXSTRINGLEN); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Attach: enter for attach"); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate usbskel_dumptree = (ddi_prop_exists(DDI_DEV_T_ANY, dip, 3417c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "usbskel_dumptree") == 1); 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Tree will %sbe dumped", 3447c478bd9Sstevel@tonic-gate ((usbskel_dumptree) ? "" : "not ")); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate parse_level = (usb_reg_parse_lvl_t)ddi_prop_get_int( 3477c478bd9Sstevel@tonic-gate DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3487c478bd9Sstevel@tonic-gate "usbskel_parse_level", USB_PARSE_LVL_ALL); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate switch (parse_level) { 3517c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_NONE: 3527c478bd9Sstevel@tonic-gate /* This driver needs a tree. */ 3537c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 3547c478bd9Sstevel@tonic-gate "parse_level requested to NOT DUMP"); 3557c478bd9Sstevel@tonic-gate parse_level = USB_PARSE_LVL_IF; 3567c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 3577c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_IF: 3587c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 3597c478bd9Sstevel@tonic-gate "parse_level set to dump specific interface"); 3607c478bd9Sstevel@tonic-gate break; 3617c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_CFG: 3627c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 3637c478bd9Sstevel@tonic-gate "parse_level set to dump specific config"); 3647c478bd9Sstevel@tonic-gate break; 3657c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_ALL: 3667c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 3677c478bd9Sstevel@tonic-gate "parse_level set to dump everything"); 3687c478bd9Sstevel@tonic-gate break; 3697c478bd9Sstevel@tonic-gate default: 3707c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 3717c478bd9Sstevel@tonic-gate "attach: parse_level will default to dump everything"); 3727c478bd9Sstevel@tonic-gate parse_level = USB_PARSE_LVL_ALL; 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) != 3767c478bd9Sstevel@tonic-gate USB_SUCCESS) { 3777c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 3787c478bd9Sstevel@tonic-gate "attach: usb_client_attach failed, error code:%d", status); 3797c478bd9Sstevel@tonic-gate goto fail; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate if ((status = usb_get_dev_data(dip, &usbskelp->usbskel_reg, parse_level, 3837c478bd9Sstevel@tonic-gate 0)) != USB_SUCCESS) { 3847c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 3857c478bd9Sstevel@tonic-gate "attach: usb_get_dev_data failed, error code:%d", status); 3867c478bd9Sstevel@tonic-gate goto fail; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate if (usbskel_dumptree) { 3907c478bd9Sstevel@tonic-gate (void) usb_print_descr_tree( 3917c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, usbskelp->usbskel_reg); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * Get the descriptor for an intr pipe at alt 0 of current interface. 3967c478bd9Sstevel@tonic-gate * This will be used later to open the pipe. 3977c478bd9Sstevel@tonic-gate */ 3987c478bd9Sstevel@tonic-gate if ((ep_datap = usb_lookup_ep_data(dip, usbskelp->usbskel_reg, 3997c478bd9Sstevel@tonic-gate usbskelp->usbskel_reg->dev_curr_if, 0, 0, 4007c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR, USB_EP_DIR_IN)) == NULL) { 4017c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 4027c478bd9Sstevel@tonic-gate "attach: Error getting intr endpoint descriptor"); 4037c478bd9Sstevel@tonic-gate goto fail; 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate usbskelp->usbskel_intr_ep_descr = ep_datap->ep_descr; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate usb_free_descr_tree(dip, usbskelp->usbskel_reg); 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate mutex_init(&usbskelp->usbskel_mutex, NULL, MUTEX_DRIVER, 410*77e51571Sgongtian zhao - Sun Microsystems - Beijing China usbskelp->usbskel_reg->dev_iblock_cookie); 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate cv_init(&usbskelp->usbskel_serial_cv, NULL, CV_DRIVER, NULL); 4137c478bd9Sstevel@tonic-gate usbskelp->usbskel_serial_inuse = B_FALSE; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate usbskelp->usbskel_locks_initialized = B_TRUE; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* create minor node */ 4187c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 4197c478bd9Sstevel@tonic-gate "usb_skeleton", 0) != DDI_SUCCESS) { 4207c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 4217c478bd9Sstevel@tonic-gate "attach: Error creating minor node"); 4227c478bd9Sstevel@tonic-gate goto fail; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate /* Put online before PM init as can get power managed afterward. */ 4267c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate #ifdef USBSKEL_PM 4297c478bd9Sstevel@tonic-gate /* initialize power management */ 4307c478bd9Sstevel@tonic-gate if (usbskel_init_power_mgmt(usbskelp) != USB_SUCCESS) { 4317c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 4327c478bd9Sstevel@tonic-gate "attach: Could not initialize power mgmt"); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate #endif 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate if (usb_register_hotplug_cbs(dip, usbskel_disconnect_callback, 4377c478bd9Sstevel@tonic-gate usbskel_reconnect_callback) != USB_SUCCESS) { 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate goto fail; 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* Report device */ 4437c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate fail: 4487c478bd9Sstevel@tonic-gate if (usbskelp) { 4497c478bd9Sstevel@tonic-gate (void) usbskel_cleanup(dip, usbskelp); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * usbskel_detach: 4587c478bd9Sstevel@tonic-gate * detach or suspend driver instance 4597c478bd9Sstevel@tonic-gate * 4607c478bd9Sstevel@tonic-gate * Note: in detach, only contention threads is from pm and disconnnect. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate static int 4637c478bd9Sstevel@tonic-gate usbskel_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4647c478bd9Sstevel@tonic-gate { 4657c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 4667c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 467*77e51571Sgongtian zhao - Sun Microsystems - Beijing China ddi_get_soft_state(usbskel_statep, instance); 4687c478bd9Sstevel@tonic-gate int rval = DDI_FAILURE; 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate switch (cmd) { 4717c478bd9Sstevel@tonic-gate case DDI_DETACH: 4727c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 4737c478bd9Sstevel@tonic-gate ASSERT((usbskelp->usbskel_drv_state & USBSKEL_OPEN) == 0); 4747c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 4777c478bd9Sstevel@tonic-gate "Detach: enter for detach"); 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate rval = usbskel_cleanup(dip, usbskelp); 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate break; 4827c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 4837c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 4847c478bd9Sstevel@tonic-gate "Detach: enter for suspend"); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate rval = usbskel_cpr_suspend(dip); 4877c478bd9Sstevel@tonic-gate default: 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate break; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * usbskel_cleanup: 4987c478bd9Sstevel@tonic-gate * clean up the driver state for detach 4997c478bd9Sstevel@tonic-gate */ 5007c478bd9Sstevel@tonic-gate static int 5017c478bd9Sstevel@tonic-gate usbskel_cleanup(dev_info_t *dip, usbskel_state_t *usbskelp) 5027c478bd9Sstevel@tonic-gate { 5037c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Cleanup: enter"); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_locks_initialized) { 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate /* This must be done 1st to prevent more events from coming. */ 5087c478bd9Sstevel@tonic-gate usb_unregister_hotplug_cbs(dip); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * At this point, no new activity can be initiated. The driver 5127c478bd9Sstevel@tonic-gate * has disabled hotplug callbacks. The Solaris framework has 5137c478bd9Sstevel@tonic-gate * disabled new opens on a device being detached, and does not 5147c478bd9Sstevel@tonic-gate * allow detaching an open device. 5157c478bd9Sstevel@tonic-gate * 5167c478bd9Sstevel@tonic-gate * The following ensures that all driver activity has drained. 5177c478bd9Sstevel@tonic-gate */ 5187c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 5197c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 5207c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 5217c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate #ifdef USBSKEL_PM 5247c478bd9Sstevel@tonic-gate /* All device activity has died down. */ 5257c478bd9Sstevel@tonic-gate usbskel_destroy_power_mgmt(usbskelp); 5267c478bd9Sstevel@tonic-gate #endif 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* start dismantling */ 5297c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate cv_destroy(&usbskelp->usbskel_serial_cv); 5327c478bd9Sstevel@tonic-gate mutex_destroy(&usbskelp->usbskel_mutex); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate usb_client_detach(dip, usbskelp->usbskel_reg); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_devinst != NULL) { 5387c478bd9Sstevel@tonic-gate kmem_free(usbskelp->usbskel_devinst, 5397c478bd9Sstevel@tonic-gate strlen(usbskelp->usbskel_devinst) + 1); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate ddi_soft_state_free(usbskel_statep, ddi_get_instance(dip)); 5437c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5507c478bd9Sstevel@tonic-gate static int 5517c478bd9Sstevel@tonic-gate usbskel_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 5527c478bd9Sstevel@tonic-gate { 5537c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 5547c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, getminor(*devp)); 5557c478bd9Sstevel@tonic-gate int rval = 0; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate if (usbskelp == NULL) { 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate return (ENXIO); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "open: enter"); 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * Keep it simple: one client at a time. 5667c478bd9Sstevel@tonic-gate * Exclusive open only 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 5697c478bd9Sstevel@tonic-gate if ((usbskelp->usbskel_drv_state & USBSKEL_OPEN) != 0) { 5707c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate return (EBUSY); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate usbskelp->usbskel_drv_state |= USBSKEL_OPEN; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * This is in place so that a disconnect or CPR doesn't interfere with 5787c478bd9Sstevel@tonic-gate * pipe opens. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate if (usbskel_serialize_access(usbskelp, USBSKEL_SER_SIG) == 0) { 5817c478bd9Sstevel@tonic-gate usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 5827c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate return (EINTR); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 5887c478bd9Sstevel@tonic-gate if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 5897c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 5907c478bd9Sstevel@tonic-gate "open: Error raising power"); 5917c478bd9Sstevel@tonic-gate rval = EIO; 5927c478bd9Sstevel@tonic-gate goto done; 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* Fail if device is no longer ready. */ 5977c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_dev_state != USB_DEV_ONLINE) { 5987c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 5997c478bd9Sstevel@tonic-gate rval = EIO; 6007c478bd9Sstevel@tonic-gate goto done; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 6047c478bd9Sstevel@tonic-gate if (usbskel_open_pipes(usbskelp) != USB_SUCCESS) { 6057c478bd9Sstevel@tonic-gate rval = EIO; 6067c478bd9Sstevel@tonic-gate goto done; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate /* Device specific initialization goes here. */ 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate done: 6127c478bd9Sstevel@tonic-gate if (rval != 0) { 6137c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 6147c478bd9Sstevel@tonic-gate usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 6177c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 6207c478bd9Sstevel@tonic-gate } else { 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* Device is idle until it is used. */ 6237c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 6247c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 6257c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate return (rval); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6337c478bd9Sstevel@tonic-gate static int 6347c478bd9Sstevel@tonic-gate usbskel_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 6357c478bd9Sstevel@tonic-gate { 6367c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 6377c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, getminor(dev)); 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close: enter"); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 6427c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 6437c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* Perform device session cleanup here. */ 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close: cleaning up..."); 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * USBA automatically flushes/resets active non-default pipes 6517c478bd9Sstevel@tonic-gate * when they are closed. We can't reset default pipe, but we 6527c478bd9Sstevel@tonic-gate * can wait for all requests on it from this dip to drain. 6537c478bd9Sstevel@tonic-gate */ 6547c478bd9Sstevel@tonic-gate (void) usb_pipe_drain_reqs(usbskelp->usbskel_dip, 6557c478bd9Sstevel@tonic-gate usbskelp->usbskel_reg->dev_default_ph, 0, 6567c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, 0); 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 6597c478bd9Sstevel@tonic-gate usbskel_close_pipes(usbskelp); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 6647c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate return (0); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6737c478bd9Sstevel@tonic-gate static int 6747c478bd9Sstevel@tonic-gate usbskel_read(dev_t dev, struct uio *uio_p, cred_t *cred_p) 6757c478bd9Sstevel@tonic-gate { 6767c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 6777c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, getminor(dev)); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "read enter"); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate return (physio(usbskel_strategy, NULL, dev, B_READ, 682*77e51571Sgongtian zhao - Sun Microsystems - Beijing China usbskel_minphys, uio_p)); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* 6877c478bd9Sstevel@tonic-gate * strategy: 6887c478bd9Sstevel@tonic-gate * Called through physio to setup and start the transfer. 6897c478bd9Sstevel@tonic-gate */ 6907c478bd9Sstevel@tonic-gate static int 6917c478bd9Sstevel@tonic-gate usbskel_strategy(struct buf *bp) 6927c478bd9Sstevel@tonic-gate { 6937c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 694*77e51571Sgongtian zhao - Sun Microsystems - Beijing China getminor(bp->b_edev)); 6957c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe = usbskelp->usbskel_reg->dev_default_ph; 6967c478bd9Sstevel@tonic-gate usb_ctrl_req_t *request; 6977c478bd9Sstevel@tonic-gate int status; 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "strategy enter"); 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Initialize residual count here in case transfer doesn't even get 7037c478bd9Sstevel@tonic-gate * started. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* Needed as this is a character driver. */ 7087c478bd9Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) { 7097c478bd9Sstevel@tonic-gate bp_mapin(bp); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 7137c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* Make sure device has not been disconnected. */ 7167c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_dev_state != USB_DEV_ONLINE) { 7177c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 7187c478bd9Sstevel@tonic-gate "usbskel_strategy: device can't be accessed"); 7197c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 7207c478bd9Sstevel@tonic-gate goto fail; 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* 7257c478bd9Sstevel@tonic-gate * Since every device has raw configuration data, set up a control 7267c478bd9Sstevel@tonic-gate * transfer to read the raw configuration data. In a production driver 7277c478bd9Sstevel@tonic-gate * a read would probably be done on a pipe other than the default pipe, 7287c478bd9Sstevel@tonic-gate * and would be reading data streamed by the device. 7297c478bd9Sstevel@tonic-gate */ 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate /* Allocate and initialize the request. */ 7327c478bd9Sstevel@tonic-gate if ((bp->b_private = request = usb_alloc_ctrl_req( 7337c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, bp->b_bcount, USB_FLAGS_SLEEP)) == 7347c478bd9Sstevel@tonic-gate NULL) { 7357c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 7367c478bd9Sstevel@tonic-gate "usbskel_read: Error allocating request"); 7377c478bd9Sstevel@tonic-gate goto fail; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate request->ctrl_bmRequestType = 7417c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD | 7427c478bd9Sstevel@tonic-gate USB_DEV_REQ_RCPT_DEV; 7437c478bd9Sstevel@tonic-gate request->ctrl_bRequest = USB_REQ_GET_DESCR; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate /* For now, return only the first configuration. */ 7467c478bd9Sstevel@tonic-gate request->ctrl_wValue = USB_DESCR_TYPE_SETUP_CFG | 0; 7477c478bd9Sstevel@tonic-gate request->ctrl_wIndex = 0; 7487c478bd9Sstevel@tonic-gate request->ctrl_wLength = bp->b_bcount; 7497c478bd9Sstevel@tonic-gate request->ctrl_timeout = 3; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate /* Autoclearing automatically set on default pipe. */ 7527c478bd9Sstevel@tonic-gate request->ctrl_attributes = USB_ATTRS_SHORT_XFER_OK; 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate request->ctrl_cb = usbskel_normal_callback; 7557c478bd9Sstevel@tonic-gate request->ctrl_exc_cb = usbskel_exception_callback; 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* Hook the req to the bp, so callback knows where to put the data. */ 7587c478bd9Sstevel@tonic-gate /* Now both bp and request know about each other. */ 7597c478bd9Sstevel@tonic-gate request->ctrl_client_private = (usb_opaque_t)bp; 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* 7627c478bd9Sstevel@tonic-gate * Issue the request asynchronously. Physio will block waiting for an 7637c478bd9Sstevel@tonic-gate * "interrupt" which comes as a callback. The callback calls biodone 7647c478bd9Sstevel@tonic-gate * to release physio from its wait. 7657c478bd9Sstevel@tonic-gate */ 7667c478bd9Sstevel@tonic-gate if ((status = usb_pipe_ctrl_xfer(pipe, request, USB_FLAGS_NOSLEEP)) != 7677c478bd9Sstevel@tonic-gate USB_SUCCESS) { 7687c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 7697c478bd9Sstevel@tonic-gate "usbskel_strategy: can't start transfer: status: %d", 7707c478bd9Sstevel@tonic-gate status); 7717c478bd9Sstevel@tonic-gate goto fail; 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate /* 7757c478bd9Sstevel@tonic-gate * Normally, usbskel_release_access() and usbskel_pm_idle_component 7767c478bd9Sstevel@tonic-gate * is called in callback handler. 7777c478bd9Sstevel@tonic-gate */ 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate return (0); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate fail: 7827c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 7837c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 7847c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate bioerror(bp, EIO); 7877c478bd9Sstevel@tonic-gate biodone(bp); 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate return (0); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate static void 7947c478bd9Sstevel@tonic-gate usbskel_minphys(struct buf *bp) 7957c478bd9Sstevel@tonic-gate { 7967c478bd9Sstevel@tonic-gate /* the config cloud is limited to 64k */ 7977c478bd9Sstevel@tonic-gate if (bp->b_bcount > USBSKEL_REQUEST_SIZE) { 7987c478bd9Sstevel@tonic-gate bp->b_bcount = USBSKEL_REQUEST_SIZE; 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate minphys(bp); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate /* 8057c478bd9Sstevel@tonic-gate * usbskel_normal_callback: 8067c478bd9Sstevel@tonic-gate * Completion handler for successful transfer. 8077c478bd9Sstevel@tonic-gate * Copy data from mblk returned by USBA, into 8087c478bd9Sstevel@tonic-gate * buffer passed by physio, to get it back to user. 8097c478bd9Sstevel@tonic-gate * Idle device 8107c478bd9Sstevel@tonic-gate * update counts, etc. 8117c478bd9Sstevel@tonic-gate * release request. 8127c478bd9Sstevel@tonic-gate * signal completion via biodone 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8157c478bd9Sstevel@tonic-gate static void 8167c478bd9Sstevel@tonic-gate usbskel_normal_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *request) 8177c478bd9Sstevel@tonic-gate { 8187c478bd9Sstevel@tonic-gate struct buf *bp = (struct buf *)request->ctrl_client_private; 8197c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 820*77e51571Sgongtian zhao - Sun Microsystems - Beijing China getminor(bp->b_edev)); 8217c478bd9Sstevel@tonic-gate mblk_t *data = request->ctrl_data; 8227c478bd9Sstevel@tonic-gate int amt_transferred = data->b_wptr - data->b_rptr; 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "normal callback enter"); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate ASSERT((request->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 8297c478bd9Sstevel@tonic-gate "at entry, b_bcount = %lu, b_resid = %lu, trans = %d", bp->b_bcount, 8307c478bd9Sstevel@tonic-gate bp->b_resid, amt_transferred); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 8337c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 8347c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate /* Copy data out of mblk, into buffer. */ 8377c478bd9Sstevel@tonic-gate if (amt_transferred) { 8387c478bd9Sstevel@tonic-gate bcopy(data->b_rptr, bp->b_un.b_addr, amt_transferred); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 8427c478bd9Sstevel@tonic-gate "normal callback: transferring %d bytes from 0x%p to 0x%p", 8437c478bd9Sstevel@tonic-gate amt_transferred, (void *)data, (void *)(bp->b_un.b_addr)); 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate /* Unhook. */ 8467c478bd9Sstevel@tonic-gate bp->b_private = NULL; 8477c478bd9Sstevel@tonic-gate request->ctrl_client_private = NULL; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate /* Free request. */ 8507c478bd9Sstevel@tonic-gate usb_free_ctrl_req(request); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate /* Finish up. */ 8537c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - amt_transferred; 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 8567c478bd9Sstevel@tonic-gate "at exit, b_bcount = %lu, b_resid = %lu, trans = %d", bp->b_bcount, 8577c478bd9Sstevel@tonic-gate bp->b_resid, amt_transferred); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate biodone(bp); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * usbskel_exception_callback: 8657c478bd9Sstevel@tonic-gate * Completion handler for an erred transfer. 8667c478bd9Sstevel@tonic-gate * Copy data from mblk returned by USBA, if any, into 8677c478bd9Sstevel@tonic-gate * buffer passed by physio, to get it back to user. 8687c478bd9Sstevel@tonic-gate * Idle device 8697c478bd9Sstevel@tonic-gate * update counts, etc. 8707c478bd9Sstevel@tonic-gate * release request. 8717c478bd9Sstevel@tonic-gate * signal completion via biodone 8727c478bd9Sstevel@tonic-gate */ 8737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8747c478bd9Sstevel@tonic-gate static void 8757c478bd9Sstevel@tonic-gate usbskel_exception_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *request) 8767c478bd9Sstevel@tonic-gate { 8777c478bd9Sstevel@tonic-gate struct buf *bp = (struct buf *)request->ctrl_client_private; 8787c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 879*77e51571Sgongtian zhao - Sun Microsystems - Beijing China getminor(bp->b_edev)); 8807c478bd9Sstevel@tonic-gate mblk_t *data = request->ctrl_data; 8817c478bd9Sstevel@tonic-gate int amt_transferred = (data ? data->b_wptr - data->b_rptr : 0); 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 8847c478bd9Sstevel@tonic-gate "at except cb entry, b_bcount = %lu, b_resid = %lu, trans = %d", 8857c478bd9Sstevel@tonic-gate bp->b_bcount, bp->b_resid, amt_transferred); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate ASSERT((request->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 8907c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 8917c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* Copy data, if any, out of mblk, into buffer. */ 8947c478bd9Sstevel@tonic-gate if (amt_transferred) { 8957c478bd9Sstevel@tonic-gate bcopy(data, bp->b_un.b_addr, amt_transferred); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount - amt_transferred; 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 9007c478bd9Sstevel@tonic-gate "exception cb: req = 0x%p, cr = %d\n\t cb_flags = 0x%x " 9017c478bd9Sstevel@tonic-gate "data = 0x%p, amt xfered = %d", (void *)request, 9027c478bd9Sstevel@tonic-gate request->ctrl_completion_reason, request->ctrl_cb_flags, 9037c478bd9Sstevel@tonic-gate (void *)(request->ctrl_data), amt_transferred); 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate /* Unhook */ 9067c478bd9Sstevel@tonic-gate bp->b_private = NULL; 9077c478bd9Sstevel@tonic-gate request->ctrl_client_private = NULL; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* Free request. */ 9107c478bd9Sstevel@tonic-gate usb_free_ctrl_req(request); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 9137c478bd9Sstevel@tonic-gate "at except cb exit, b_bcount = %lu, b_resid = %lu, trans = %d", 9147c478bd9Sstevel@tonic-gate bp->b_bcount, bp->b_resid, amt_transferred); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate bioerror(bp, EIO); 9177c478bd9Sstevel@tonic-gate biodone(bp); 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate /* 9227c478bd9Sstevel@tonic-gate * XXX Empty ioctl for now. 9237c478bd9Sstevel@tonic-gate */ 9247c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9257c478bd9Sstevel@tonic-gate static int 9267c478bd9Sstevel@tonic-gate usbskel_ioctl(dev_t dev, int cmd, intptr_t arg, 9277c478bd9Sstevel@tonic-gate int mode, cred_t *cred_p, int *rval_p) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 9307c478bd9Sstevel@tonic-gate ddi_get_soft_state(usbskel_statep, getminor(dev)); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "ioctl enter"); 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate return (ENOTTY); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate /* 9397c478bd9Sstevel@tonic-gate * usbskel_disconnect_callback: 9407c478bd9Sstevel@tonic-gate * Called when device hotplug-removed. 9417c478bd9Sstevel@tonic-gate * Close pipes. (This does not attempt to contact device.) 9427c478bd9Sstevel@tonic-gate * Set state to DISCONNECTED 9437c478bd9Sstevel@tonic-gate */ 9447c478bd9Sstevel@tonic-gate static int 9457c478bd9Sstevel@tonic-gate usbskel_disconnect_callback(dev_info_t *dip) 9467c478bd9Sstevel@tonic-gate { 9477c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 9487c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 949*77e51571Sgongtian zhao - Sun Microsystems - Beijing China ddi_get_soft_state(usbskel_statep, instance); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "disconnect: enter"); 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 9547c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * Save any state of device or IO in progress required by 9587c478bd9Sstevel@tonic-gate * usbskel_restore_device_state for proper device "thawing" later. 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_DISCONNECTED; 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 9637c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * usbskel_reconnect_callback: 9717c478bd9Sstevel@tonic-gate * Called with device hotplug-inserted 9727c478bd9Sstevel@tonic-gate * Restore state 9737c478bd9Sstevel@tonic-gate */ 9747c478bd9Sstevel@tonic-gate static int 9757c478bd9Sstevel@tonic-gate usbskel_reconnect_callback(dev_info_t *dip) 9767c478bd9Sstevel@tonic-gate { 9777c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 9787c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = 979*77e51571Sgongtian zhao - Sun Microsystems - Beijing China ddi_get_soft_state(usbskel_statep, instance); 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "reconnect: enter"); 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 9847c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 9857c478bd9Sstevel@tonic-gate usbskel_restore_device_state(dip, usbskelp); 9867c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 9877c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate /* 9947c478bd9Sstevel@tonic-gate * usbskel_restore_device_state: 9957c478bd9Sstevel@tonic-gate * Called during hotplug-reconnect and resume. 9967c478bd9Sstevel@tonic-gate * reenable power management 9977c478bd9Sstevel@tonic-gate * Verify the device is the same as before the disconnect/suspend. 9987c478bd9Sstevel@tonic-gate * Restore device state 9997c478bd9Sstevel@tonic-gate * Thaw any IO which was frozen. 10007c478bd9Sstevel@tonic-gate * Quiesce device. (Other routines will activate if thawed IO.) 10017c478bd9Sstevel@tonic-gate * Set device online. 10027c478bd9Sstevel@tonic-gate * Leave device disconnected if there are problems. 10037c478bd9Sstevel@tonic-gate */ 10047c478bd9Sstevel@tonic-gate static void 10057c478bd9Sstevel@tonic-gate usbskel_restore_device_state(dev_info_t *dip, usbskel_state_t *usbskelp) 10067c478bd9Sstevel@tonic-gate { 10077c478bd9Sstevel@tonic-gate int rval; 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 10107c478bd9Sstevel@tonic-gate "usbskel_restore_device_state: enter"); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate ASSERT((usbskelp->usbskel_dev_state == USB_DEV_DISCONNECTED) || 10157c478bd9Sstevel@tonic-gate (usbskelp->usbskel_dev_state == USB_DEV_SUSPENDED)); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 10207c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 10217c478bd9Sstevel@tonic-gate "usbskel_restore_device_state: Error raising power"); 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate goto fail; 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate /* Check if we are talking to the same device */ 10277c478bd9Sstevel@tonic-gate if (usbskel_check_same_device(usbskelp) != USB_SUCCESS) { 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate goto fail; 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 10337c478bd9Sstevel@tonic-gate if ((rval = usbskel_test_and_adjust_device_state(usbskelp)) != 10347c478bd9Sstevel@tonic-gate USB_SUCCESS) { 10357c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 10367c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 10377c478bd9Sstevel@tonic-gate "usbskel_restore_device_state: " 10387c478bd9Sstevel@tonic-gate "Error adjusting device: rval = %d", rval); 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate goto fail; 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 10437c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm) { 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate /* Failure here means device disappeared again. */ 10487c478bd9Sstevel@tonic-gate if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) != 10497c478bd9Sstevel@tonic-gate USB_SUCCESS) { 10507c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 10517c478bd9Sstevel@tonic-gate "device may or may not be accessible. " 10527c478bd9Sstevel@tonic-gate "Please verify reconnection"); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 10617c478bd9Sstevel@tonic-gate "usbskel_restore_device_state: end"); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate return; 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate fail: 10667c478bd9Sstevel@tonic-gate /* change the device state from suspended to disconnected */ 10677c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 10687c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_DISCONNECTED; 10697c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 10727c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* 10777c478bd9Sstevel@tonic-gate * usbskel_cpr_suspend: 10787c478bd9Sstevel@tonic-gate * Clean up device. 10797c478bd9Sstevel@tonic-gate * Wait for any IO to finish, then close pipes. 10807c478bd9Sstevel@tonic-gate * Quiesce device. 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate static int 10837c478bd9Sstevel@tonic-gate usbskel_cpr_suspend(dev_info_t *dip) 10847c478bd9Sstevel@tonic-gate { 10857c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 10867c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 1087*77e51571Sgongtian zhao - Sun Microsystems - Beijing China instance); 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "suspend enter"); 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate /* Serialize to prevent races with detach, open, device access. */ 10927c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 10937c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 10947c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 10977c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 10987c478bd9Sstevel@tonic-gate "suspend: Error raising power"); 10997c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate return (USB_FAILURE); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate /* 11077c478bd9Sstevel@tonic-gate * Set dev_state to suspended so other driver threads don't start any 11087c478bd9Sstevel@tonic-gate * new I/O. In a real driver, there may be draining of requests done 11097c478bd9Sstevel@tonic-gate * afterwards, and we don't want the draining to compete with new 11107c478bd9Sstevel@tonic-gate * requests being queued. 11117c478bd9Sstevel@tonic-gate */ 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate /* Don't suspend if the device is open. */ 11147c478bd9Sstevel@tonic-gate if ((usbskelp->usbskel_drv_state & USBSKEL_OPEN) != 0) { 11157c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 11167c478bd9Sstevel@tonic-gate "suspend: Device is open. Can't suspend"); 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 11197c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate return (USB_FAILURE); 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate /* Access device here to clean it up. */ 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_SUSPENDED; 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate /* 11317c478bd9Sstevel@tonic-gate * Save any state of device required by usbskel_restore_device_state 11327c478bd9Sstevel@tonic-gate * for proper device "thawing" later. 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 11367c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "suspend: success"); 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * usbskel_cpr_resume: 11487c478bd9Sstevel@tonic-gate * 11497c478bd9Sstevel@tonic-gate * usbskel_restore_device_state marks success by putting device back online 11507c478bd9Sstevel@tonic-gate */ 11517c478bd9Sstevel@tonic-gate static void 11527c478bd9Sstevel@tonic-gate usbskel_cpr_resume(dev_info_t *dip) 11537c478bd9Sstevel@tonic-gate { 11547c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 11557c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 1156*77e51571Sgongtian zhao - Sun Microsystems - Beijing China instance); 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "resume: enter"); 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * NOTE: A pm_raise_power in usbskel_restore_device_state will bring 11627c478bd9Sstevel@tonic-gate * the power-up state of device into synch with the system. 11637c478bd9Sstevel@tonic-gate */ 11647c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 11657c478bd9Sstevel@tonic-gate usbskel_restore_device_state(dip, usbskelp); 11667c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate /* 11717c478bd9Sstevel@tonic-gate * usbskel_test_and_adjust_device_state: 11727c478bd9Sstevel@tonic-gate * Place any device-specific initialization or sanity verification here. 11737c478bd9Sstevel@tonic-gate */ 11747c478bd9Sstevel@tonic-gate static int 11757c478bd9Sstevel@tonic-gate usbskel_test_and_adjust_device_state(usbskel_state_t *usbskelp) 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "test and adjust enter"); 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate /* 11847c478bd9Sstevel@tonic-gate * usbskel_open_pipes: 11857c478bd9Sstevel@tonic-gate * Open any pipes other than default pipe. 11867c478bd9Sstevel@tonic-gate * Mutex is assumed to be held. 11877c478bd9Sstevel@tonic-gate */ 11887c478bd9Sstevel@tonic-gate static int 11897c478bd9Sstevel@tonic-gate usbskel_open_pipes(usbskel_state_t *usbskelp) 11907c478bd9Sstevel@tonic-gate { 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 11937c478bd9Sstevel@tonic-gate usb_pipe_policy_t pipe_policy; 11947c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle; 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "open_pipes enter"); 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate bzero(&pipe_policy, sizeof (pipe_policy)); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate /* 12017c478bd9Sstevel@tonic-gate * Allow that pipes can support at least two asynchronous operations 12027c478bd9Sstevel@tonic-gate * going on simultaneously. Operations include asynchronous callbacks, 12037c478bd9Sstevel@tonic-gate * resets, closures. 12047c478bd9Sstevel@tonic-gate */ 12057c478bd9Sstevel@tonic-gate pipe_policy.pp_max_async_reqs = 2; 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_open(usbskelp->usbskel_dip, 12087c478bd9Sstevel@tonic-gate &usbskelp->usbskel_intr_ep_descr, &pipe_policy, 12097c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, &pipe_handle)) != USB_SUCCESS) { 12107c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 12117c478bd9Sstevel@tonic-gate "usbskel_open_pipes: Error opening intr pipe: status = %d", 12127c478bd9Sstevel@tonic-gate rval); 12137c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 12167c478bd9Sstevel@tonic-gate usbskelp->usbskel_intr_ph = pipe_handle; 12177c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * At this point, polling could be started on the pipe by making an 12217c478bd9Sstevel@tonic-gate * asynchronous input request on the pipe. Allocate a request by 12227c478bd9Sstevel@tonic-gate * calling usb_alloc_intr_req(9F) with a zero length, initialize 12237c478bd9Sstevel@tonic-gate * attributes with USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING, 12247c478bd9Sstevel@tonic-gate * initialize length to be packetsize of the endpoint, specify the 12257c478bd9Sstevel@tonic-gate * callbacks. Pass this request to usb_pipe_intr_xfer to start polling. 12267c478bd9Sstevel@tonic-gate * Call usb_pipe_stop_intr_poling(9F) to stop polling. 12277c478bd9Sstevel@tonic-gate */ 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate return (rval); 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate /* 12347c478bd9Sstevel@tonic-gate * usbskel_close_pipes: 12357c478bd9Sstevel@tonic-gate * Close pipes. Mutex is assumed to be held. 12367c478bd9Sstevel@tonic-gate */ 12377c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12387c478bd9Sstevel@tonic-gate static void 12397c478bd9Sstevel@tonic-gate usbskel_close_pipes(usbskel_state_t *usbskelp) 12407c478bd9Sstevel@tonic-gate { 12417c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close_pipes enter"); 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_intr_ph) { 12447c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = usbskelp->usbskel_intr_ph; 12457c478bd9Sstevel@tonic-gate usbskelp->usbskel_intr_ph = NULL; 12467c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate usb_pipe_close(usbskelp->usbskel_dip, pipe_handle, 12497c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, 0); 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate static int 12567c478bd9Sstevel@tonic-gate usbskel_pm_busy_component(usbskel_state_t *usbskelp) 12577c478bd9Sstevel@tonic-gate { 12587c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 12617c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm != NULL) { 12627c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_pm_busy++; 12637c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 12647c478bd9Sstevel@tonic-gate if (pm_busy_component(usbskelp->usbskel_dip, 0) == 12657c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 12667c478bd9Sstevel@tonic-gate (void) pm_raise_power( 12677c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, 0, USB_DEV_OS_FULL_PWR); 12687c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 12697c478bd9Sstevel@tonic-gate } else { 12707c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 12717c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_pm_busy--; 12727c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate return (rval); 12787c478bd9Sstevel@tonic-gate } 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate static void 12817c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskel_state_t *usbskelp) 12827c478bd9Sstevel@tonic-gate { 12837c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 12847c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm != NULL) { 12857c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 12867c478bd9Sstevel@tonic-gate if (pm_idle_component(usbskelp->usbskel_dip, 0) == 12877c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 12887c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 12897c478bd9Sstevel@tonic-gate ASSERT(usbskelp->usbskel_pm->usbskel_pm_busy > 0); 12907c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_pm_busy--; 12917c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 12947c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 12957c478bd9Sstevel@tonic-gate "usbskel_pm_idle_component: %d", 12967c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_pm_busy); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate /* 13027c478bd9Sstevel@tonic-gate * usbskel_power : 13037c478bd9Sstevel@tonic-gate * Power entry point, the workhorse behind pm_raise_power, pm_lower_power, 13047c478bd9Sstevel@tonic-gate * usb_req_raise_power and usb_req_lower_power. 13057c478bd9Sstevel@tonic-gate */ 13067c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13077c478bd9Sstevel@tonic-gate static int 13087c478bd9Sstevel@tonic-gate usbskel_power(dev_info_t *dip, int comp, int level) 13097c478bd9Sstevel@tonic-gate { 13107c478bd9Sstevel@tonic-gate usbskel_state_t *usbskelp; 13117c478bd9Sstevel@tonic-gate usbskel_power_t *pm; 13127c478bd9Sstevel@tonic-gate int rval = USB_FAILURE; 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate usbskelp = ddi_get_soft_state(usbskel_statep, ddi_get_instance(dip)); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 13177c478bd9Sstevel@tonic-gate "usbskel_power: enter: level = %d", level); 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 13207c478bd9Sstevel@tonic-gate (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate /* 13247c478bd9Sstevel@tonic-gate * If we are disconnected/suspended, return success. Note that if we 13257c478bd9Sstevel@tonic-gate * return failure, bringing down the system will hang when 13267c478bd9Sstevel@tonic-gate * PM tries to power up all devices 13277c478bd9Sstevel@tonic-gate */ 13287c478bd9Sstevel@tonic-gate if ((usbskelp->usbskel_dev_state == USB_DEV_DISCONNECTED) || 1329*77e51571Sgongtian zhao - Sun Microsystems - Beijing China (usbskelp->usbskel_dev_state == USB_DEV_SUSPENDED)) { 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 13327c478bd9Sstevel@tonic-gate "usbskel_power: disconnected/suspended " 13337c478bd9Sstevel@tonic-gate "dev_state=%d", usbskelp->usbskel_dev_state); 13347c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate goto done; 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm == NULL) { 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate goto done; 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate pm = usbskelp->usbskel_pm; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate /* Check if we are transitioning to a legal power level */ 13477c478bd9Sstevel@tonic-gate if (USB_DEV_PWRSTATE_OK(pm->usbskel_pwr_states, level)) { 13487c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 13497c478bd9Sstevel@tonic-gate "usbskel_power: illegal power level = %d " 13507c478bd9Sstevel@tonic-gate "pwr_states: %x", level, pm->usbskel_pwr_states); 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate goto done; 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate switch (level) { 13567c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_OFF : 13577c478bd9Sstevel@tonic-gate /* fail attempt to go to low power if busy */ 13587c478bd9Sstevel@tonic-gate if (pm->usbskel_pm_busy) { 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate goto done; 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_dev_state == USB_DEV_ONLINE) { 13637c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_PWRED_DOWN; 13647c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_current_power = 13657c478bd9Sstevel@tonic-gate USB_DEV_OS_PWR_OFF; 13667c478bd9Sstevel@tonic-gate } else { 13677c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate break; 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate case USB_DEV_OS_FULL_PWR : 13727c478bd9Sstevel@tonic-gate /* 13737c478bd9Sstevel@tonic-gate * PM framework tries to put us in full power during system 13747c478bd9Sstevel@tonic-gate * shutdown. 13757c478bd9Sstevel@tonic-gate */ 13767c478bd9Sstevel@tonic-gate usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 13777c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm->usbskel_current_power = 13787c478bd9Sstevel@tonic-gate USB_DEV_OS_FULL_PWR; 13797c478bd9Sstevel@tonic-gate break; 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* Levels 1 and 2 are not supported by this driver to keep it simple. */ 13827c478bd9Sstevel@tonic-gate default: 13837c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 13847c478bd9Sstevel@tonic-gate "usbskel_power: power level %d not supported", level); 13857c478bd9Sstevel@tonic-gate break; 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate done: 13887c478bd9Sstevel@tonic-gate usbskel_release_access(usbskelp); 13897c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate #ifdef USBSKEL_PM 13967c478bd9Sstevel@tonic-gate /* 13977c478bd9Sstevel@tonic-gate * usbskel_init_power_mgmt: 13987c478bd9Sstevel@tonic-gate * Initialize power management and remote wakeup functionality. 13997c478bd9Sstevel@tonic-gate * No mutex is necessary in this function as it's called only by attach. 14007c478bd9Sstevel@tonic-gate */ 14017c478bd9Sstevel@tonic-gate static int 14027c478bd9Sstevel@tonic-gate usbskel_init_power_mgmt(usbskel_state_t *usbskelp) 14037c478bd9Sstevel@tonic-gate { 14047c478bd9Sstevel@tonic-gate int rval = USB_FAILURE; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "init_power_mgmt enter"); 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate /* 14097c478bd9Sstevel@tonic-gate * If remote wakeup is not available you may not want to do 14107c478bd9Sstevel@tonic-gate * power management. 14117c478bd9Sstevel@tonic-gate */ 14127c478bd9Sstevel@tonic-gate if (usb_handle_remote_wakeup(usbskelp->usbskel_dip, 14137c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 14147c478bd9Sstevel@tonic-gate usbskel_power_t *usbskelpm; 14157c478bd9Sstevel@tonic-gate uint_t pwr_states; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* Allocate the state structure */ 14187c478bd9Sstevel@tonic-gate usbskelpm = kmem_zalloc(sizeof (usbskel_power_t), KM_SLEEP); 14197c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm = usbskelpm; 14207c478bd9Sstevel@tonic-gate usbskelpm->usbskel_state = usbskelp; 14217c478bd9Sstevel@tonic-gate usbskelpm->usbskel_pm_capabilities = 0; 14227c478bd9Sstevel@tonic-gate usbskelpm->usbskel_current_power = USB_DEV_OS_FULL_PWR; 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate if ((rval = usb_create_pm_components( 14257c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, &pwr_states)) == USB_SUCCESS) { 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, 14287c478bd9Sstevel@tonic-gate "usbskel_init_power_mgmt: created PM components"); 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate usbskelpm->usbskel_pwr_states = 1431*77e51571Sgongtian zhao - Sun Microsystems - Beijing China (uint8_t)pwr_states; 14327c478bd9Sstevel@tonic-gate (void) pm_raise_power( 14337c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, 0, USB_DEV_OS_FULL_PWR); 14347c478bd9Sstevel@tonic-gate } else { 14357c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 14367c478bd9Sstevel@tonic-gate "usbskel_init_power_mgmt: create_pm_compts failed"); 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate } else { 14397c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 14407c478bd9Sstevel@tonic-gate "usbskel_init_power_mgmt: failure enabling remote wakeup"); 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "usbskel_init_power_mgmt: end"); 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate return (rval); 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate /* 14497c478bd9Sstevel@tonic-gate * usbskel_destroy_power_mgmt: 14507c478bd9Sstevel@tonic-gate * Shut down and destroy power management and remote wakeup functionality. 14517c478bd9Sstevel@tonic-gate */ 14527c478bd9Sstevel@tonic-gate static void 14537c478bd9Sstevel@tonic-gate usbskel_destroy_power_mgmt(usbskel_state_t *usbskelp) 14547c478bd9Sstevel@tonic-gate { 14557c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_LOG, "destroy_power_mgmt enter"); 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&usbskelp->usbskel_mutex)); 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_pm) { 14607c478bd9Sstevel@tonic-gate (void) usbskel_pm_busy_component(usbskelp); 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate mutex_enter(&usbskelp->usbskel_mutex); 14637c478bd9Sstevel@tonic-gate if (usbskelp->usbskel_dev_state != USB_DEV_DISCONNECTED) { 14647c478bd9Sstevel@tonic-gate int rval; 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate if ((rval = usb_handle_remote_wakeup( 14697c478bd9Sstevel@tonic-gate usbskelp->usbskel_dip, 14707c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_DISABLE)) != 14717c478bd9Sstevel@tonic-gate USB_SUCCESS) { 14727c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 14737c478bd9Sstevel@tonic-gate "usbskel_destroy_power_mgmt: " 14747c478bd9Sstevel@tonic-gate "Error disabling rmt wakeup: rval = %d", 14757c478bd9Sstevel@tonic-gate rval); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate } else { 14787c478bd9Sstevel@tonic-gate mutex_exit(&usbskelp->usbskel_mutex); 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate /* 14827c478bd9Sstevel@tonic-gate * Since remote wakeup is disabled now, 14837c478bd9Sstevel@tonic-gate * no one can raise power 14847c478bd9Sstevel@tonic-gate * and get to device once power is lowered here. 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate pm_lower_power(usbskelp->usbskel_dip, 0, USB_DEV_OS_PWR_OFF); 14877c478bd9Sstevel@tonic-gate usbskel_pm_idle_component(usbskelp); 14887c478bd9Sstevel@tonic-gate kmem_free(usbskelp->usbskel_pm, sizeof (usbskel_power_t)); 14897c478bd9Sstevel@tonic-gate usbskelp->usbskel_pm = NULL; 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate #endif 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate /* 14967c478bd9Sstevel@tonic-gate * usbskel_serialize_access: 14977c478bd9Sstevel@tonic-gate * Get the serial synchronization object before returning. 14987c478bd9Sstevel@tonic-gate * 14997c478bd9Sstevel@tonic-gate * Arguments: 15007c478bd9Sstevel@tonic-gate * usbskelp - Pointer to usbskel state structure 15017c478bd9Sstevel@tonic-gate * waitsig - Set to: 15027c478bd9Sstevel@tonic-gate * USBSKEL_SER_SIG - to wait such that a signal can interrupt 15037c478bd9Sstevel@tonic-gate * USBSKEL_SER_NOSIG - to wait such that a signal cannot interrupt 15047c478bd9Sstevel@tonic-gate */ 15057c478bd9Sstevel@tonic-gate static int 15067c478bd9Sstevel@tonic-gate usbskel_serialize_access(usbskel_state_t *usbskelp, boolean_t waitsig) 15077c478bd9Sstevel@tonic-gate { 15087c478bd9Sstevel@tonic-gate int rval = 1; 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate while (usbskelp->usbskel_serial_inuse) { 15137c478bd9Sstevel@tonic-gate if (waitsig == USBSKEL_SER_SIG) { 15147c478bd9Sstevel@tonic-gate rval = cv_wait_sig(&usbskelp->usbskel_serial_cv, 15157c478bd9Sstevel@tonic-gate &usbskelp->usbskel_mutex); 15167c478bd9Sstevel@tonic-gate } else { 15177c478bd9Sstevel@tonic-gate cv_wait(&usbskelp->usbskel_serial_cv, 15187c478bd9Sstevel@tonic-gate &usbskelp->usbskel_mutex); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate usbskelp->usbskel_serial_inuse = B_TRUE; 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate return (rval); 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* 15287c478bd9Sstevel@tonic-gate * usbskel_release_access: 15297c478bd9Sstevel@tonic-gate * Release the serial synchronization object. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate static void 15327c478bd9Sstevel@tonic-gate usbskel_release_access(usbskel_state_t *usbskelp) 15337c478bd9Sstevel@tonic-gate { 15347c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 15357c478bd9Sstevel@tonic-gate usbskelp->usbskel_serial_inuse = B_FALSE; 15367c478bd9Sstevel@tonic-gate cv_broadcast(&usbskelp->usbskel_serial_cv); 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* 15417c478bd9Sstevel@tonic-gate * usbskel_check_same_device: 15427c478bd9Sstevel@tonic-gate * Check if the device connected to the port is the same as 15437c478bd9Sstevel@tonic-gate * the previous device that was in the port. The previous device is 15447c478bd9Sstevel@tonic-gate * represented by the dip on record for the port. Print a message 15457c478bd9Sstevel@tonic-gate * if the device is different. Can block. 15467c478bd9Sstevel@tonic-gate * 15477c478bd9Sstevel@tonic-gate * return values: 15487c478bd9Sstevel@tonic-gate * USB_SUCCESS: same device 15497c478bd9Sstevel@tonic-gate * USB_INVALID_VERSION not same device 15507c478bd9Sstevel@tonic-gate * USB_FAILURE: Failure processing request 15517c478bd9Sstevel@tonic-gate */ 15527c478bd9Sstevel@tonic-gate static int 15537c478bd9Sstevel@tonic-gate usbskel_check_same_device(usbskel_state_t *usbskelp) 15547c478bd9Sstevel@tonic-gate { 15557c478bd9Sstevel@tonic-gate usb_dev_descr_t *orig_usb_dev_descr; 15567c478bd9Sstevel@tonic-gate usb_dev_descr_t usb_dev_descr; 15577c478bd9Sstevel@tonic-gate mblk_t *pdata = NULL; 15587c478bd9Sstevel@tonic-gate int rval; 15597c478bd9Sstevel@tonic-gate char *buf; 15607c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 15617c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 15627c478bd9Sstevel@tonic-gate boolean_t match = B_TRUE; 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate usb_ctrl_setup_t setup = { 15657c478bd9Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD | 15667c478bd9Sstevel@tonic-gate USB_DEV_REQ_RCPT_DEV, 15677c478bd9Sstevel@tonic-gate USB_REQ_GET_DESCR, /* bRequest */ 15687c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 15697c478bd9Sstevel@tonic-gate 0, /* wIndex */ 15707c478bd9Sstevel@tonic-gate USB_DEV_DESCR_SIZE, /* wLength */ 15717c478bd9Sstevel@tonic-gate 0 /* request attributes */ 15727c478bd9Sstevel@tonic-gate }; 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&usbskelp->usbskel_mutex)); 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate orig_usb_dev_descr = usbskelp->usbskel_reg->dev_descr; 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate /* get the "new" device descriptor */ 15797c478bd9Sstevel@tonic-gate rval = usb_pipe_ctrl_xfer_wait(usbskelp->usbskel_reg->dev_default_ph, 15807c478bd9Sstevel@tonic-gate &setup, &pdata, &completion_reason, &cb_flags, USB_FLAGS_SLEEP); 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 15837c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 15847c478bd9Sstevel@tonic-gate "usbskel_check_same_device: " 15857c478bd9Sstevel@tonic-gate "getting device descriptor failed " 15867c478bd9Sstevel@tonic-gate "rval=%d, cr=%d, cb=0x%x\n", 15877c478bd9Sstevel@tonic-gate rval, completion_reason, cb_flags); 15887c478bd9Sstevel@tonic-gate freemsg(pdata); 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate return (USB_FAILURE); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate ASSERT(pdata != NULL); 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate (void) usb_parse_data("2cs4c3s4c", pdata->b_rptr, 15967c478bd9Sstevel@tonic-gate pdata->b_wptr - pdata->b_rptr, &usb_dev_descr, 15977c478bd9Sstevel@tonic-gate sizeof (usb_dev_descr_t)); 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate freemsg(pdata); 16007c478bd9Sstevel@tonic-gate pdata = NULL; 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate /* Always check the device descriptor length. */ 16037c478bd9Sstevel@tonic-gate if (usb_dev_descr.bLength != USB_DEV_DESCR_SIZE) { 16047c478bd9Sstevel@tonic-gate match = B_FALSE; 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate /* Always check the device descriptor. */ 16077c478bd9Sstevel@tonic-gate } else if (bcmp(orig_usb_dev_descr, 16087c478bd9Sstevel@tonic-gate (char *)&usb_dev_descr, USB_DEV_DESCR_SIZE) != 0) { 16097c478bd9Sstevel@tonic-gate match = B_FALSE; 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate /* if requested & this device has a serial number check and compare */ 16137c478bd9Sstevel@tonic-gate if ((match == B_TRUE) && 16147c478bd9Sstevel@tonic-gate (usbskelp->usbskel_reg->dev_serial != NULL)) { 16157c478bd9Sstevel@tonic-gate buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP); 16167c478bd9Sstevel@tonic-gate if (usb_get_string_descr(usbskelp->usbskel_dip, USB_LANG_ID, 16177c478bd9Sstevel@tonic-gate usb_dev_descr.iSerialNumber, buf, 16187c478bd9Sstevel@tonic-gate USB_MAXSTRINGLEN) == USB_SUCCESS) { 16197c478bd9Sstevel@tonic-gate match = 16207c478bd9Sstevel@tonic-gate (strcmp(buf, 16217c478bd9Sstevel@tonic-gate usbskelp->usbskel_reg->dev_serial) == 0); 16227c478bd9Sstevel@tonic-gate } 16237c478bd9Sstevel@tonic-gate kmem_free(buf, USB_MAXSTRINGLEN); 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate if (match == B_FALSE) { 16277c478bd9Sstevel@tonic-gate usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 16287c478bd9Sstevel@tonic-gate "Device is not identical to the " 16297c478bd9Sstevel@tonic-gate "previous one this port.\n" 16307c478bd9Sstevel@tonic-gate "Please disconnect and reconnect"); 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate /* 16397c478bd9Sstevel@tonic-gate * usbskel_log: 16407c478bd9Sstevel@tonic-gate * Switchable logging to logfile and screen. 16417c478bd9Sstevel@tonic-gate * 16427c478bd9Sstevel@tonic-gate * Arguments: 16437c478bd9Sstevel@tonic-gate * usbskelp: usbskel state pointer. 16447c478bd9Sstevel@tonic-gate * if NULL, driver name and instance won't print with the message 16457c478bd9Sstevel@tonic-gate * msglevel: 16467c478bd9Sstevel@tonic-gate * if USBSKEL_LOG_LOG, goes only to logfile. 16477c478bd9Sstevel@tonic-gate * (usbskel_errlevel must be set to USBSKEL_LOG_LOG too.) 16487c478bd9Sstevel@tonic-gate * if USBSKEL_LOG_CONSOLE, goes to both logfile and screen 16497c478bd9Sstevel@tonic-gate * (usbskel_errlevel can be either value for this to work.) 16507c478bd9Sstevel@tonic-gate * cmn_err_level: error level passed to cmn_err(9F) 16517c478bd9Sstevel@tonic-gate * format and args: as you would call cmn_err, except without special 16527c478bd9Sstevel@tonic-gate * first routing character. 16537c478bd9Sstevel@tonic-gate * 16547c478bd9Sstevel@tonic-gate * Do not call this in an interrupt context, since kmem_alloc can sleep. 16557c478bd9Sstevel@tonic-gate */ 16567c478bd9Sstevel@tonic-gate static void 16577c478bd9Sstevel@tonic-gate usbskel_log(usbskel_state_t *usbskelp, int msglevel, char *formatarg, ...) 16587c478bd9Sstevel@tonic-gate { 16597c478bd9Sstevel@tonic-gate va_list ap; 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate if (msglevel <= usbskel_errlevel) { 16627c478bd9Sstevel@tonic-gate char *format; 16637c478bd9Sstevel@tonic-gate int formatlen = strlen(formatarg) + 2; /* '!' and NULL char */ 16647c478bd9Sstevel@tonic-gate int devinst_start = 0; 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate /* Allocate extra room if driver name and instance is present */ 16677c478bd9Sstevel@tonic-gate if (usbskelp != NULL) { 16687c478bd9Sstevel@tonic-gate formatlen += strlen(usbskelp->usbskel_devinst); 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate format = kmem_zalloc(formatlen, KM_SLEEP); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate if (msglevel == USBSKEL_LOG_LOG) { 16747c478bd9Sstevel@tonic-gate format[0] = '!'; 16757c478bd9Sstevel@tonic-gate devinst_start = 1; 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate if (usbskelp != NULL) { 16797c478bd9Sstevel@tonic-gate (void) strcpy(&format[devinst_start], 16807c478bd9Sstevel@tonic-gate usbskelp->usbskel_devinst); 16817c478bd9Sstevel@tonic-gate } 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate va_start(ap, formatarg); 16847c478bd9Sstevel@tonic-gate (void) strcat(format, formatarg); 16857c478bd9Sstevel@tonic-gate vcmn_err(CE_CONT, format, ap); 16867c478bd9Sstevel@tonic-gate va_end(ap); 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate kmem_free(format, formatlen); 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate } 1691