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