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
5112116d8Sfb  * Common Development and Distribution License (the "License").
6112116d8Sfb  * 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  *
21*be529ebcSRaymond Chen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
227c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Printer Class Driver for USB
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * This driver supports devices that adhere to the USB Printer Class
307c478bd9Sstevel@tonic-gate  * specification 1.0.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * NOTE: This driver is not DDI compliant in that it uses undocumented
337c478bd9Sstevel@tonic-gate  * functions for logging (USB_DPRINTF_L*, usb_alloc_log_hdl, usb_free_log_hdl),
347c478bd9Sstevel@tonic-gate  * and serialization (usb_serialize_access, usb_release_access,
357c478bd9Sstevel@tonic-gate  * usb_init_serialization, usb_fini_serialization)
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * Undocumented functions may go away in a future Solaris OS release.
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  * Please see the DDK for sample code of these functions, and for the usbskel
407c478bd9Sstevel@tonic-gate  * skeleton template driver which contains scaled-down versions of these
417c478bd9Sstevel@tonic-gate  * functions written in a DDI-compliant way.
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
457c478bd9Sstevel@tonic-gate #define	DEBUG
467c478bd9Sstevel@tonic-gate #endif
477c478bd9Sstevel@tonic-gate #ifdef __lock_lint
487c478bd9Sstevel@tonic-gate #define	_MULTI_DATAMODEL
497c478bd9Sstevel@tonic-gate #endif
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #define	USBDRV_MAJOR_VER	2
527c478bd9Sstevel@tonic-gate #define	USBDRV_MINOR_VER	0
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
557c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
567c478bd9Sstevel@tonic-gate #include <sys/bpp_io.h>
577c478bd9Sstevel@tonic-gate #include <sys/ecppsys.h>
587c478bd9Sstevel@tonic-gate #include <sys/prnio.h>
597c478bd9Sstevel@tonic-gate #include <sys/errno.h>
607c478bd9Sstevel@tonic-gate #include <sys/usb/clients/printer/usb_printer.h>
617c478bd9Sstevel@tonic-gate #include <sys/usb/clients/printer/usbprn.h>
62d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /* Debugging support */
654610e4a0Sfrits uint_t	usbprn_errmask		= (uint_t)PRINT_MASK_ALL;
664610e4a0Sfrits uint_t	usbprn_errlevel 	= USB_LOG_L4;
674610e4a0Sfrits uint_t	usbprn_instance_debug	= (uint_t)-1;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /* local variables */
707c478bd9Sstevel@tonic-gate static uint_t usbprn_ifcap =
717c478bd9Sstevel@tonic-gate 	PRN_HOTPLUG | PRN_1284_DEVID | PRN_1284_STATUS | PRN_TIMEOUTS;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Function Prototypes
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate static int	usbprn_attach(dev_info_t *, ddi_attach_cmd_t);
777c478bd9Sstevel@tonic-gate static int	usbprn_detach(dev_info_t *, ddi_detach_cmd_t);
787c478bd9Sstevel@tonic-gate static int	usbprn_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
797c478bd9Sstevel@tonic-gate static void	usbprn_cleanup(dev_info_t *, usbprn_state_t *);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static int	usbprn_get_descriptors(usbprn_state_t *);
827c478bd9Sstevel@tonic-gate static int	usbprn_get_device_id(usbprn_state_t *);
837c478bd9Sstevel@tonic-gate static int	usbprn_get_port_status(usbprn_state_t *);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static int	usbprn_open(dev_t *, int, int, cred_t *);
867c478bd9Sstevel@tonic-gate static int	usbprn_close(dev_t, int, int, cred_t *);
877c478bd9Sstevel@tonic-gate static int	usbprn_open_usb_pipes(usbprn_state_t *);
887c478bd9Sstevel@tonic-gate static void	usbprn_close_usb_pipes(usbprn_state_t *);
897c478bd9Sstevel@tonic-gate static int	usbprn_write(dev_t, struct uio *, cred_t *);
907c478bd9Sstevel@tonic-gate static int	usbprn_read(dev_t, struct uio *, cred_t *);
917c478bd9Sstevel@tonic-gate static int	usbprn_poll(dev_t, short, int, short *, struct pollhead **);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate static int	usbprn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
947c478bd9Sstevel@tonic-gate static void	usbprn_minphys(struct buf *);
957c478bd9Sstevel@tonic-gate static int	usbprn_strategy(struct buf *);
967c478bd9Sstevel@tonic-gate static int	usbprn_setparms(usbprn_state_t *, intptr_t arg, int);
977c478bd9Sstevel@tonic-gate static int	usbprn_getparms(usbprn_state_t *, intptr_t, int);
987c478bd9Sstevel@tonic-gate static void	usbprn_geterr(usbprn_state_t *, intptr_t, int);
997c478bd9Sstevel@tonic-gate static int	usbprn_testio(usbprn_state_t  *, int);
1007c478bd9Sstevel@tonic-gate static int	usbprn_ioctl_get_status(usbprn_state_t *);
1017c478bd9Sstevel@tonic-gate static int	usbprn_prnio_get_status(usbprn_state_t *, intptr_t, int);
1027c478bd9Sstevel@tonic-gate static int	usbprn_prnio_get_1284_status(usbprn_state_t *, intptr_t, int);
1037c478bd9Sstevel@tonic-gate static int	usbprn_prnio_get_ifcap(usbprn_state_t *, intptr_t, int);
1047c478bd9Sstevel@tonic-gate static int	usbprn_prnio_set_ifcap(usbprn_state_t *, intptr_t, int);
1057c478bd9Sstevel@tonic-gate static int	usbprn_prnio_get_ifinfo(usbprn_state_t *, intptr_t, int);
1067c478bd9Sstevel@tonic-gate static int	usbprn_prnio_get_1284_devid(usbprn_state_t *, intptr_t, int);
1077c478bd9Sstevel@tonic-gate static int	usbprn_prnio_get_timeouts(usbprn_state_t *, intptr_t, int);
1087c478bd9Sstevel@tonic-gate static int	usbprn_prnio_set_timeouts(usbprn_state_t *, intptr_t, int);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static void	usbprn_send_async_bulk_data(usbprn_state_t *);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate static void	usbprn_bulk_xfer_cb(usb_pipe_handle_t, usb_bulk_req_t *);
1137c478bd9Sstevel@tonic-gate static void	usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t,
1147c478bd9Sstevel@tonic-gate 		    usb_bulk_req_t *);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static void	usbprn_biodone(usbprn_state_t *, int, int);
1177c478bd9Sstevel@tonic-gate static char	usbprn_error_state(uchar_t);
1187c478bd9Sstevel@tonic-gate static void	usbprn_print_long(usbprn_state_t *, char *, int);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /* event handling */
1217c478bd9Sstevel@tonic-gate static	void	usbprn_restore_device_state(dev_info_t *, usbprn_state_t *);
1227c478bd9Sstevel@tonic-gate static	int	usbprn_disconnect_event_cb(dev_info_t *);
1237c478bd9Sstevel@tonic-gate static	int	usbprn_reconnect_event_cb(dev_info_t *);
1247c478bd9Sstevel@tonic-gate static	int	usbprn_cpr_suspend(dev_info_t *);
1257c478bd9Sstevel@tonic-gate static	void	usbprn_cpr_resume(dev_info_t *);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate static usb_event_t usbprn_events = {
1287c478bd9Sstevel@tonic-gate 	usbprn_disconnect_event_cb,
1297c478bd9Sstevel@tonic-gate 	usbprn_reconnect_event_cb,
1307c478bd9Sstevel@tonic-gate 	NULL, NULL
1317c478bd9Sstevel@tonic-gate };
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /* PM handling */
1347c478bd9Sstevel@tonic-gate static	void	usbprn_create_pm_components(dev_info_t *, usbprn_state_t *);
1357c478bd9Sstevel@tonic-gate static	int	usbprn_power(dev_info_t *, int comp, int level);
1367c478bd9Sstevel@tonic-gate static	int	usbprn_pwrlvl0(usbprn_state_t *);
1377c478bd9Sstevel@tonic-gate static	int	usbprn_pwrlvl1(usbprn_state_t *);
1387c478bd9Sstevel@tonic-gate static	int	usbprn_pwrlvl2(usbprn_state_t *);
1397c478bd9Sstevel@tonic-gate static	int	usbprn_pwrlvl3(usbprn_state_t *);
1407c478bd9Sstevel@tonic-gate static	void	usbprn_pm_busy_component(usbprn_state_t *);
1417c478bd9Sstevel@tonic-gate static	void	usbprn_pm_idle_component(usbprn_state_t *);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /* module loading stuff */
1447c478bd9Sstevel@tonic-gate struct cb_ops usbprn_cb_ops = {
1457c478bd9Sstevel@tonic-gate 	usbprn_open,		/* open  */
1467c478bd9Sstevel@tonic-gate 	usbprn_close,		/* close */
1477c478bd9Sstevel@tonic-gate 	nulldev,		/* strategy */
1487c478bd9Sstevel@tonic-gate 	nulldev,		/* print */
1497c478bd9Sstevel@tonic-gate 	nulldev,		/* dump */
1507c478bd9Sstevel@tonic-gate 	usbprn_read,		/* read */
1517c478bd9Sstevel@tonic-gate 	usbprn_write,		/* write */
1527c478bd9Sstevel@tonic-gate 	usbprn_ioctl,		/* ioctl */
1537c478bd9Sstevel@tonic-gate 	nulldev,		/* devmap */
1547c478bd9Sstevel@tonic-gate 	nulldev,		/* mmap */
1557c478bd9Sstevel@tonic-gate 	nulldev,		/* segmap */
1567c478bd9Sstevel@tonic-gate 	usbprn_poll,		/* poll */
1577c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
1587c478bd9Sstevel@tonic-gate 	NULL,			/* streamtab  */
1597c478bd9Sstevel@tonic-gate 	D_64BIT | D_MP
1607c478bd9Sstevel@tonic-gate };
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static struct dev_ops usbprn_ops = {
1637c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1647c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
1657c478bd9Sstevel@tonic-gate 	usbprn_info,		/* info */
1667c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
1677c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
1687c478bd9Sstevel@tonic-gate 	usbprn_attach,		/* attach */
1697c478bd9Sstevel@tonic-gate 	usbprn_detach,		/* detach */
1707c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
1717c478bd9Sstevel@tonic-gate 	&usbprn_cb_ops,		/* driver operations */
1727c478bd9Sstevel@tonic-gate 	NULL,			/* bus operations */
17319397407SSherry Moore 	usbprn_power,		/* power */
174*be529ebcSRaymond Chen 	ddi_quiesce_not_needed,	/* devo_quiesce */
1757c478bd9Sstevel@tonic-gate };
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static struct modldrv usbprnmodldrv =	{
1787c478bd9Sstevel@tonic-gate 	&mod_driverops,
17977e51571Sgongtian zhao - Sun Microsystems - Beijing China 	"USB printer client driver",
1807c478bd9Sstevel@tonic-gate 	&usbprn_ops
1817c478bd9Sstevel@tonic-gate };
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1847c478bd9Sstevel@tonic-gate 	MODREV_1,
1857c478bd9Sstevel@tonic-gate 	&usbprnmodldrv,
1867c478bd9Sstevel@tonic-gate 	NULL,
1877c478bd9Sstevel@tonic-gate };
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /* local variables */
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /* soft state structures */
1927c478bd9Sstevel@tonic-gate #define	USBPRN_INITIAL_SOFT_SPACE	1
1937c478bd9Sstevel@tonic-gate static void *usbprn_statep;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate static int usbprn_max_xfer_size = USBPRN_MAX_XFER_SIZE;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /* prnio support */
1987c478bd9Sstevel@tonic-gate static const char usbprn_prnio_ifinfo[] = PRN_USB;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate int
_init(void)2027c478bd9Sstevel@tonic-gate _init(void)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	int rval;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if ((rval = ddi_soft_state_init(&usbprn_statep,
2077c478bd9Sstevel@tonic-gate 	    sizeof (usbprn_state_t), USBPRN_INITIAL_SOFT_SPACE)) != 0) {
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		return (rval);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
2137c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&usbprn_statep);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	return (rval);
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate int
_fini(void)2217c478bd9Sstevel@tonic-gate _fini(void)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	int rval;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) != 0) {
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		return (rval);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&usbprn_statep);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	return (rval);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2377c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate /*
2447c478bd9Sstevel@tonic-gate  * usbprn_info:
2457c478bd9Sstevel@tonic-gate  *	Get minor number, soft state structure, etc.
2467c478bd9Sstevel@tonic-gate  */
2477c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2487c478bd9Sstevel@tonic-gate static int
usbprn_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2497c478bd9Sstevel@tonic-gate usbprn_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
2507c478bd9Sstevel@tonic-gate 			void *arg, void **result)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp;
2537c478bd9Sstevel@tonic-gate 	int		error = DDI_FAILURE;
2547c478bd9Sstevel@tonic-gate 	minor_t		minor = getminor((dev_t)arg);
2557c478bd9Sstevel@tonic-gate 	int		instance = USBPRN_MINOR_TO_INSTANCE(minor);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	switch (infocmd) {
2587c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2597c478bd9Sstevel@tonic-gate 		if ((usbprnp = ddi_get_soft_state(usbprn_statep,
2607c478bd9Sstevel@tonic-gate 		    instance)) != NULL) {
2617c478bd9Sstevel@tonic-gate 			*result = usbprnp->usbprn_dip;
2627c478bd9Sstevel@tonic-gate 			if (*result != NULL) {
2637c478bd9Sstevel@tonic-gate 				error = DDI_SUCCESS;
2647c478bd9Sstevel@tonic-gate 			}
2657c478bd9Sstevel@tonic-gate 		} else {
2667c478bd9Sstevel@tonic-gate 			*result = NULL;
2677c478bd9Sstevel@tonic-gate 		}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 		break;
2707c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2717c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
2727c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		break;
2757c478bd9Sstevel@tonic-gate 	default:
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		break;
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	return (error);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  * usbprn_attach:
2867c478bd9Sstevel@tonic-gate  *	Attach driver
2877c478bd9Sstevel@tonic-gate  *	Get the descriptor information
2887c478bd9Sstevel@tonic-gate  *	Get the device id
2897c478bd9Sstevel@tonic-gate  *	Reset the device
2907c478bd9Sstevel@tonic-gate  *	Get the port status
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate static int
usbprn_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2937c478bd9Sstevel@tonic-gate usbprn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
2967c478bd9Sstevel@tonic-gate 	usbprn_state_t		*usbprnp = NULL;
2977c478bd9Sstevel@tonic-gate 	size_t			sz;
2987c478bd9Sstevel@tonic-gate 	usb_ugen_info_t 	usb_ugen_info;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	switch (cmd) {
3017c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 		break;
3047c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
3057c478bd9Sstevel@tonic-gate 		usbprn_cpr_resume(dip);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3087c478bd9Sstevel@tonic-gate 	default:
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(usbprn_statep, instance) == DDI_SUCCESS) {
3147c478bd9Sstevel@tonic-gate 		usbprnp = ddi_get_soft_state(usbprn_statep, instance);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 	if (usbprnp == NULL)  {
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_instance = instance;
3227c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_dip	= dip;
3237c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_log_handle = usb_alloc_log_hdl(dip,
324112116d8Sfb 	    "prn", &usbprn_errlevel,
325112116d8Sfb 	    &usbprn_errmask, &usbprn_instance_debug, 0);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3287c478bd9Sstevel@tonic-gate 	    "usbprn_attach: cmd=%x", cmd);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
3317c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3327c478bd9Sstevel@tonic-gate 		    "usb_client_attach failed");
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		goto fail;
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 	if (usb_get_dev_data(dip, &usbprnp->usbprn_dev_data,
3377c478bd9Sstevel@tonic-gate 	    USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
3387c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3397c478bd9Sstevel@tonic-gate 		    "usb_get_dev_data failed");
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		goto fail;
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	/* Initialize locks and conditional variables */
3457c478bd9Sstevel@tonic-gate 	mutex_init(&usbprnp->usbprn_mutex, NULL, MUTEX_DRIVER,
346112116d8Sfb 	    usbprnp->usbprn_dev_data->dev_iblock_cookie);
3477c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_write_acc = usb_init_serialization(dip,
348112116d8Sfb 	    USB_INIT_SER_CHECK_SAME_THREAD);
3497c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_ser_acc = usb_init_serialization(dip,
3507c478bd9Sstevel@tonic-gate 	    USB_INIT_SER_CHECK_SAME_THREAD);
3517c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_dev_acc = usb_init_serialization(dip, 0);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_flags |= USBPRN_LOCKS_INIT_DONE;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* Obtain all the relevant descriptors */
3567c478bd9Sstevel@tonic-gate 	if (usbprn_get_descriptors(usbprnp) != USB_SUCCESS) {
3577c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3587c478bd9Sstevel@tonic-gate 		    "usb get descriptors failed");
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		goto fail;
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_def_ph = usbprnp->usbprn_dev_data->dev_default_ph;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/* Obtain the device id */
3667c478bd9Sstevel@tonic-gate 	(void) usbprn_get_device_id(usbprnp);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	/* Get the port status */
3697c478bd9Sstevel@tonic-gate 	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
3707c478bd9Sstevel@tonic-gate 		/* some printers fail on the first */
3717c478bd9Sstevel@tonic-gate 		if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
3727c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
3737c478bd9Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
3747c478bd9Sstevel@tonic-gate 			    "usb get port status failed");
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 			goto fail;
3777c478bd9Sstevel@tonic-gate 		}
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3817c478bd9Sstevel@tonic-gate 	    "usbprn_attach: printer status=0x%x", usbprnp->usbprn_last_status);
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	if ((usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR) == 0) {
3847c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3857c478bd9Sstevel@tonic-gate 		    "usbprn_attach: error occurred with the printer");
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	/*
3897c478bd9Sstevel@tonic-gate 	 * Create minor node based on information from the
3907c478bd9Sstevel@tonic-gate 	 * descriptors
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	if ((ddi_create_minor_node(dip, "printer", S_IFCHR,
3937c478bd9Sstevel@tonic-gate 	    instance << USBPRN_MINOR_INSTANCE_SHIFT,
3947c478bd9Sstevel@tonic-gate 	    DDI_NT_PRINTER, 0)) != DDI_SUCCESS) {
395d291d9f2Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3967c478bd9Sstevel@tonic-gate 		    "usbprn_attach: cannot create minor node");
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 		goto fail;
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_setparms.write_timeout = USBPRN_XFER_TIMEOUT;
4027c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_setparms.mode =  ECPP_CENTRONICS;
4037c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	if (usb_pipe_get_max_bulk_transfer_size(usbprnp->usbprn_dip, &sz)) {
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		goto fail;
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_max_bulk_xfer_size = sz;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
4137c478bd9Sstevel@tonic-gate 	    "usbprn_attach: xfer_size=0x%lx", sz);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/* enable PM */
4167c478bd9Sstevel@tonic-gate 	usbprn_create_pm_components(dip, usbprnp);
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	/* Register for events */
4197c478bd9Sstevel@tonic-gate 	if (usb_register_event_cbs(dip, &usbprn_events, 0) != USB_SUCCESS) {
420d291d9f2Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
4217c478bd9Sstevel@tonic-gate 		    "usbprn_attach: usb_register_event_cbs failed");
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 		goto fail;
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	usb_free_dev_data(dip, usbprnp->usbprn_dev_data);
4277c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_dev_data = NULL;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	if (usb_owns_device(dip)) {
4307c478bd9Sstevel@tonic-gate 		/* get a ugen handle */
4317c478bd9Sstevel@tonic-gate 		bzero(&usb_ugen_info, sizeof (usb_ugen_info));
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_flags = 0;
4347c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
435112116d8Sfb 		    (dev_t)USBPRN_MINOR_UGEN_BITS_MASK;
4367c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_instance_mask =
437112116d8Sfb 		    (dev_t)~USBPRN_MINOR_UGEN_BITS_MASK;
4387c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_ugen_hdl =
439112116d8Sfb 		    usb_ugen_get_hdl(dip, &usb_ugen_info);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		if (usb_ugen_attach(usbprnp->usbprn_ugen_hdl, cmd) !=
4427c478bd9Sstevel@tonic-gate 		    USB_SUCCESS) {
4437c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
4447c478bd9Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
4457c478bd9Sstevel@tonic-gate 			    "usb_ugen_attach failed");
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 			usb_ugen_release_hdl(usbprnp->usbprn_ugen_hdl);
4487c478bd9Sstevel@tonic-gate 			usbprnp->usbprn_ugen_hdl = NULL;
4497c478bd9Sstevel@tonic-gate 		}
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	/* Report device */
4537c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
4567c478bd9Sstevel@tonic-gate 	    "usbprn_attach: done");
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate fail:
4617c478bd9Sstevel@tonic-gate 	if (usbprnp) {
4627c478bd9Sstevel@tonic-gate 		usbprn_cleanup(dip, usbprnp);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate  * usbprn_detach:
4717c478bd9Sstevel@tonic-gate  *	detach or suspend driver instance
4727c478bd9Sstevel@tonic-gate  */
4737c478bd9Sstevel@tonic-gate static int
usbprn_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4747c478bd9Sstevel@tonic-gate usbprn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
4777c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp;
4787c478bd9Sstevel@tonic-gate 	int		rval = DDI_FAILURE;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	usbprnp = ddi_get_soft_state(usbprn_statep, instance);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
4837c478bd9Sstevel@tonic-gate 	    "usbprn_detach: cmd=%x", cmd);
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	switch (cmd) {
4867c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
4877c478bd9Sstevel@tonic-gate 		ASSERT((usbprnp->usbprn_flags & USBPRN_OPEN) == 0);
4887c478bd9Sstevel@tonic-gate 		usbprn_cleanup(dip, usbprnp);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4917c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
4927c478bd9Sstevel@tonic-gate 		rval = usbprn_cpr_suspend(dip);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS :
4957c478bd9Sstevel@tonic-gate 		    DDI_FAILURE);
4967c478bd9Sstevel@tonic-gate 	default:
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		return (rval);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate }
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate /*
5047c478bd9Sstevel@tonic-gate  * usbprn_cleanup:
5057c478bd9Sstevel@tonic-gate  *	clean up the driver state
5067c478bd9Sstevel@tonic-gate  */
5077c478bd9Sstevel@tonic-gate static void
usbprn_cleanup(dev_info_t * dip,usbprn_state_t * usbprnp)5087c478bd9Sstevel@tonic-gate usbprn_cleanup(dev_info_t *dip, usbprn_state_t *usbprnp)
5097c478bd9Sstevel@tonic-gate {
5107c478bd9Sstevel@tonic-gate 	usbprn_power_t	*usbprnpm = usbprnp->usbprn_pm;
5117c478bd9Sstevel@tonic-gate 	int		rval = 0;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
5147c478bd9Sstevel@tonic-gate 	    "usbprn_cleanup: Start");
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	ASSERT(usbprnp != NULL);
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_LOCKS_INIT_DONE) {
5197c478bd9Sstevel@tonic-gate 		/*
5207c478bd9Sstevel@tonic-gate 		 * Disable the event callbacks first, after this point, event
5217c478bd9Sstevel@tonic-gate 		 * callbacks will never get called. Note we shouldn't hold
5227c478bd9Sstevel@tonic-gate 		 * mutex while unregistering events because there may be a
5237c478bd9Sstevel@tonic-gate 		 * competing event callback thread. Event callbacks are done
5247c478bd9Sstevel@tonic-gate 		 * with ndi mutex held and this can cause a potential deadlock.
5257c478bd9Sstevel@tonic-gate 		 */
5267c478bd9Sstevel@tonic-gate 		usb_unregister_event_cbs(dip, &usbprn_events);
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
5297c478bd9Sstevel@tonic-gate 		if ((usbprnpm) &&
5307c478bd9Sstevel@tonic-gate 		    (usbprnp->usbprn_dev_state != USB_DEV_DISCONNECTED)) {
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 			mutex_exit(&usbprnp->usbprn_mutex);
5337c478bd9Sstevel@tonic-gate 			usbprn_pm_busy_component(usbprnp);
5347c478bd9Sstevel@tonic-gate 			mutex_enter(&usbprnp->usbprn_mutex);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 			if (usbprnpm->usbprn_wakeup_enabled) {
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 				mutex_exit(&usbprnp->usbprn_mutex);
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 				(void) pm_raise_power(dip, 0,
5417c478bd9Sstevel@tonic-gate 				    USB_DEV_OS_FULL_PWR);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 				if ((rval = usb_handle_remote_wakeup(dip,
5447c478bd9Sstevel@tonic-gate 				    USB_REMOTE_WAKEUP_DISABLE)) !=
5457c478bd9Sstevel@tonic-gate 				    USB_SUCCESS) {
5467c478bd9Sstevel@tonic-gate 					USB_DPRINTF_L2(PRINT_MASK_ALL,
5477c478bd9Sstevel@tonic-gate 					    usbprnp->usbprn_log_handle,
5487c478bd9Sstevel@tonic-gate 					    "usbprn_cleanup: "
5497c478bd9Sstevel@tonic-gate 					    "disable remote wakeup "
5507c478bd9Sstevel@tonic-gate 					    "failed, rval=%d", rval);
5517c478bd9Sstevel@tonic-gate 				}
5527c478bd9Sstevel@tonic-gate 			} else {
5537c478bd9Sstevel@tonic-gate 				mutex_exit(&usbprnp->usbprn_mutex);
5547c478bd9Sstevel@tonic-gate 			}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 			(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
5577c478bd9Sstevel@tonic-gate 			usbprn_pm_idle_component(usbprnp);
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 			mutex_enter(&usbprnp->usbprn_mutex);
5607c478bd9Sstevel@tonic-gate 		}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 		if (usbprnp->usbprn_device_id) {
5677c478bd9Sstevel@tonic-gate 			kmem_free(usbprnp->usbprn_device_id,
5687c478bd9Sstevel@tonic-gate 			    usbprnp->usbprn_device_id_len + 1);
5697c478bd9Sstevel@tonic-gate 		}
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 		mutex_destroy(&usbprnp->usbprn_mutex);
5727c478bd9Sstevel@tonic-gate 		usb_fini_serialization(usbprnp->usbprn_dev_acc);
5737c478bd9Sstevel@tonic-gate 		usb_fini_serialization(usbprnp->usbprn_ser_acc);
5747c478bd9Sstevel@tonic-gate 		usb_fini_serialization(usbprnp->usbprn_write_acc);
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	if (usbprnpm) {
5787c478bd9Sstevel@tonic-gate 		kmem_free(usbprnpm, sizeof (usbprn_power_t));
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
5827c478bd9Sstevel@tonic-gate 	    "usbprn_cleanup: End");
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_ugen_hdl) {
5857c478bd9Sstevel@tonic-gate 		(void) usb_ugen_detach(usbprnp->usbprn_ugen_hdl, DDI_DETACH);
5867c478bd9Sstevel@tonic-gate 		usb_ugen_release_hdl(usbprnp->usbprn_ugen_hdl);
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/* unregister with USBA */
5907c478bd9Sstevel@tonic-gate 	usb_client_detach(dip, usbprnp->usbprn_dev_data);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(usbprnp->usbprn_log_handle);
5937c478bd9Sstevel@tonic-gate 	ddi_prop_remove_all(dip);
5947c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(usbprn_statep, usbprnp->usbprn_instance);
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate /*
5997c478bd9Sstevel@tonic-gate  * usbprn_cpr_suspend:
6007c478bd9Sstevel@tonic-gate  *	prepare to be suspended
6017c478bd9Sstevel@tonic-gate  */
6027c478bd9Sstevel@tonic-gate static int
usbprn_cpr_suspend(dev_info_t * dip)6037c478bd9Sstevel@tonic-gate usbprn_cpr_suspend(dev_info_t *dip)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp;
6067c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
6077c478bd9Sstevel@tonic-gate 	int		rval = USB_FAILURE;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	usbprnp = ddi_get_soft_state(usbprn_statep, instance);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
6127c478bd9Sstevel@tonic-gate 	    "usbprn_cpr_suspend");
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	if ((usbprnp->usbprn_flags & USBPRN_OPEN) != 0) {
6197c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_CPR,
6227c478bd9Sstevel@tonic-gate 		    usbprnp->usbprn_log_handle,
6237c478bd9Sstevel@tonic-gate 		    "usbprn_cpr_suspend: "
6247c478bd9Sstevel@tonic-gate 		    "Device is open.  Can't suspend");
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	} else {
6277c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_dev_state = USB_DEV_SUSPENDED;
6287c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
6317c478bd9Sstevel@tonic-gate 		    "usbprn_cpr_suspend: SUCCESS");
6327c478bd9Sstevel@tonic-gate 		rval = USB_SUCCESS;
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && usbprnp->usbprn_ugen_hdl) {
6377c478bd9Sstevel@tonic-gate 		rval = usb_ugen_detach(usbprnp->usbprn_ugen_hdl,
638112116d8Sfb 		    DDI_SUSPEND);
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	return (rval);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate static void
usbprn_cpr_resume(dev_info_t * dip)6467c478bd9Sstevel@tonic-gate usbprn_cpr_resume(dev_info_t *dip)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
6497c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep, instance);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
6527c478bd9Sstevel@tonic-gate 	    "usbprn_cpr_resume");
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	/* Needed as power up state of dev is "unknown" to system */
6557c478bd9Sstevel@tonic-gate 	usbprn_pm_busy_component(usbprnp);
6567c478bd9Sstevel@tonic-gate 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	usbprn_restore_device_state(dip, usbprnp);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	usbprn_pm_idle_component(usbprnp);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_ugen_hdl) {
6637c478bd9Sstevel@tonic-gate 		(void) usb_ugen_attach(usbprnp->usbprn_ugen_hdl,
664112116d8Sfb 		    DDI_RESUME);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate /*
6707c478bd9Sstevel@tonic-gate  * usbprn_get_descriptors:
6717c478bd9Sstevel@tonic-gate  *	Obtain all the descriptors for the device
6727c478bd9Sstevel@tonic-gate  */
6737c478bd9Sstevel@tonic-gate static int
usbprn_get_descriptors(usbprn_state_t * usbprnp)6747c478bd9Sstevel@tonic-gate usbprn_get_descriptors(usbprn_state_t *usbprnp)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	int			interface;
6777c478bd9Sstevel@tonic-gate 	usb_client_dev_data_t	*dev_data =
678112116d8Sfb 	    usbprnp->usbprn_dev_data;
6797c478bd9Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
6807c478bd9Sstevel@tonic-gate 	usb_cfg_data_t		*cfg_data;
6817c478bd9Sstevel@tonic-gate 	usb_ep_data_t		*ep_data;
6827c478bd9Sstevel@tonic-gate 	dev_info_t		*dip = usbprnp->usbprn_dip;
6837c478bd9Sstevel@tonic-gate 	int			alt, rval;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	/*
6887c478bd9Sstevel@tonic-gate 	 * Section 4.2.1 of the spec says the printer could have
6897c478bd9Sstevel@tonic-gate 	 * multiple configurations.  This driver is just for one
6907c478bd9Sstevel@tonic-gate 	 * configuration interface and one interface.
6917c478bd9Sstevel@tonic-gate 	 */
6927c478bd9Sstevel@tonic-gate 	interface = dev_data->dev_curr_if;
6937c478bd9Sstevel@tonic-gate 	cfg_data = dev_data->dev_curr_cfg;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	/* find alternate that supports BI/UNI protocol */
6967c478bd9Sstevel@tonic-gate 	for (alt = 0; alt < cfg_data->cfg_if[interface].if_n_alt; alt++) {
6977c478bd9Sstevel@tonic-gate 		altif_data = &cfg_data->cfg_if[interface].if_alt[alt];
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 		if ((altif_data->altif_descr.bInterfaceProtocol ==
7007c478bd9Sstevel@tonic-gate 		    USB_PROTO_PRINTER_UNI) ||
7017c478bd9Sstevel@tonic-gate 		    (altif_data->altif_descr.bInterfaceProtocol ==
7027c478bd9Sstevel@tonic-gate 		    USB_PROTO_PRINTER_BI)) {
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 			break;
7057c478bd9Sstevel@tonic-gate 		} else {
7067c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA,
7077c478bd9Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
7087c478bd9Sstevel@tonic-gate 			    "alternate %d not supported", alt);
7097c478bd9Sstevel@tonic-gate 		}
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	if (alt == cfg_data->cfg_if[interface].if_n_alt) {
7137c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
7147c478bd9Sstevel@tonic-gate 		    "usbprn_get_descriptors: no alternate");
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	if ((rval = usb_set_alt_if(dip, interface, alt, USB_FLAGS_SLEEP,
7217c478bd9Sstevel@tonic-gate 	    NULL, NULL)) != USB_SUCCESS) {
7227c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
7237c478bd9Sstevel@tonic-gate 		    "usbprn_get_descriptors: set alternate failed (%d)",
7247c478bd9Sstevel@tonic-gate 		    rval);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 		return (rval);
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_config_descr = cfg_data->cfg_descr;
7307c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_if_descr = altif_data->altif_descr;
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	/*
7337c478bd9Sstevel@tonic-gate 	 * find the endpoint descriptors. There will be a bulk-out endpoint
7347c478bd9Sstevel@tonic-gate 	 * and an optional bulk-in endpoint.
7357c478bd9Sstevel@tonic-gate 	 */
7367c478bd9Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, alt, 0,
7377c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
7387c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_bulk_out.ps_ept_descr = ep_data->ep_descr;
7397c478bd9Sstevel@tonic-gate 	}
7407c478bd9Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, alt, 0,
7417c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
7427c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_bulk_in.ps_ept_descr = ep_data->ep_descr;
7437c478bd9Sstevel@tonic-gate 	}
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
7467c478bd9Sstevel@tonic-gate }
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate  * usbprn_get_device_id:
7517c478bd9Sstevel@tonic-gate  *	Get the device id as described in 4.2.1 of the specification
7527c478bd9Sstevel@tonic-gate  *	Lexmark printer returns 2 bytes when asked for 8 bytes
7537c478bd9Sstevel@tonic-gate  *	We are ignoring data over and underrun.
7547c478bd9Sstevel@tonic-gate  *	This is a synchronous function
7557c478bd9Sstevel@tonic-gate  */
7567c478bd9Sstevel@tonic-gate static int
usbprn_get_device_id(usbprn_state_t * usbprnp)7577c478bd9Sstevel@tonic-gate usbprn_get_device_id(usbprn_state_t *usbprnp)
7587c478bd9Sstevel@tonic-gate {
7597c478bd9Sstevel@tonic-gate 	int			len, n;
7607c478bd9Sstevel@tonic-gate 	mblk_t			*data = NULL;
7617c478bd9Sstevel@tonic-gate 	usb_cr_t		completion_reason;
7627c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags;
7637c478bd9Sstevel@tonic-gate 	int			rval = USB_FAILURE;
7647c478bd9Sstevel@tonic-gate 	usb_ctrl_setup_t setup = {
7657c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST |	/* bmRequestType */
766112116d8Sfb 	    USB_DEV_REQ_TYPE_CLASS |
767112116d8Sfb 	    USB_DEV_REQ_RCPT_IF,
7687c478bd9Sstevel@tonic-gate 	    USB_PRINTER_GET_DEVICE_ID,	/* bRequest */
7697c478bd9Sstevel@tonic-gate 	    0,				/* wValue: fill in later */
7707c478bd9Sstevel@tonic-gate 	    0,				/* wIndex: fill in later  */
7717c478bd9Sstevel@tonic-gate 	    0,				/* wLength: fill in later */
7727c478bd9Sstevel@tonic-gate 	    0				/* attributes */
773112116d8Sfb 	    };
7747c478bd9Sstevel@tonic-gate 	void			*ptr;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
7777c478bd9Sstevel@tonic-gate 	    "usbprn_get_device_id: Begin");
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	setup.wIndex = (usbprnp->usbprn_if_descr.bInterfaceNumber << 0x8) |
782112116d8Sfb 	    (usbprnp->usbprn_if_descr.bAlternateSetting);
7837c478bd9Sstevel@tonic-gate 	setup.wLength = USBPRN_MAX_DEVICE_ID_LENGTH;
7847c478bd9Sstevel@tonic-gate 	setup.wValue = usbprnp->usbprn_config_descr.iConfiguration;
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	/*
7877c478bd9Sstevel@tonic-gate 	 * This is always a sync request as this will never
7887c478bd9Sstevel@tonic-gate 	 * be called in interrupt context.
7897c478bd9Sstevel@tonic-gate 	 * First get the first two bytes that gives the length
7907c478bd9Sstevel@tonic-gate 	 * of the device id string; then get the whole string
7917c478bd9Sstevel@tonic-gate 	 */
7927c478bd9Sstevel@tonic-gate 	if (usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph, &setup,
7937c478bd9Sstevel@tonic-gate 	    &data, &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
7967c478bd9Sstevel@tonic-gate 		    "usbprn_get_device_id: First sync command failed, cr=%d ",
7977c478bd9Sstevel@tonic-gate 		    completion_reason);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		/*
8007c478bd9Sstevel@tonic-gate 		 * some devices return more than requested. as long as
8017c478bd9Sstevel@tonic-gate 		 * we get the first two bytes, we can continue
8027c478bd9Sstevel@tonic-gate 		 */
8037c478bd9Sstevel@tonic-gate 		if (((completion_reason != USB_CR_DATA_OVERRUN) &&
8047c478bd9Sstevel@tonic-gate 		    (completion_reason != USB_CR_DATA_UNDERRUN)) ||
8057c478bd9Sstevel@tonic-gate 		    (data == NULL)) {
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 			goto done;
8087c478bd9Sstevel@tonic-gate 		}
8097c478bd9Sstevel@tonic-gate 	}
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	ASSERT(data);
812d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	n = MBLKL(data);
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	if (n < 2) {
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 		goto done;
8177c478bd9Sstevel@tonic-gate 	}
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	len = (((*data->b_rptr) << 0x8) | (*(data->b_rptr+1)));
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	/*
8227c478bd9Sstevel@tonic-gate 	 * Std 1284-1994, chapter 7.6:
8237c478bd9Sstevel@tonic-gate 	 *	Length values of x'0000', x'0001' and x'0002' are reserved
8247c478bd9Sstevel@tonic-gate 	 */
8257c478bd9Sstevel@tonic-gate 	if (len < 3) {
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 		goto done;
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
8317c478bd9Sstevel@tonic-gate 	    "usbprn_get_device_id: device id length=%d", len);
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	/* did we get enough data */
8347c478bd9Sstevel@tonic-gate 	if (len > n) {
8357c478bd9Sstevel@tonic-gate 		freemsg(data);
8367c478bd9Sstevel@tonic-gate 		data = NULL;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 		setup.wLength = (uint16_t)len;
8397c478bd9Sstevel@tonic-gate 		if ((rval = usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph,
8407c478bd9Sstevel@tonic-gate 		    &setup, &data, &completion_reason, &cb_flags, 0)) !=
8417c478bd9Sstevel@tonic-gate 		    USB_SUCCESS) {
8427c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
8437c478bd9Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
8447c478bd9Sstevel@tonic-gate 			    "usbprn_get_device_id: 2nd command failed "
8457c478bd9Sstevel@tonic-gate 			    "cr=%d cb_flags=0x%x",
8467c478bd9Sstevel@tonic-gate 			    completion_reason, cb_flags);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 			goto done;
8497c478bd9Sstevel@tonic-gate 		}
8507c478bd9Sstevel@tonic-gate 
851d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		ASSERT(len == MBLKL(data));
8527c478bd9Sstevel@tonic-gate 	}
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
855112116d8Sfb 	    "usbprn_get_device_id: returned data length=%ld",
856d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (long)(MBLKL(data)));
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	ptr = kmem_zalloc(len + 1, KM_SLEEP);
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
8617c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_device_id_len = len;
8627c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_device_id = ptr;
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	bcopy(data->b_rptr, usbprnp->usbprn_device_id,
865112116d8Sfb 	    usbprnp->usbprn_device_id_len);
8667c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_device_id[usbprnp->usbprn_device_id_len] = '\0';
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	/* Length is in the first two bytes, dump string in logbuf */
8697c478bd9Sstevel@tonic-gate 	usbprn_print_long(usbprnp, usbprnp->usbprn_device_id + 2,
8707c478bd9Sstevel@tonic-gate 	    usbprnp->usbprn_device_id_len - 2);
8717c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	rval = USB_SUCCESS;
8747c478bd9Sstevel@tonic-gate done:
8757c478bd9Sstevel@tonic-gate 	freemsg(data);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
8787c478bd9Sstevel@tonic-gate 	    "usbprn_get_device_id: rval=%d", rval);
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	return (rval);
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate  * usbprn_get_port_status:
8867c478bd9Sstevel@tonic-gate  *	Get the port status.
8877c478bd9Sstevel@tonic-gate  *	This is a synchronous function
8887c478bd9Sstevel@tonic-gate  */
8897c478bd9Sstevel@tonic-gate static int
usbprn_get_port_status(usbprn_state_t * usbprnp)8907c478bd9Sstevel@tonic-gate usbprn_get_port_status(usbprn_state_t  *usbprnp)
8917c478bd9Sstevel@tonic-gate {
8927c478bd9Sstevel@tonic-gate 	mblk_t			*data = NULL;
8937c478bd9Sstevel@tonic-gate 	usb_cr_t		completion_reason;
8947c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags;
8957c478bd9Sstevel@tonic-gate 	usb_ctrl_setup_t setup = {
8967c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST |	/* bmRequestType */
897112116d8Sfb 	    USB_DEV_REQ_TYPE_CLASS |
898112116d8Sfb 	    USB_DEV_REQ_RCPT_IF,
8997c478bd9Sstevel@tonic-gate 	    USB_PRINTER_GET_PORT_STATUS, /* bRequest */
9007c478bd9Sstevel@tonic-gate 	    0,				/* wValue */
9017c478bd9Sstevel@tonic-gate 	    0,				/* wIndex: fill in later  */
9027c478bd9Sstevel@tonic-gate 	    1,				/* wLength */
9037c478bd9Sstevel@tonic-gate 	    0				/* attributes */
904112116d8Sfb 	    };
9057c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
9087c478bd9Sstevel@tonic-gate 	    "usbprn_get_port_status: Begin");
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	setup.wIndex = usbprnp->usbprn_if_descr.bInterfaceNumber;
9117c478bd9Sstevel@tonic-gate 	if (usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph,
9127c478bd9Sstevel@tonic-gate 	    &setup, &data, &completion_reason, &cb_flags, 0) !=
9137c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
9147c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
9157c478bd9Sstevel@tonic-gate 		    "usbprn_get_port_status: Sync command failed "
9167c478bd9Sstevel@tonic-gate 		    "cr=%d cb_flags=0x%x", completion_reason, cb_flags);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		freemsg(data);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
9217c478bd9Sstevel@tonic-gate 	} else {
9227c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 		ASSERT(data);
925d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		ASSERT(MBLKL(data) == 1);
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_last_status = *data->b_rptr;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
9307c478bd9Sstevel@tonic-gate 		    "usbprn_get_port_status(sync): status=0x%x",
9317c478bd9Sstevel@tonic-gate 		    usbprnp->usbprn_last_status);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9347c478bd9Sstevel@tonic-gate 		freemsg(data);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate /*
9427c478bd9Sstevel@tonic-gate  * usbprn_open:
9437c478bd9Sstevel@tonic-gate  *	Open the pipes
9447c478bd9Sstevel@tonic-gate  */
9457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9467c478bd9Sstevel@tonic-gate static int
usbprn_open(dev_t * devp,int flag,int sflag,cred_t * credp)9477c478bd9Sstevel@tonic-gate usbprn_open(dev_t *devp, int flag, int sflag, cred_t *credp)
9487c478bd9Sstevel@tonic-gate {
9497c478bd9Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
950112116d8Sfb 	    USBPRN_MINOR_TO_INSTANCE(getminor(*devp)));
9517c478bd9Sstevel@tonic-gate 	int rval = 0;
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	if (usbprnp == NULL) {
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 		return (ENXIO);
9567c478bd9Sstevel@tonic-gate 	}
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
9597c478bd9Sstevel@tonic-gate 	    "usbprn_open:");
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	/* Fail open on a disconnected device */
9647c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
9657c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED) {
9667c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9677c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 		return (ENODEV);
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	/* cannot happen? but just in case */
9737c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_dev_state == USB_DEV_SUSPENDED) {
9747c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9757c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 		return (EIO);
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	if (getminor(*devp) & USBPRN_MINOR_UGEN_BITS_MASK) {
9817c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 		rval = usb_ugen_open(usbprnp->usbprn_ugen_hdl,
984112116d8Sfb 		    devp, flag, sflag, credp);
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		return (rval);
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	/* Exit if this instance is already open */
9927c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
9937c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9947c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 		return (EBUSY);
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	/* raise power */
10017c478bd9Sstevel@tonic-gate 	usbprn_pm_busy_component(usbprnp);
10027c478bd9Sstevel@tonic-gate 	(void) pm_raise_power(usbprnp->usbprn_dip,
1003112116d8Sfb 	    0, USB_DEV_OS_FULL_PWR);
10047c478bd9Sstevel@tonic-gate 	/* initialize some softstate data */
10057c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
10067c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_prn_timeouts.tmo_forward =
1007112116d8Sfb 	    usbprnp->usbprn_setparms.write_timeout;
10087c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_prn_timeouts.tmo_reverse = 0;
10097c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	if (usbprn_open_usb_pipes(usbprnp) != USB_SUCCESS) {
10127c478bd9Sstevel@tonic-gate 
1013d291d9f2Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
10147c478bd9Sstevel@tonic-gate 		    "usbprn_open: pipe open failed");
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
10177c478bd9Sstevel@tonic-gate 		usbprn_pm_idle_component(usbprnp);
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 		return (EIO);
10207c478bd9Sstevel@tonic-gate 	}
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
10237c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_flags |= USBPRN_OPEN;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	/* set last status to online */
10267c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_last_status &= ~USB_PRINTER_PORT_NO_SELECT;
10277c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
10327c478bd9Sstevel@tonic-gate 	    "usbprn_open: End");
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	return (rval);
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate /*
10397c478bd9Sstevel@tonic-gate  * usbprn_close:
10407c478bd9Sstevel@tonic-gate  *	Close the pipes
10417c478bd9Sstevel@tonic-gate  */
10427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10437c478bd9Sstevel@tonic-gate static int
usbprn_close(dev_t dev,int flag,int otyp,cred_t * credp)10447c478bd9Sstevel@tonic-gate usbprn_close(dev_t dev, int flag, int otyp, cred_t *credp)
10457c478bd9Sstevel@tonic-gate {
10467c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep,
1047112116d8Sfb 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
10487c478bd9Sstevel@tonic-gate 	int		rval = 0;
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	if (usbprnp == NULL) {
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 		return (ENXIO);
10537c478bd9Sstevel@tonic-gate 	}
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbprnp->usbprn_log_handle,
10567c478bd9Sstevel@tonic-gate 	    "usbprn_close:");
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
10597c478bd9Sstevel@tonic-gate 		rval = usb_ugen_close(usbprnp->usbprn_ugen_hdl,
1060112116d8Sfb 		    dev, flag, otyp, credp);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 		return (rval);
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	/* avoid races with connect/disconnect */
10667c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
10677c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_dev_acc, USB_WAIT, 0);
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	/* Close all usb pipes */
10707c478bd9Sstevel@tonic-gate 	usbprn_close_usb_pipes(usbprnp);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	/* prevent any accesses by setting flags to closed */
10737c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
10747c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_flags &= ~USBPRN_OPEN;
10757c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_dev_acc);
10787c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	usbprn_pm_idle_component(usbprnp);
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbprnp->usbprn_log_handle,
10837c478bd9Sstevel@tonic-gate 	    "usbprn_close: End");
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	return (rval);
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate /*
10907c478bd9Sstevel@tonic-gate  * usbprn_read:
10917c478bd9Sstevel@tonic-gate  *	Read entry point (TBD)
10927c478bd9Sstevel@tonic-gate  */
10937c478bd9Sstevel@tonic-gate /* ARGSUSED */
10947c478bd9Sstevel@tonic-gate static int
usbprn_read(dev_t dev,struct uio * uiop,cred_t * credp)10957c478bd9Sstevel@tonic-gate usbprn_read(dev_t dev, struct uio *uiop, cred_t *credp)
10967c478bd9Sstevel@tonic-gate {
10977c478bd9Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1098112116d8Sfb 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	if (usbprnp == NULL) {
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 		return (ENXIO);
11037c478bd9Sstevel@tonic-gate 	}
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
11067c478bd9Sstevel@tonic-gate 		int rval;
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 		/* raise power */
11097c478bd9Sstevel@tonic-gate 		usbprn_pm_busy_component(usbprnp);
11107c478bd9Sstevel@tonic-gate 		(void) pm_raise_power(usbprnp->usbprn_dip,
1111112116d8Sfb 		    0, USB_DEV_OS_FULL_PWR);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 		if (usb_serialize_access(usbprnp->usbprn_write_acc,
11147c478bd9Sstevel@tonic-gate 		    USB_WAIT_SIG, 0) == 0) {
11157c478bd9Sstevel@tonic-gate 			usbprn_pm_idle_component(usbprnp);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 			return (EINTR);
11187c478bd9Sstevel@tonic-gate 		}
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 		rval = usb_ugen_read(usbprnp->usbprn_ugen_hdl, dev,
1121112116d8Sfb 		    uiop, credp);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_write_acc);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 		usbprn_pm_idle_component(usbprnp);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 		return (rval);
11287c478bd9Sstevel@tonic-gate 	}
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	/* Do a bulk-in from the printer */
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	return (EIO);
11337c478bd9Sstevel@tonic-gate }
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate /*
11377c478bd9Sstevel@tonic-gate  * usbprn_write:
11387c478bd9Sstevel@tonic-gate  *	Write to the printer
11397c478bd9Sstevel@tonic-gate  */
11407c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
11417c478bd9Sstevel@tonic-gate static int
usbprn_write(dev_t dev,struct uio * uiop,cred_t * credp)11427c478bd9Sstevel@tonic-gate usbprn_write(dev_t dev, struct uio *uiop, cred_t *credp)
11437c478bd9Sstevel@tonic-gate {
11447c478bd9Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1145112116d8Sfb 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
11467c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
11477c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
11487c478bd9Sstevel@tonic-gate 	int		rval;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	if (usbprnp == NULL) {
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 		return (ENXIO);
11537c478bd9Sstevel@tonic-gate 	}
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1156112116d8Sfb 	    "usbprn_write: Begin usbprnp=0x%p ", (void *)usbprnp);
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
11597c478bd9Sstevel@tonic-gate 		/* raise power */
11607c478bd9Sstevel@tonic-gate 		usbprn_pm_busy_component(usbprnp);
11617c478bd9Sstevel@tonic-gate 		(void) pm_raise_power(usbprnp->usbprn_dip,
1162112116d8Sfb 		    0, USB_DEV_OS_FULL_PWR);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 		if (usb_serialize_access(usbprnp->usbprn_write_acc,
11657c478bd9Sstevel@tonic-gate 		    USB_WAIT_SIG, 0) == 0) {
11667c478bd9Sstevel@tonic-gate 			usbprn_pm_idle_component(usbprnp);
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 			return (EINTR);
11697c478bd9Sstevel@tonic-gate 		}
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 		rval = usb_ugen_write(usbprnp->usbprn_ugen_hdl, dev,
1172112116d8Sfb 		    uiop, credp);
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_write_acc);
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 		usbprn_pm_idle_component(usbprnp);
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 		return (rval);
11797c478bd9Sstevel@tonic-gate 	}
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	/*
11827c478bd9Sstevel@tonic-gate 	 * serialize writes
11837c478bd9Sstevel@tonic-gate 	 * we cannot use usbprn_ser_acc sync object at this point because
11847c478bd9Sstevel@tonic-gate 	 * that would block out the ioctls for the full duration of the write.
11857c478bd9Sstevel@tonic-gate 	 */
11867c478bd9Sstevel@tonic-gate 	if (usb_serialize_access(usbprnp->usbprn_write_acc,
11877c478bd9Sstevel@tonic-gate 	    USB_WAIT_SIG, 0) == 0) {
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 		return (EINTR);
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	/*
11937c478bd9Sstevel@tonic-gate 	 * Check the status of the pipe.  If it's not idle,
11947c478bd9Sstevel@tonic-gate 	 * then wait.
11957c478bd9Sstevel@tonic-gate 	 */
11967c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	/* if device is disconnected or pipes closed, fail immediately */
11997c478bd9Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
12007c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
12037c478bd9Sstevel@tonic-gate 		    "usbprn_write: device can't be accessed");
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_write_acc);
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 		return (EIO);
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	/* all pipes must be idle */
12117c478bd9Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
12127c478bd9Sstevel@tonic-gate 	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	/*
12177c478bd9Sstevel@tonic-gate 	 * Call physio to do the transfer.  physio will
12187c478bd9Sstevel@tonic-gate 	 * call the strategy routine, and then call
12197c478bd9Sstevel@tonic-gate 	 * biowait() to block until the transfer completes.
12207c478bd9Sstevel@tonic-gate 	 */
12217c478bd9Sstevel@tonic-gate 	rval = physio(usbprn_strategy, (struct buf *)0, dev,
12227c478bd9Sstevel@tonic-gate 	    B_WRITE, usbprn_minphys, uiop);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_write_acc);
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
12277c478bd9Sstevel@tonic-gate 	    "usbprn_write: End");
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	return (rval);
12307c478bd9Sstevel@tonic-gate }
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate /*
12347c478bd9Sstevel@tonic-gate  * usbprn_poll
12357c478bd9Sstevel@tonic-gate  */
12367c478bd9Sstevel@tonic-gate static int
usbprn_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)12377c478bd9Sstevel@tonic-gate usbprn_poll(dev_t dev, short events,
12387c478bd9Sstevel@tonic-gate     int anyyet,  short *reventsp, struct pollhead **phpp)
12397c478bd9Sstevel@tonic-gate {
12407c478bd9Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1241112116d8Sfb 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	if (usbprnp == NULL) {
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 		return (ENXIO);
12467c478bd9Sstevel@tonic-gate 	}
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
12497c478bd9Sstevel@tonic-gate 		return (usb_ugen_poll(usbprnp->usbprn_ugen_hdl, dev, events,
1250112116d8Sfb 		    anyyet, reventsp, phpp));
12517c478bd9Sstevel@tonic-gate 	}
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	return (ENXIO);
12547c478bd9Sstevel@tonic-gate }
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate /*
12587c478bd9Sstevel@tonic-gate  * usbprn_strategy:
12597c478bd9Sstevel@tonic-gate  *	service a request to the device.
12607c478bd9Sstevel@tonic-gate  */
12617c478bd9Sstevel@tonic-gate static int
usbprn_strategy(struct buf * bp)12627c478bd9Sstevel@tonic-gate usbprn_strategy(struct buf *bp)
12637c478bd9Sstevel@tonic-gate {
12647c478bd9Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1265112116d8Sfb 	    USBPRN_MINOR_TO_INSTANCE(getminor(bp->b_edev)));
12667c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	bp_mapin(bp);
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/*
12717c478bd9Sstevel@tonic-gate 	 * serialize to avoid races
12727c478bd9Sstevel@tonic-gate 	 * access is released in usbprn_biodone()
12737c478bd9Sstevel@tonic-gate 	 */
12747c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_dev_acc, USB_WAIT, 0);
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
12777c478bd9Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
12787c478bd9Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
12797c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
12827c478bd9Sstevel@tonic-gate 		    "usbprn_strategy: device can't be accessed");
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 		return (0);
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	bulk_out->ps_flags = USBPRN_PS_NEED_TO_XFER;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	ASSERT(usbprnp->usbprn_bp == NULL);
12907c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_bp = bp;
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
12937c478bd9Sstevel@tonic-gate 	    "usbprn_strategy: usbprnp=0x%p bp=0x%p count=%lu",
1294112116d8Sfb 	    (void *)usbprnp, (void *)bp, bp->b_bcount);
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	ASSERT(usbprnp->usbprn_bulk_mp == NULL);
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_bulk_mp = allocb(bp->b_bcount, BPRI_HI);
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_bulk_mp == NULL) {
13017c478bd9Sstevel@tonic-gate 		bulk_out->ps_flags = USBPRN_PS_IDLE;
13027c478bd9Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
13037c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
13067c478bd9Sstevel@tonic-gate 		    "usbprn_strategy: allocb failed");
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 		return (0);
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)bp->b_un.b_addr,
1312112116d8Sfb 	    usbprnp->usbprn_bulk_mp->b_datap->db_base, bp->b_bcount);
13137c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_bulk_mp->b_wptr += bp->b_bcount;
13147c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	usbprn_send_async_bulk_data(usbprnp);
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	return (0);
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate /*
13237c478bd9Sstevel@tonic-gate  * usbprn_ioctl:
13247c478bd9Sstevel@tonic-gate  *	handle the ioctl
13257c478bd9Sstevel@tonic-gate  */
13267c478bd9Sstevel@tonic-gate /*ARGSUSED4*/
13277c478bd9Sstevel@tonic-gate static int
usbprn_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * credp,int * rvalp)13287c478bd9Sstevel@tonic-gate usbprn_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
13297c478bd9Sstevel@tonic-gate 		cred_t *credp, int *rvalp)
13307c478bd9Sstevel@tonic-gate {
13317c478bd9Sstevel@tonic-gate 	int		err = 0;
13327c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep,
1333112116d8Sfb 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
13347c478bd9Sstevel@tonic-gate 	struct ecpp_device_id	usbprn_devid;
13357c478bd9Sstevel@tonic-gate 	int		len;
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
13387c478bd9Sstevel@tonic-gate 	    "usbprn_ioctl: Begin ");
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
13417c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	/*
13447c478bd9Sstevel@tonic-gate 	 * only for PRNIOC_GET_STATUS cmd:
13457c478bd9Sstevel@tonic-gate 	 * if device is disconnected or pipes closed, fail immediately
13467c478bd9Sstevel@tonic-gate 	 */
13477c478bd9Sstevel@tonic-gate 	if ((cmd == PRNIOC_GET_STATUS) &&
13487c478bd9Sstevel@tonic-gate 	    !(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
13497c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
13527c478bd9Sstevel@tonic-gate 		    "usbprn_write: device can't be accessed");
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 		return (EIO);
13577c478bd9Sstevel@tonic-gate 	}
13587c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	switch (cmd) {
13617c478bd9Sstevel@tonic-gate 	case ECPPIOC_GETDEVID:
13627c478bd9Sstevel@tonic-gate 		/*
13637c478bd9Sstevel@tonic-gate 		 * With genericized ioctls this interface should change.
13647c478bd9Sstevel@tonic-gate 		 * We ignore the mode in USB printer driver because
13657c478bd9Sstevel@tonic-gate 		 * it need not be in nibble mode in usb driver unlike
13667c478bd9Sstevel@tonic-gate 		 * ecpp to retrieve the device id string. Also we do
13677c478bd9Sstevel@tonic-gate 		 * not expect the application to call this twice since
13687c478bd9Sstevel@tonic-gate 		 * it doesn't change since attach time and we take care
13697c478bd9Sstevel@tonic-gate 		 * of calling it twice: once for getting the length and
13707c478bd9Sstevel@tonic-gate 		 * once for getting the actual device id string. So we
13717c478bd9Sstevel@tonic-gate 		 * set both the lengths to actual device id string length.
13727c478bd9Sstevel@tonic-gate 		 * Ref: PSARC/2000/018
13737c478bd9Sstevel@tonic-gate 		 */
13747c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
13757c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl: ECPPIOC_GETDEVID(0x%x)", cmd);
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 		bzero(&usbprn_devid, sizeof (usbprn_devid));
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 		ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
13807c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
13817c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
13827c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32: {
13837c478bd9Sstevel@tonic-gate 			struct ecpp_device_id32	usbprn_devid32;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 			if (ddi_copyin((caddr_t)arg, &usbprn_devid32,
13867c478bd9Sstevel@tonic-gate 			    sizeof (struct ecpp_device_id32), flag)) {
13877c478bd9Sstevel@tonic-gate 				err = EFAULT;
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 				break;
13907c478bd9Sstevel@tonic-gate 			}
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 			if (usbprnp->usbprn_device_id == NULL) {
13937c478bd9Sstevel@tonic-gate 				err = EIO;
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 				break;
13967c478bd9Sstevel@tonic-gate 			}
13977c478bd9Sstevel@tonic-gate 			ASSERT(usbprnp->usbprn_device_id_len > 2);
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 			usbprn_devid32.rlen = usbprnp->usbprn_device_id_len - 2;
14007c478bd9Sstevel@tonic-gate 			len = min(usbprn_devid32.len, usbprn_devid32.rlen);
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 			if (ddi_copyout(usbprnp->usbprn_device_id + 2,
14037c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)usbprn_devid32.addr,
14047c478bd9Sstevel@tonic-gate 			    len, flag)) {
14057c478bd9Sstevel@tonic-gate 				err = EFAULT;
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 				break;
14087c478bd9Sstevel@tonic-gate 			}
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&usbprn_devid32, (caddr_t)arg,
14117c478bd9Sstevel@tonic-gate 			    sizeof (struct ecpp_device_id32), flag)) {
14127c478bd9Sstevel@tonic-gate 				err = EFAULT;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 				break;
14157c478bd9Sstevel@tonic-gate 			}
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 			break;
14187c478bd9Sstevel@tonic-gate 		}
14197c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
14207c478bd9Sstevel@tonic-gate 			if (ddi_copyin((caddr_t)arg, &usbprn_devid,
14217c478bd9Sstevel@tonic-gate 			    sizeof (struct ecpp_device_id), flag)) {
14227c478bd9Sstevel@tonic-gate 				err = EFAULT;
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 				break;
14257c478bd9Sstevel@tonic-gate 			}
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 			if (usbprnp->usbprn_device_id == NULL) {
14287c478bd9Sstevel@tonic-gate 				err = EIO;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 				break;
14317c478bd9Sstevel@tonic-gate 			}
14327c478bd9Sstevel@tonic-gate 			ASSERT(usbprnp->usbprn_device_id_len > 2);
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 			usbprn_devid.rlen = usbprnp->usbprn_device_id_len - 2;
14357c478bd9Sstevel@tonic-gate 			len = min(usbprn_devid.len, usbprn_devid.rlen);
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 			if (ddi_copyout(usbprnp->usbprn_device_id + 2,
14387c478bd9Sstevel@tonic-gate 			    usbprn_devid.addr, len, flag)) {
14397c478bd9Sstevel@tonic-gate 				err = EFAULT;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 				break;
14427c478bd9Sstevel@tonic-gate 			}
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&usbprn_devid, (caddr_t)arg,
14457c478bd9Sstevel@tonic-gate 			    sizeof (struct ecpp_device_id), flag)) {
14467c478bd9Sstevel@tonic-gate 				err = EFAULT;
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 				break;
14497c478bd9Sstevel@tonic-gate 			}
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 			break;
14527c478bd9Sstevel@tonic-gate 		}
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 		break;
14557c478bd9Sstevel@tonic-gate #else
14567c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &usbprn_devid,
14577c478bd9Sstevel@tonic-gate 		    sizeof (struct ecpp_device_id), flag)) {
14587c478bd9Sstevel@tonic-gate 			err = EFAULT;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 			break;
14617c478bd9Sstevel@tonic-gate 		}
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 		if (usbprnp->usbprn_device_id == NULL) {
14657c478bd9Sstevel@tonic-gate 			err = EIO;
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 			break;
14687c478bd9Sstevel@tonic-gate 		}
14697c478bd9Sstevel@tonic-gate 		ASSERT(usbprnp->usbprn_device_id_len > 2);
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 		usbprn_devid.rlen = usbprnp->usbprn_device_id_len - 2;
14727c478bd9Sstevel@tonic-gate 		len = min(usbprn_devid.len, usbprn_devid.rlen);
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
14757c478bd9Sstevel@tonic-gate 		    usbprn_devid.addr, len, flag)) {
14767c478bd9Sstevel@tonic-gate 			err = EFAULT;
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 			break;
14797c478bd9Sstevel@tonic-gate 		}
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&usbprn_devid, (caddr_t)arg,
14827c478bd9Sstevel@tonic-gate 		    sizeof (struct ecpp_device_id), flag)) {
14837c478bd9Sstevel@tonic-gate 			err = EFAULT;
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 			break;
14867c478bd9Sstevel@tonic-gate 		}
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 		break;
14897c478bd9Sstevel@tonic-gate #endif
14907c478bd9Sstevel@tonic-gate 	case ECPPIOC_SETPARMS:
14917c478bd9Sstevel@tonic-gate 		err = usbprn_setparms(usbprnp, arg, flag);
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 		break;
14947c478bd9Sstevel@tonic-gate 	case ECPPIOC_GETPARMS:
14957c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
14967c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl: ECPPIOC_GETPARMS(0x%x)", cmd);
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		/* Get the parameters */
14997c478bd9Sstevel@tonic-gate 		err = usbprn_getparms(usbprnp, arg, flag);
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 		break;
15027c478bd9Sstevel@tonic-gate 	case BPPIOC_GETERR:
15037c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15047c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl: ECPPIOC_GETERR(0x%x)", cmd);
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 		/* Get the error state */
15077c478bd9Sstevel@tonic-gate 		usbprn_geterr(usbprnp, arg, flag);
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 		break;
15107c478bd9Sstevel@tonic-gate 	case BPPIOC_TESTIO:
15117c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15127c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl: BPPIOC_TESTIO(0x%x)",  cmd);
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 		/* Get the port status */
15157c478bd9Sstevel@tonic-gate 		err = usbprn_testio(usbprnp, flag);
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		break;
15187c478bd9Sstevel@tonic-gate 	case PRNIOC_GET_IFCAP:
15197c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15207c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_IFCAP(0x%x)",  cmd);
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 		/* get interface capabilities */
15237c478bd9Sstevel@tonic-gate 		err = usbprn_prnio_get_ifcap(usbprnp, arg, flag);
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 		break;
15267c478bd9Sstevel@tonic-gate 	case PRNIOC_SET_IFCAP:
15277c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15287c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_SET_IFCAP(0x%x)",  cmd);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 		/* get interface capabilities */
15317c478bd9Sstevel@tonic-gate 		err = usbprn_prnio_set_ifcap(usbprnp, arg, flag);
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 		break;
15347c478bd9Sstevel@tonic-gate 	case PRNIOC_GET_IFINFO:
15357c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15367c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_IFINFO(0x%x)",  cmd);
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 		/* get interface information */
15397c478bd9Sstevel@tonic-gate 		err = usbprn_prnio_get_ifinfo(usbprnp, arg, flag);
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 		break;
15427c478bd9Sstevel@tonic-gate 	case PRNIOC_GET_STATUS:
15437c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15447c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_STATUS(0x%x)",  cmd);
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 		/* get prnio status */
15477c478bd9Sstevel@tonic-gate 		err = usbprn_prnio_get_status(usbprnp, arg, flag);
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 		break;
15507c478bd9Sstevel@tonic-gate 	case PRNIOC_GET_1284_DEVID:
15517c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15527c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_1284_DEVID(0x%x)",  cmd);
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 		/* get device ID */
15557c478bd9Sstevel@tonic-gate 		err = usbprn_prnio_get_1284_devid(usbprnp, arg, flag);
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 		break;
15587c478bd9Sstevel@tonic-gate 	case PRNIOC_GET_1284_STATUS:
15597c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15607c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_1284_STATUS(0x%x)",  cmd);
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 		/* get prnio status */
15637c478bd9Sstevel@tonic-gate 		err = usbprn_prnio_get_1284_status(usbprnp, arg, flag);
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 		break;
15667c478bd9Sstevel@tonic-gate 	case PRNIOC_GET_TIMEOUTS:
15677c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15687c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_TIMEOUTS(0x%x)", cmd);
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 		/* Get the parameters */
15717c478bd9Sstevel@tonic-gate 		err = usbprn_prnio_get_timeouts(usbprnp, arg, flag);
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 		break;
15747c478bd9Sstevel@tonic-gate 	case PRNIOC_SET_TIMEOUTS:
15757c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15767c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_SET_TIMEOUTS(0x%x)", cmd);
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 		/* Get the parameters */
15797c478bd9Sstevel@tonic-gate 		err = usbprn_prnio_set_timeouts(usbprnp, arg, flag);
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 		break;
15827c478bd9Sstevel@tonic-gate 	case PRNIOC_RESET:
15837c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15847c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_RESET(0x%x)",  cmd);
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 		/* nothing */
15877c478bd9Sstevel@tonic-gate 		err = 0;
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 		break;
15907c478bd9Sstevel@tonic-gate 	default:
15917c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15927c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl: unknown(0x%x)", cmd);
15937c478bd9Sstevel@tonic-gate 		err = EINVAL;
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15997c478bd9Sstevel@tonic-gate 	    "usbprn_ioctl: End ");
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	return (err);
16027c478bd9Sstevel@tonic-gate }
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate /*
16067c478bd9Sstevel@tonic-gate  * breakup by physio
16077c478bd9Sstevel@tonic-gate  */
16087c478bd9Sstevel@tonic-gate static void
usbprn_minphys(struct buf * bp)16097c478bd9Sstevel@tonic-gate usbprn_minphys(struct buf *bp)
16107c478bd9Sstevel@tonic-gate {
16117c478bd9Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1612112116d8Sfb 	    USBPRN_MINOR_TO_INSTANCE(getminor(bp->b_edev)));
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
16157c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
16167c478bd9Sstevel@tonic-gate 	    "usbprn_minphys: bcount=%lu", bp->b_bcount);
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	if (bp->b_bcount > usbprnp->usbprn_max_bulk_xfer_size) {
16197c478bd9Sstevel@tonic-gate 		bp->b_bcount = min(usbprn_max_xfer_size,
16207c478bd9Sstevel@tonic-gate 		    usbprnp->usbprn_max_bulk_xfer_size);
16217c478bd9Sstevel@tonic-gate 	} else {
16227c478bd9Sstevel@tonic-gate 		bp->b_bcount = min(usbprn_max_xfer_size, bp->b_bcount);
16237c478bd9Sstevel@tonic-gate 	}
16247c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate /*
16297c478bd9Sstevel@tonic-gate  * usbprn_open_usb_pipes:
16307c478bd9Sstevel@tonic-gate  *	Open all pipes on the device
16317c478bd9Sstevel@tonic-gate  */
16327c478bd9Sstevel@tonic-gate static int
usbprn_open_usb_pipes(usbprn_state_t * usbprnp)16337c478bd9Sstevel@tonic-gate usbprn_open_usb_pipes(usbprn_state_t *usbprnp)
16347c478bd9Sstevel@tonic-gate {
16357c478bd9Sstevel@tonic-gate 	usb_pipe_policy_t *policy;
16367c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
16377c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
16407c478bd9Sstevel@tonic-gate 	    "usbprn_open_usb_pipes:");
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	/*
16437c478bd9Sstevel@tonic-gate 	 * Intitialize the pipe policy for the bulk out pipe
16447c478bd9Sstevel@tonic-gate 	 */
16457c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
16467c478bd9Sstevel@tonic-gate 	policy = &(bulk_out->ps_policy);
16477c478bd9Sstevel@tonic-gate 	policy->pp_max_async_reqs = 1;
16487c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	/* Open bulk_out pipe */
16517c478bd9Sstevel@tonic-gate 	if (usb_pipe_open(usbprnp->usbprn_dip, &bulk_out->ps_ept_descr,
16527c478bd9Sstevel@tonic-gate 	    policy, USB_FLAGS_SLEEP, &bulk_out->ps_handle) != USB_SUCCESS) {
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
16557c478bd9Sstevel@tonic-gate 	}
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate #ifdef LATER
16587c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
16597c478bd9Sstevel@tonic-gate 	/* Open the bulk in pipe if one exists */
16607c478bd9Sstevel@tonic-gate 	if (bulk_in->ps_ept_descr->bLength) {
16617c478bd9Sstevel@tonic-gate 		/*
16627c478bd9Sstevel@tonic-gate 		 * Initialize the pipe policy for the Bulk In pipe
16637c478bd9Sstevel@tonic-gate 		 */
16647c478bd9Sstevel@tonic-gate 		policy = &bulk_in->ps_policy;
16657c478bd9Sstevel@tonic-gate 		bulk_in->ps_flags = USBPRN_PS_IDLE;
16667c478bd9Sstevel@tonic-gate 		policy->pp_max_async_reqs = 1;
16677c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 		/* Open bulk_in pipe */
16707c478bd9Sstevel@tonic-gate 		if (usb_pipe_open(usbprnp->usbprn_dip, bulk_in->ps_ept_descr,
16717c478bd9Sstevel@tonic-gate 		    policy, USB_FLAGS_SLEEP, &bulk_in->ps_handle) !=
16727c478bd9Sstevel@tonic-gate 		    USB_SUCCESS) {
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
16757c478bd9Sstevel@tonic-gate 		}
16767c478bd9Sstevel@tonic-gate 	} else {
16777c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate #else
16807c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
16817c478bd9Sstevel@tonic-gate 	bulk_in->ps_flags = USBPRN_PS_IDLE;
16827c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
16837c478bd9Sstevel@tonic-gate #endif
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
16867c478bd9Sstevel@tonic-gate 	    "usbprn_open_usb_pipes: success");
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
16897c478bd9Sstevel@tonic-gate }
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate /*
16937c478bd9Sstevel@tonic-gate  * usbprn_close_usb_pipes:
16947c478bd9Sstevel@tonic-gate  *	Close the default/bulk in/out pipes synchronously
16957c478bd9Sstevel@tonic-gate  */
16967c478bd9Sstevel@tonic-gate static void
usbprn_close_usb_pipes(usbprn_state_t * usbprnp)16977c478bd9Sstevel@tonic-gate usbprn_close_usb_pipes(usbprn_state_t *usbprnp)
16987c478bd9Sstevel@tonic-gate {
16997c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
17007c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
17037c478bd9Sstevel@tonic-gate 	    "usbprn_close_usb_pipes:");
17047c478bd9Sstevel@tonic-gate #ifdef DEBUG
17057c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
17067c478bd9Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
17077c478bd9Sstevel@tonic-gate 	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
17087c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
17097c478bd9Sstevel@tonic-gate #endif
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	/*
17127c478bd9Sstevel@tonic-gate 	 * close the pipe, if another thread is already closing the
17137c478bd9Sstevel@tonic-gate 	 * pipe, we get USB_INVALID_PIPE
17147c478bd9Sstevel@tonic-gate 	 */
17157c478bd9Sstevel@tonic-gate 	if (bulk_out->ps_handle) {
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
17187c478bd9Sstevel@tonic-gate 		    "usbprn_close_usb_pipes: Closing bulk out pipe");
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 		usb_pipe_close(usbprnp->usbprn_dip, bulk_out->ps_handle,
1721112116d8Sfb 		    USB_FLAGS_SLEEP, NULL, NULL);
17227c478bd9Sstevel@tonic-gate 		bulk_out->ps_handle = NULL;
17237c478bd9Sstevel@tonic-gate 	}
17247c478bd9Sstevel@tonic-gate 	if (bulk_in->ps_handle) {
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
17277c478bd9Sstevel@tonic-gate 		    "usbprn_close_usb_pipes: Closing bulk in pipe");
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 		usb_pipe_close(usbprnp->usbprn_dip, bulk_in->ps_handle,
1730112116d8Sfb 		    USB_FLAGS_SLEEP, NULL, NULL);
17317c478bd9Sstevel@tonic-gate 		bulk_in->ps_handle = NULL;
17327c478bd9Sstevel@tonic-gate 	}
17337c478bd9Sstevel@tonic-gate }
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate /*
17377c478bd9Sstevel@tonic-gate  * usbprn_getparms:
17387c478bd9Sstevel@tonic-gate  *	Get the parameters for the device
17397c478bd9Sstevel@tonic-gate  */
17407c478bd9Sstevel@tonic-gate static int
usbprn_getparms(usbprn_state_t * usbprnp,intptr_t arg,int flag)17417c478bd9Sstevel@tonic-gate usbprn_getparms(usbprn_state_t *usbprnp, intptr_t arg, int flag)
17427c478bd9Sstevel@tonic-gate {
17437c478bd9Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	if (ddi_copyout(&usbprnp->usbprn_setparms,
17467c478bd9Sstevel@tonic-gate 	    (caddr_t)arg, sizeof (struct ecpp_transfer_parms), flag)) {
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 		return (EFAULT);
17497c478bd9Sstevel@tonic-gate 	}
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	return (0);
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate /*
17567c478bd9Sstevel@tonic-gate  * usbprn_setparms:
17577c478bd9Sstevel@tonic-gate  *	Set the parameters for the device
17587c478bd9Sstevel@tonic-gate  */
17597c478bd9Sstevel@tonic-gate static int
usbprn_setparms(usbprn_state_t * usbprnp,intptr_t arg,int flag)17607c478bd9Sstevel@tonic-gate usbprn_setparms(usbprn_state_t *usbprnp, intptr_t arg, int flag)
17617c478bd9Sstevel@tonic-gate {
17627c478bd9Sstevel@tonic-gate 	struct ecpp_transfer_parms xfer;
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)arg, &xfer,
17677c478bd9Sstevel@tonic-gate 	    sizeof (struct ecpp_transfer_parms), flag)) {
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 		return (EFAULT);
17707c478bd9Sstevel@tonic-gate 	}
17717c478bd9Sstevel@tonic-gate 	if ((xfer.write_timeout < USBPRN_XFER_TIMEOUT_MIN) ||
17727c478bd9Sstevel@tonic-gate 	    (xfer.write_timeout > USBPRN_XFER_TIMEOUT_MAX)) {
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 		return (EINVAL);
17757c478bd9Sstevel@tonic-gate 	}
17767c478bd9Sstevel@tonic-gate 	if (!((xfer.mode == ECPP_CENTRONICS) ||
17777c478bd9Sstevel@tonic-gate 	    (xfer.mode == ECPP_COMPAT_MODE) ||
17787c478bd9Sstevel@tonic-gate 	    (xfer.mode == ECPP_NIBBLE_MODE) ||
17797c478bd9Sstevel@tonic-gate 	    (xfer.mode == ECPP_ECP_MODE) ||
17807c478bd9Sstevel@tonic-gate 	    (xfer.mode == ECPP_DIAG_MODE))) {
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 		return (EINVAL);
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 	}
17857c478bd9Sstevel@tonic-gate 	if (xfer.mode != ECPP_CENTRONICS) {
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 		return (EPROTONOSUPPORT);
17887c478bd9Sstevel@tonic-gate 	}
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
17917c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_setparms = xfer;
17927c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_prn_timeouts.tmo_forward = xfer.write_timeout;
17937c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	return (0);
17967c478bd9Sstevel@tonic-gate }
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate /*
18007c478bd9Sstevel@tonic-gate  * usbprn_geterr:
18017c478bd9Sstevel@tonic-gate  *	Return the any device error state
18027c478bd9Sstevel@tonic-gate  */
18037c478bd9Sstevel@tonic-gate static void
usbprn_geterr(usbprn_state_t * usbprnp,intptr_t arg,int flag)18047c478bd9Sstevel@tonic-gate usbprn_geterr(usbprn_state_t *usbprnp, intptr_t arg, int flag)
18057c478bd9Sstevel@tonic-gate {
18067c478bd9Sstevel@tonic-gate 	struct bpp_error_status bpp_status;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	bzero(&bpp_status, sizeof (bpp_status));
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
18117c478bd9Sstevel@tonic-gate 	bpp_status.bus_error = 0;
18127c478bd9Sstevel@tonic-gate 	bpp_status.timeout_occurred = 0;
18137c478bd9Sstevel@tonic-gate 	bpp_status.pin_status = usbprn_error_state(usbprnp->usbprn_last_status);
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
18167c478bd9Sstevel@tonic-gate 	    "usbprn_geterr: status=0x%x", usbprnp->usbprn_last_status);
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	(void) ddi_copyout(&bpp_status,
18217c478bd9Sstevel@tonic-gate 	    (caddr_t)arg, sizeof (struct bpp_error_status), flag);
18227c478bd9Sstevel@tonic-gate }
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate /*
18267c478bd9Sstevel@tonic-gate  * usbprn_error_state:
18277c478bd9Sstevel@tonic-gate  *	Map the driver error state to that of the application
18287c478bd9Sstevel@tonic-gate  */
18297c478bd9Sstevel@tonic-gate static char
usbprn_error_state(uchar_t status)18307c478bd9Sstevel@tonic-gate usbprn_error_state(uchar_t status)
18317c478bd9Sstevel@tonic-gate {
18327c478bd9Sstevel@tonic-gate 	uchar_t app_err_status = 0;
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 	if (!(status & USB_PRINTER_PORT_NO_ERROR)) {
18357c478bd9Sstevel@tonic-gate 		app_err_status |= USB_PRINTER_ERR_ERR;
18367c478bd9Sstevel@tonic-gate 	}
18377c478bd9Sstevel@tonic-gate 	if (status & USB_PRINTER_PORT_EMPTY) {
18387c478bd9Sstevel@tonic-gate 		app_err_status |= USB_PRINTER_PE_ERR;
18397c478bd9Sstevel@tonic-gate 	}
18407c478bd9Sstevel@tonic-gate 	if (!(status & USB_PRINTER_PORT_NO_SELECT)) {
18417c478bd9Sstevel@tonic-gate 		app_err_status |= USB_PRINTER_SLCT_ERR;
18427c478bd9Sstevel@tonic-gate 	}
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 	return (app_err_status);
18457c478bd9Sstevel@tonic-gate }
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate static int
usbprn_ioctl_get_status(usbprn_state_t * usbprnp)18497c478bd9Sstevel@tonic-gate usbprn_ioctl_get_status(usbprn_state_t *usbprnp)
18507c478bd9Sstevel@tonic-gate {
18517c478bd9Sstevel@tonic-gate 	/* Check the transfer mode */
18527c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	/* if device is disconnected or pipes closed, fail immediately */
18557c478bd9Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
18567c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
18597c478bd9Sstevel@tonic-gate 		    "usbprn_ioctl_get_status: device can't be accessed");
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 		return (EIO);
18627c478bd9Sstevel@tonic-gate 	}
18637c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
18667c478bd9Sstevel@tonic-gate 
18677c478bd9Sstevel@tonic-gate 		return (EIO);
18687c478bd9Sstevel@tonic-gate 	}
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 	return (0);
18717c478bd9Sstevel@tonic-gate }
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate /*
18757c478bd9Sstevel@tonic-gate  * usbprn_testio:
18767c478bd9Sstevel@tonic-gate  *	Execute the ECPP_TESTIO ioctl
18777c478bd9Sstevel@tonic-gate  */
18787c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
18797c478bd9Sstevel@tonic-gate static int
usbprn_testio(usbprn_state_t * usbprnp,int flag)18807c478bd9Sstevel@tonic-gate usbprn_testio(usbprn_state_t *usbprnp, int flag)
18817c478bd9Sstevel@tonic-gate {
18827c478bd9Sstevel@tonic-gate 	int	err;
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
18857c478bd9Sstevel@tonic-gate 	    "usbprn_testio: begin");
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	if ((err = usbprn_ioctl_get_status(usbprnp)) != 0) {
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 		return (err);
18907c478bd9Sstevel@tonic-gate 	}
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	/* There is an error.  Return it to the user */
18937c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	if (usbprn_error_state(usbprnp->usbprn_last_status) != 0) {
18967c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 		return (EIO);
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate 	} else {
19017c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 		return (0);
19047c478bd9Sstevel@tonic-gate 	}
19057c478bd9Sstevel@tonic-gate }
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate /*
19097c478bd9Sstevel@tonic-gate  * usbprn_prnio_get_status:
19107c478bd9Sstevel@tonic-gate  *	Execute the PRNIOC_GET_STATUS ioctl
19117c478bd9Sstevel@tonic-gate  */
19127c478bd9Sstevel@tonic-gate static int
usbprn_prnio_get_status(usbprn_state_t * usbprnp,intptr_t arg,int flag)19137c478bd9Sstevel@tonic-gate usbprn_prnio_get_status(usbprn_state_t *usbprnp, intptr_t arg, int flag)
19147c478bd9Sstevel@tonic-gate {
19157c478bd9Sstevel@tonic-gate 	uint_t	prnio_status = 0;
19167c478bd9Sstevel@tonic-gate 	int	err;
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
19197c478bd9Sstevel@tonic-gate 	    "usbprn_prnio_get_status: begin");
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 	/* capture printer status */
19227c478bd9Sstevel@tonic-gate 	err = usbprn_ioctl_get_status(usbprnp);
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_dev_state == USB_DEV_ONLINE) {
19277c478bd9Sstevel@tonic-gate 		prnio_status |= PRN_ONLINE;
19287c478bd9Sstevel@tonic-gate 	}
19297c478bd9Sstevel@tonic-gate 	if ((err == 0) &&
19307c478bd9Sstevel@tonic-gate 	    (usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR)) {
19317c478bd9Sstevel@tonic-gate 		prnio_status |= PRN_READY;
19327c478bd9Sstevel@tonic-gate 	}
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	if (ddi_copyout(&prnio_status,
19377c478bd9Sstevel@tonic-gate 	    (caddr_t)arg, sizeof (prnio_status), flag)) {
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 		return (EFAULT);
19407c478bd9Sstevel@tonic-gate 	}
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	return (0);
19437c478bd9Sstevel@tonic-gate }
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate /*
19477c478bd9Sstevel@tonic-gate  * usbprn_prnio_get_1284_status:
19487c478bd9Sstevel@tonic-gate  *	Execute the PRNIOC_GET_1284_STATUS ioctl
19497c478bd9Sstevel@tonic-gate  */
19507c478bd9Sstevel@tonic-gate static int
usbprn_prnio_get_1284_status(usbprn_state_t * usbprnp,intptr_t arg,int flag)19517c478bd9Sstevel@tonic-gate usbprn_prnio_get_1284_status(usbprn_state_t *usbprnp, intptr_t arg, int flag)
19527c478bd9Sstevel@tonic-gate {
19537c478bd9Sstevel@tonic-gate 	uchar_t		status;
19547c478bd9Sstevel@tonic-gate 	int		err;
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
19577c478bd9Sstevel@tonic-gate 	    "usbprn_prnio_get_1284_status: begin");
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	if ((err = usbprn_ioctl_get_status(usbprnp)) != 0) {
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 		return (err);
19627c478bd9Sstevel@tonic-gate 	}
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	/* status was captured successfully */
19657c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	status = usbprnp->usbprn_last_status & (USB_PRINTER_PORT_NO_ERROR |
1968112116d8Sfb 	    USB_PRINTER_PORT_NO_SELECT | USB_PRINTER_PORT_EMPTY);
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	if (ddi_copyout(&status, (caddr_t)arg, sizeof (status), flag)) {
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 		return (EFAULT);
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	return (0);
19787c478bd9Sstevel@tonic-gate }
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate /*
19827c478bd9Sstevel@tonic-gate  * usbprn_prnio_get_ifcap:
19837c478bd9Sstevel@tonic-gate  *	Execute the PRNIOC_GET_IFCAP ioctl
19847c478bd9Sstevel@tonic-gate  */
19857c478bd9Sstevel@tonic-gate /* ARGSUSED */
19867c478bd9Sstevel@tonic-gate static int
usbprn_prnio_get_ifcap(usbprn_state_t * usbprnp,intptr_t arg,int flag)19877c478bd9Sstevel@tonic-gate usbprn_prnio_get_ifcap(usbprn_state_t *usbprnp, intptr_t arg, int flag)
19887c478bd9Sstevel@tonic-gate {
19897c478bd9Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
19907c478bd9Sstevel@tonic-gate 
19917c478bd9Sstevel@tonic-gate 	if (ddi_copyout(&usbprn_ifcap, (caddr_t)arg, sizeof (usbprn_ifcap),
19927c478bd9Sstevel@tonic-gate 	    flag)) {
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 		return (EFAULT);
19957c478bd9Sstevel@tonic-gate 	}
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	return (0);
19987c478bd9Sstevel@tonic-gate }
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate /*
20027c478bd9Sstevel@tonic-gate  * usbprn_prnio_get_ifcap:
20037c478bd9Sstevel@tonic-gate  *	Execute the PRNIOC_SET_IFCAP ioctl
20047c478bd9Sstevel@tonic-gate  */
20057c478bd9Sstevel@tonic-gate /* ARGSUSED */
20067c478bd9Sstevel@tonic-gate static int
usbprn_prnio_set_ifcap(usbprn_state_t * usbprnp,intptr_t arg,int flag)20077c478bd9Sstevel@tonic-gate usbprn_prnio_set_ifcap(usbprn_state_t *usbprnp, intptr_t arg, int flag)
20087c478bd9Sstevel@tonic-gate {
20097c478bd9Sstevel@tonic-gate 	uint_t	new_ifcap;
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)arg, &new_ifcap, sizeof (new_ifcap), flag)) {
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 		return (EFAULT);
20167c478bd9Sstevel@tonic-gate 	}
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 	/* no settable capabilities */
20197c478bd9Sstevel@tonic-gate 	if (usbprn_ifcap != new_ifcap) {
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 		return (EINVAL);
20227c478bd9Sstevel@tonic-gate 	}
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	return (0);
20257c478bd9Sstevel@tonic-gate }
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate /*
20297c478bd9Sstevel@tonic-gate  * usbprn_prnio_get_ifinfo:
20307c478bd9Sstevel@tonic-gate  *	Execute the PRNIOC_GET_IFINFO ioctl
20317c478bd9Sstevel@tonic-gate  */
20327c478bd9Sstevel@tonic-gate /* ARGSUSED */
20337c478bd9Sstevel@tonic-gate static int
usbprn_prnio_get_ifinfo(usbprn_state_t * usbprnp,intptr_t arg,int flag)20347c478bd9Sstevel@tonic-gate usbprn_prnio_get_ifinfo(usbprn_state_t *usbprnp, intptr_t arg, int flag)
20357c478bd9Sstevel@tonic-gate {
20367c478bd9Sstevel@tonic-gate 	struct prn_interface_info	prn_info;
20377c478bd9Sstevel@tonic-gate 	int	rlen, len;
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 	rlen = strlen(usbprn_prnio_ifinfo);
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20427c478bd9Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 	switch (ddi_model_convert_from(flag & FMODELS)) {
20457c478bd9Sstevel@tonic-gate 	case DDI_MODEL_ILP32: {
20467c478bd9Sstevel@tonic-gate 		struct prn_interface_info32	prn_info32;
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &prn_info32,
20497c478bd9Sstevel@tonic-gate 		    sizeof (struct prn_interface_info32), flag)) {
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 			return (EFAULT);
20527c478bd9Sstevel@tonic-gate 		}
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 		prn_info32.if_rlen = rlen;
20557c478bd9Sstevel@tonic-gate 		len = min(rlen, prn_info32.if_len);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&usbprn_prnio_ifinfo[0],
20587c478bd9Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)prn_info32.if_data, len, flag)) {
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 			return (EFAULT);
20617c478bd9Sstevel@tonic-gate 		}
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&prn_info32, (caddr_t)arg,
20647c478bd9Sstevel@tonic-gate 		    sizeof (struct prn_interface_info32), flag)) {
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 			return (EFAULT);
20677c478bd9Sstevel@tonic-gate 		}
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 		break;
20707c478bd9Sstevel@tonic-gate 	}
20717c478bd9Sstevel@tonic-gate 	case DDI_MODEL_NONE:
20727c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20737c478bd9Sstevel@tonic-gate 		ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &prn_info,
20767c478bd9Sstevel@tonic-gate 		    sizeof (struct prn_interface_info), flag)) {
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 			return (EFAULT);
20797c478bd9Sstevel@tonic-gate 		}
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 		prn_info.if_rlen = rlen;
20827c478bd9Sstevel@tonic-gate 		len = min(rlen, prn_info.if_len);
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&usbprn_prnio_ifinfo[0],
20857c478bd9Sstevel@tonic-gate 		    prn_info.if_data, len, flag)) {
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 			return (EFAULT);
20887c478bd9Sstevel@tonic-gate 		}
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&prn_info, (caddr_t)arg,
20917c478bd9Sstevel@tonic-gate 		    sizeof (struct prn_interface_info), flag)) {
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 			return (EFAULT);
20947c478bd9Sstevel@tonic-gate 		}
20957c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 		break;
20987c478bd9Sstevel@tonic-gate 	}
20997c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	return (0);
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate /*
21067c478bd9Sstevel@tonic-gate  * usbprn_prnio_getdevid:
21077c478bd9Sstevel@tonic-gate  *	Execute the PRNIOC_GET_1284_DEVID ioctl
21087c478bd9Sstevel@tonic-gate  */
21097c478bd9Sstevel@tonic-gate static int
usbprn_prnio_get_1284_devid(usbprn_state_t * usbprnp,intptr_t arg,int flag)21107c478bd9Sstevel@tonic-gate usbprn_prnio_get_1284_devid(usbprn_state_t *usbprnp, intptr_t arg, int flag)
21117c478bd9Sstevel@tonic-gate {
21127c478bd9Sstevel@tonic-gate 	struct prn_1284_device_id prn_devid;
21137c478bd9Sstevel@tonic-gate 	int	len;
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
21187c478bd9Sstevel@tonic-gate 	switch (ddi_model_convert_from(flag & FMODELS)) {
21197c478bd9Sstevel@tonic-gate 	case DDI_MODEL_ILP32: {
21207c478bd9Sstevel@tonic-gate 		struct prn_1284_device_id32	prn_devid32;
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &prn_devid32,
21237c478bd9Sstevel@tonic-gate 		    sizeof (struct prn_1284_device_id32), flag)) {
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 			return (EFAULT);
21267c478bd9Sstevel@tonic-gate 		}
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 		prn_devid32.id_rlen = usbprnp->usbprn_device_id_len - 2;
21297c478bd9Sstevel@tonic-gate 		len = min(prn_devid32.id_rlen, prn_devid32.id_len);
21307c478bd9Sstevel@tonic-gate 
21317c478bd9Sstevel@tonic-gate 		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
21327c478bd9Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)prn_devid32.id_data, len, flag)) {
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 			return (EFAULT);
21357c478bd9Sstevel@tonic-gate 		}
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&prn_devid32, (caddr_t)arg,
21387c478bd9Sstevel@tonic-gate 		    sizeof (struct prn_1284_device_id32), flag)) {
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 			return (EFAULT);
21417c478bd9Sstevel@tonic-gate 		}
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 		break;
21447c478bd9Sstevel@tonic-gate 	}
21457c478bd9Sstevel@tonic-gate 	case DDI_MODEL_NONE:
21467c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21477c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &prn_devid,
21487c478bd9Sstevel@tonic-gate 		    sizeof (struct prn_1284_device_id), flag)) {
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 			return (EFAULT);
21517c478bd9Sstevel@tonic-gate 		}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 		prn_devid.id_rlen = usbprnp->usbprn_device_id_len - 2;
21547c478bd9Sstevel@tonic-gate 		len = min(prn_devid.id_rlen, prn_devid.id_len);
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
21577c478bd9Sstevel@tonic-gate 		    prn_devid.id_data, len, flag)) {
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 			return (EFAULT);
21607c478bd9Sstevel@tonic-gate 		}
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&prn_devid, (caddr_t)arg,
21637c478bd9Sstevel@tonic-gate 		    sizeof (struct prn_1284_device_id), flag)) {
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 			return (EFAULT);
21667c478bd9Sstevel@tonic-gate 		}
21677c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate 		break;
21707c478bd9Sstevel@tonic-gate 	}
21717c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	return (0);
21747c478bd9Sstevel@tonic-gate }
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate /*
21787c478bd9Sstevel@tonic-gate  * usbprn_prnio_get_timeouts:
21797c478bd9Sstevel@tonic-gate  *	Return timeout
21807c478bd9Sstevel@tonic-gate  */
21817c478bd9Sstevel@tonic-gate static int
usbprn_prnio_get_timeouts(usbprn_state_t * usbprnp,intptr_t arg,int flag)21827c478bd9Sstevel@tonic-gate usbprn_prnio_get_timeouts(usbprn_state_t *usbprnp, intptr_t arg, int flag)
21837c478bd9Sstevel@tonic-gate {
21847c478bd9Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	if (ddi_copyout(&usbprnp->usbprn_prn_timeouts,
21877c478bd9Sstevel@tonic-gate 	    (caddr_t)arg, sizeof (struct prn_timeouts), flag)) {
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 		return (EFAULT);
21907c478bd9Sstevel@tonic-gate 	}
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 	return (0);
21937c478bd9Sstevel@tonic-gate }
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate /*
21977c478bd9Sstevel@tonic-gate  * usbprn_prnio_set_timeouts:
21987c478bd9Sstevel@tonic-gate  *	Set write timeout and prn timeout
21997c478bd9Sstevel@tonic-gate  */
22007c478bd9Sstevel@tonic-gate static int
usbprn_prnio_set_timeouts(usbprn_state_t * usbprnp,intptr_t arg,int flag)22017c478bd9Sstevel@tonic-gate usbprn_prnio_set_timeouts(usbprn_state_t *usbprnp, intptr_t arg, int flag)
22027c478bd9Sstevel@tonic-gate {
22037c478bd9Sstevel@tonic-gate 	struct prn_timeouts prn_timeouts;
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)arg, &prn_timeouts,
22087c478bd9Sstevel@tonic-gate 	    sizeof (struct prn_timeouts), flag)) {
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 		return (EFAULT);
22117c478bd9Sstevel@tonic-gate 	}
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	if ((prn_timeouts.tmo_forward < USBPRN_XFER_TIMEOUT_MIN) ||
22147c478bd9Sstevel@tonic-gate 	    (prn_timeouts.tmo_forward > USBPRN_XFER_TIMEOUT_MAX)) {
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 		return (EINVAL);
22177c478bd9Sstevel@tonic-gate 	}
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_prn_timeouts = prn_timeouts;
22227c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_setparms.write_timeout = prn_timeouts.tmo_forward;
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 	return (0);
22277c478bd9Sstevel@tonic-gate }
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate /*
22317c478bd9Sstevel@tonic-gate  * usbprn_biodone:
22327c478bd9Sstevel@tonic-gate  *	If there is a bp, complete it
22337c478bd9Sstevel@tonic-gate  */
22347c478bd9Sstevel@tonic-gate static void
usbprn_biodone(usbprn_state_t * usbprnp,int err,int bytes_remaining)22357c478bd9Sstevel@tonic-gate usbprn_biodone(usbprn_state_t *usbprnp, int err, int bytes_remaining)
22367c478bd9Sstevel@tonic-gate {
22377c478bd9Sstevel@tonic-gate 	struct buf *bp = usbprnp->usbprn_bp;
22387c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
22397c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&usbprnp->usbprn_mutex));
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	/* all pipes must be idle now */
22447c478bd9Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
22457c478bd9Sstevel@tonic-gate 	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
22467c478bd9Sstevel@tonic-gate 
22477c478bd9Sstevel@tonic-gate 	if (bp) {
22487c478bd9Sstevel@tonic-gate 		bp->b_resid = bytes_remaining;
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
22517c478bd9Sstevel@tonic-gate 		    "usbprn_biodone: "
22527c478bd9Sstevel@tonic-gate 		    "bp=0x%p bcount=0x%lx resid=0x%lx remaining=0x%x err=%d",
22537c478bd9Sstevel@tonic-gate 		    (void *)bp, bp->b_bcount, bp->b_resid, bytes_remaining,
22547c478bd9Sstevel@tonic-gate 		    err);
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 		if (err) {
22577c478bd9Sstevel@tonic-gate 			bioerror(bp, err);
22587c478bd9Sstevel@tonic-gate 		}
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_bp = NULL;
22617c478bd9Sstevel@tonic-gate 		biodone(bp);
22627c478bd9Sstevel@tonic-gate 	}
22637c478bd9Sstevel@tonic-gate 
22647c478bd9Sstevel@tonic-gate 	/* release access */
22657c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_dev_acc);
22667c478bd9Sstevel@tonic-gate }
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate /*
22707c478bd9Sstevel@tonic-gate  * usbprn_send_async_bulk_data:
22717c478bd9Sstevel@tonic-gate  *	Send bulk data down to the device through the bulk out pipe
22727c478bd9Sstevel@tonic-gate  */
22737c478bd9Sstevel@tonic-gate static void
usbprn_send_async_bulk_data(usbprn_state_t * usbprnp)22747c478bd9Sstevel@tonic-gate usbprn_send_async_bulk_data(usbprn_state_t *usbprnp)
22757c478bd9Sstevel@tonic-gate {
22767c478bd9Sstevel@tonic-gate 	int		rval;
22777c478bd9Sstevel@tonic-gate 	int		timeout;
22787c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
22797c478bd9Sstevel@tonic-gate 	size_t		max_xfer_count, xfer_count;
22807c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
22817c478bd9Sstevel@tonic-gate 	usb_bulk_req_t *req;
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
22847c478bd9Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate 	timeout = usbprnp->usbprn_setparms.write_timeout;
22877c478bd9Sstevel@tonic-gate 	max_xfer_count = usbprnp->usbprn_bp->b_bcount;
22887c478bd9Sstevel@tonic-gate 	mp = usbprnp->usbprn_bulk_mp;
22897c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
2290d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	xfer_count = MBLKL(mp);
22917c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	req = usb_alloc_bulk_req(usbprnp->usbprn_dip, 0, USB_FLAGS_SLEEP);
2294d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	req->bulk_len		= (uint_t)xfer_count;
22957c478bd9Sstevel@tonic-gate 	req->bulk_data		= mp;
22967c478bd9Sstevel@tonic-gate 	req->bulk_timeout	= timeout;
22977c478bd9Sstevel@tonic-gate 	req->bulk_cb		= usbprn_bulk_xfer_cb;
22987c478bd9Sstevel@tonic-gate 	req->bulk_exc_cb	= usbprn_bulk_xfer_exc_cb;
22997c478bd9Sstevel@tonic-gate 	req->bulk_client_private = (usb_opaque_t)usbprnp;
23007c478bd9Sstevel@tonic-gate 	req->bulk_attributes	= USB_ATTRS_AUTOCLEARING;
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23037c478bd9Sstevel@tonic-gate 	    "usbprn_send_async_bulk_data: req = 0x%p "
23047c478bd9Sstevel@tonic-gate 	    "max_bulk_xfer_size=%lu mp=0x%p xfer_cnt=%lu timeout=%x",
2305112116d8Sfb 	    (void *)req, max_xfer_count, (void *)mp, xfer_count, timeout);
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 	ASSERT(xfer_count <= max_xfer_count);
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate 	if ((rval = usb_pipe_bulk_xfer(bulk_out->ps_handle, req, 0)) !=
23117c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23147c478bd9Sstevel@tonic-gate 		    "usbprn_send_async_bulk_data: Bulk mp=0x%p "
2315112116d8Sfb 		    "rval=%d", (void *)mp, rval);
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
23187c478bd9Sstevel@tonic-gate 		bulk_out->ps_flags = USBPRN_PS_IDLE;
23197c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_bulk_mp = NULL;
23207c478bd9Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
23217c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 		usb_free_bulk_req(req);
23247c478bd9Sstevel@tonic-gate 	} else {
23257c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
23267c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_bulk_mp = NULL;
23277c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
23287c478bd9Sstevel@tonic-gate 	}
23297c478bd9Sstevel@tonic-gate }
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate /*
23337c478bd9Sstevel@tonic-gate  * usbprn_bulk_xfer_cb
23347c478bd9Sstevel@tonic-gate  *	Callback for a normal transfer for both bulk pipes.
23357c478bd9Sstevel@tonic-gate  */
23367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
23377c478bd9Sstevel@tonic-gate static void
usbprn_bulk_xfer_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)23387c478bd9Sstevel@tonic-gate usbprn_bulk_xfer_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
23397c478bd9Sstevel@tonic-gate {
23407c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = (usbprn_state_t *)req->bulk_client_private;
23417c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	ASSERT(usbprnp != NULL);
23447c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2349112116d8Sfb 	    "usbprn_bulk_xfer_cb: mp=0x%p ", (void *)usbprnp->usbprn_bulk_mp);
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
23527c478bd9Sstevel@tonic-gate 	ASSERT(usbprnp->usbprn_bp != NULL);
23537c478bd9Sstevel@tonic-gate 	ASSERT((req->bulk_cb_flags & USB_CB_INTR_CONTEXT) == 0);
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	/*
23567c478bd9Sstevel@tonic-gate 	 * if device is disconnected or driver close called, return
23577c478bd9Sstevel@tonic-gate 	 * The pipe could be closed, or a timeout could have
23587c478bd9Sstevel@tonic-gate 	 * come in and the pipe is being reset.  If the
23597c478bd9Sstevel@tonic-gate 	 * state isn't transferring, then return
23607c478bd9Sstevel@tonic-gate 	 */
23617c478bd9Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp)) ||
23627c478bd9Sstevel@tonic-gate 	    (bulk_out->ps_flags != USBPRN_PS_NEED_TO_XFER)) {
23637c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23647c478bd9Sstevel@tonic-gate 		    "usbprn_bulk_xfer_cb: no access or pipe closed");
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate 		bulk_out->ps_flags = USBPRN_PS_IDLE;
23677c478bd9Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
23687c478bd9Sstevel@tonic-gate 	} else {
23697c478bd9Sstevel@tonic-gate 
23707c478bd9Sstevel@tonic-gate 		/*
23717c478bd9Sstevel@tonic-gate 		 * data has been xferred, complete the bp.
23727c478bd9Sstevel@tonic-gate 		 */
23737c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23747c478bd9Sstevel@tonic-gate 		    "usbprn_bulk_xfer_cb: transaction over");
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 		bulk_out->ps_flags = USBPRN_PS_IDLE;
23777c478bd9Sstevel@tonic-gate 		usbprn_biodone(usbprnp, 0, 0);
23787c478bd9Sstevel@tonic-gate 	}
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
23817c478bd9Sstevel@tonic-gate 
23827c478bd9Sstevel@tonic-gate 	usb_free_bulk_req(req);
23837c478bd9Sstevel@tonic-gate }
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate /*
23877c478bd9Sstevel@tonic-gate  * usbprn_bulk_xfer_exc_cb:
23887c478bd9Sstevel@tonic-gate  *	Exception callback for the bulk pipes
23897c478bd9Sstevel@tonic-gate  */
23907c478bd9Sstevel@tonic-gate static void
usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)23917c478bd9Sstevel@tonic-gate usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
23927c478bd9Sstevel@tonic-gate {
23937c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = (usbprn_state_t *)req->bulk_client_private;
23947c478bd9Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
23957c478bd9Sstevel@tonic-gate 	int		bytes_remaining = 0;
23967c478bd9Sstevel@tonic-gate 	mblk_t		*data = req->bulk_data;
23977c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason = req->bulk_completion_reason;
23987c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags = req->bulk_cb_flags;
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
24017c478bd9Sstevel@tonic-gate 	    "usbprn_bulk_xfer_exc_cb: "
24027c478bd9Sstevel@tonic-gate 	    "pipe=0x%p req=0x%p cr=%d cb_flags=0x%x data=0x%p",
2403112116d8Sfb 	    (void *)pipe, (void *)req, completion_reason, cb_flags,
2404112116d8Sfb 	    (void *)data);
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	ASSERT((req->bulk_cb_flags & USB_CB_INTR_CONTEXT) == 0);
24077c478bd9Sstevel@tonic-gate 	ASSERT(data != NULL);
24087c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
24097c478bd9Sstevel@tonic-gate 
24107c478bd9Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
24117c478bd9Sstevel@tonic-gate 	bulk_out->ps_flags = USBPRN_PS_IDLE;
24127c478bd9Sstevel@tonic-gate 	bulk_out->ps_cr = completion_reason;
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	if (data) {
2415d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		bytes_remaining = MBLKL(data);
24167c478bd9Sstevel@tonic-gate 	}
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	/*
24197c478bd9Sstevel@tonic-gate 	 * If the pipe is closed or device not responding or not in
24207c478bd9Sstevel@tonic-gate 	 * need of transfer, just give up on this bp.
24217c478bd9Sstevel@tonic-gate 	 */
24227c478bd9Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp)) ||
24237c478bd9Sstevel@tonic-gate 	    (req->bulk_completion_reason == USB_CR_DEV_NOT_RESP)) {
24247c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
24257c478bd9Sstevel@tonic-gate 		    "usbprn_bulk_xfer_exc_cb: "
24267c478bd9Sstevel@tonic-gate 		    "device not accesible or wrong state");
24277c478bd9Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
24287c478bd9Sstevel@tonic-gate 	} else {
24297c478bd9Sstevel@tonic-gate 		if (completion_reason == USB_CR_TIMEOUT) {
24307c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL,
24317c478bd9Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
24327c478bd9Sstevel@tonic-gate 			    "usbprn_bulk_xfer_exc_cb: timeout error, "
24337c478bd9Sstevel@tonic-gate 			    "xferred %lu bytes",
24347c478bd9Sstevel@tonic-gate 			    ((usbprnp->usbprn_bp->b_bcount) -
24357c478bd9Sstevel@tonic-gate 			    bytes_remaining));
24367c478bd9Sstevel@tonic-gate 			usbprn_biodone(usbprnp, 0, bytes_remaining);
24377c478bd9Sstevel@tonic-gate 		} else {
24387c478bd9Sstevel@tonic-gate 			usbprn_biodone(usbprnp, EIO, 0);
24397c478bd9Sstevel@tonic-gate 		}
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate 	}
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
24447c478bd9Sstevel@tonic-gate 
24457c478bd9Sstevel@tonic-gate 	usb_free_bulk_req(req);
24467c478bd9Sstevel@tonic-gate }
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate /*
24507c478bd9Sstevel@tonic-gate  * usbprn_reconnect_event_cb:
24517c478bd9Sstevel@tonic-gate  *	Called upon when the device is hotplugged back; event handling
24527c478bd9Sstevel@tonic-gate  */
24537c478bd9Sstevel@tonic-gate /*ARGSUSED*/
24547c478bd9Sstevel@tonic-gate static int
usbprn_reconnect_event_cb(dev_info_t * dip)24557c478bd9Sstevel@tonic-gate usbprn_reconnect_event_cb(dev_info_t *dip)
24567c478bd9Sstevel@tonic-gate {
24577c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp =
2458112116d8Sfb 	    (usbprn_state_t *)ddi_get_soft_state(usbprn_statep,
2459112116d8Sfb 	    ddi_get_instance(dip));
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 	ASSERT(usbprnp != NULL);
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
24647c478bd9Sstevel@tonic-gate 	    "usbprn_reconnect_event_cb:");
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
24697c478bd9Sstevel@tonic-gate 	ASSERT(usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED);
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 	usbprn_restore_device_state(dip, usbprnp);
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_ugen_hdl) {
24767c478bd9Sstevel@tonic-gate 		(void) usb_ugen_reconnect_ev_cb(usbprnp->usbprn_ugen_hdl);
24777c478bd9Sstevel@tonic-gate 	}
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
24827c478bd9Sstevel@tonic-gate }
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate /*
24867c478bd9Sstevel@tonic-gate  * usbprn_disconnect_event_cb:
24877c478bd9Sstevel@tonic-gate  *	callback for disconnect events
24887c478bd9Sstevel@tonic-gate  */
24897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
24907c478bd9Sstevel@tonic-gate static int
usbprn_disconnect_event_cb(dev_info_t * dip)24917c478bd9Sstevel@tonic-gate usbprn_disconnect_event_cb(dev_info_t *dip)
24927c478bd9Sstevel@tonic-gate {
24937c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = (usbprn_state_t *)ddi_get_soft_state(
2494112116d8Sfb 	    usbprn_statep, ddi_get_instance(dip));
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
24977c478bd9Sstevel@tonic-gate 	    "usbprn_disconnect_event_cb: Begin");
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
25027c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_dev_state = USB_DEV_DISCONNECTED;
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
25057c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
25067c478bd9Sstevel@tonic-gate 		    "device was disconnected while open. "
25077c478bd9Sstevel@tonic-gate 		    "Data may have been lost");
25087c478bd9Sstevel@tonic-gate 	}
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	/* For now, we set the offline bit in usbprn_last_status */
25117c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_last_status |= USB_PRINTER_PORT_NO_SELECT;
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
25147c478bd9Sstevel@tonic-gate 
25157c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_ugen_hdl) {
25167c478bd9Sstevel@tonic-gate 		(void) usb_ugen_disconnect_ev_cb(usbprnp->usbprn_ugen_hdl);
25177c478bd9Sstevel@tonic-gate 	}
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
25227c478bd9Sstevel@tonic-gate 	    "usbprn_disconnect_event_cb: End");
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
25257c478bd9Sstevel@tonic-gate }
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate /*
25297c478bd9Sstevel@tonic-gate  * usbprn_restore_device_state:
25307c478bd9Sstevel@tonic-gate  *	set original configuration of the device
25317c478bd9Sstevel@tonic-gate  *	Restores data xfer
25327c478bd9Sstevel@tonic-gate  */
25337c478bd9Sstevel@tonic-gate static void
usbprn_restore_device_state(dev_info_t * dip,usbprn_state_t * usbprnp)25347c478bd9Sstevel@tonic-gate usbprn_restore_device_state(dev_info_t *dip, usbprn_state_t *usbprnp)
25357c478bd9Sstevel@tonic-gate {
25367c478bd9Sstevel@tonic-gate 	int alt, rval, iface;
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
25397c478bd9Sstevel@tonic-gate 	    "usbprn_restore_device_state:");
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
25427c478bd9Sstevel@tonic-gate 	ASSERT((usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED) ||
2543112116d8Sfb 	    (usbprnp->usbprn_dev_state == USB_DEV_SUSPENDED));
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	/* Check if we are talking to the same device */
25487c478bd9Sstevel@tonic-gate 	if (usb_check_same_device(dip, usbprnp->usbprn_log_handle,
2549d291d9f2Sfrits 	    USB_LOG_L0, PRINT_MASK_ALL,
25507c478bd9Sstevel@tonic-gate 	    USB_CHK_ALL, NULL) != USB_SUCCESS) {
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate 		/* change the device state from suspended to disconnected */
25537c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
25547c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_dev_state = USB_DEV_DISCONNECTED;
25557c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate 		return;
25587c478bd9Sstevel@tonic-gate 	}
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L0(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
25617c478bd9Sstevel@tonic-gate 	    "Printer has been reconnected but data may have been lost");
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 	/* set last status to online */
25667c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_last_status &= ~USB_PRINTER_PORT_NO_SELECT;
25677c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	/* Get the port status */
25707c478bd9Sstevel@tonic-gate 	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
25717c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
25727c478bd9Sstevel@tonic-gate 		    "usbprn_restore_device_state: port status failed");
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 		return;
25757c478bd9Sstevel@tonic-gate 	}
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate 	if ((usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR) == 0) {
25807c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
25817c478bd9Sstevel@tonic-gate 		    "usbprn_restore_device_state: An error with the printer");
25827c478bd9Sstevel@tonic-gate 	}
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
25857c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
25867c478bd9Sstevel@tonic-gate 		usbprn_close_usb_pipes(usbprnp);
25877c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
25887c478bd9Sstevel@tonic-gate 	}
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 	/* restore alternate */
25917c478bd9Sstevel@tonic-gate 	alt = usbprnp->usbprn_if_descr.bAlternateSetting,
2592112116d8Sfb 	    mutex_exit(&usbprnp->usbprn_mutex);
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 	iface = usb_owns_device(dip) ? 0 :  usb_get_if_number(dip);
25957c478bd9Sstevel@tonic-gate 	if ((rval = usb_set_alt_if(dip, iface, alt,
25967c478bd9Sstevel@tonic-gate 	    USB_FLAGS_SLEEP, NULL, NULL)) != USB_SUCCESS) {
25977c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
25987c478bd9Sstevel@tonic-gate 		    "usbprn_restore_device_state: set alternate failed (%d)",
25997c478bd9Sstevel@tonic-gate 		    rval);
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 		return;
26027c478bd9Sstevel@tonic-gate 	}
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
26097c478bd9Sstevel@tonic-gate 		(void) usbprn_open_usb_pipes(usbprnp);
26107c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
26117c478bd9Sstevel@tonic-gate 	}
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate 	if (usbprnp->usbprn_pm && usbprnp->usbprn_pm->usbprn_wakeup_enabled) {
26147c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
26157c478bd9Sstevel@tonic-gate 		(void) usb_handle_remote_wakeup(usbprnp->usbprn_dip,
26167c478bd9Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE);
26177c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
26187c478bd9Sstevel@tonic-gate 	}
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
26217c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
26247c478bd9Sstevel@tonic-gate 	    "usbprn_restore_device_state: End");
26257c478bd9Sstevel@tonic-gate }
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate /*
26297c478bd9Sstevel@tonic-gate  *	Create power managements components
26307c478bd9Sstevel@tonic-gate  */
26317c478bd9Sstevel@tonic-gate static void
usbprn_create_pm_components(dev_info_t * dip,usbprn_state_t * usbprnp)26327c478bd9Sstevel@tonic-gate usbprn_create_pm_components(dev_info_t *dip, usbprn_state_t *usbprnp)
26337c478bd9Sstevel@tonic-gate {
26347c478bd9Sstevel@tonic-gate 	usbprn_power_t	*usbprnpm;
26357c478bd9Sstevel@tonic-gate 	uint_t		pwr_states;
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
26387c478bd9Sstevel@tonic-gate 	    "usbprn_create_pm_components: Begin");
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate 	/* Allocate the state structure */
26417c478bd9Sstevel@tonic-gate 	usbprnpm = kmem_zalloc(sizeof (usbprn_power_t),
2642112116d8Sfb 	    KM_SLEEP);
26437c478bd9Sstevel@tonic-gate 	usbprnp->usbprn_pm = usbprnpm;
26447c478bd9Sstevel@tonic-gate 	usbprnpm->usbprn_pm_capabilities = 0;
26457c478bd9Sstevel@tonic-gate 	usbprnpm->usbprn_current_power = USB_DEV_OS_FULL_PWR;
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate 	if (usb_create_pm_components(dip, &pwr_states) ==
26487c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
26497c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_PM,
26507c478bd9Sstevel@tonic-gate 		    usbprnp->usbprn_log_handle,
26517c478bd9Sstevel@tonic-gate 		    "usbprn_create_pm_components: "
26527c478bd9Sstevel@tonic-gate 		    "created PM components");
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 		if (usb_handle_remote_wakeup(dip,
26557c478bd9Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
26567c478bd9Sstevel@tonic-gate 			usbprnpm->usbprn_wakeup_enabled = 1;
26577c478bd9Sstevel@tonic-gate 		}
26587c478bd9Sstevel@tonic-gate 		usbprnpm->usbprn_pwr_states = (uint8_t)pwr_states;
26597c478bd9Sstevel@tonic-gate 		(void) pm_raise_power(usbprnp->usbprn_dip, 0,
2660112116d8Sfb 		    USB_DEV_OS_FULL_PWR);
26617c478bd9Sstevel@tonic-gate 	} else {
26627c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM,
26637c478bd9Sstevel@tonic-gate 		    usbprnp->usbprn_log_handle,
26647c478bd9Sstevel@tonic-gate 		    "usbprn_create_pm_components: Failed");
26657c478bd9Sstevel@tonic-gate 	}
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
26687c478bd9Sstevel@tonic-gate 	    "usbprn_create_pm_components: END");
26697c478bd9Sstevel@tonic-gate }
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 
26727c478bd9Sstevel@tonic-gate /*
26737c478bd9Sstevel@tonic-gate  * usbprn_pwrlvl0:
26747c478bd9Sstevel@tonic-gate  * Functions to handle power transition for OS levels 0 -> 3
26757c478bd9Sstevel@tonic-gate  */
26767c478bd9Sstevel@tonic-gate static int
usbprn_pwrlvl0(usbprn_state_t * usbprnp)26777c478bd9Sstevel@tonic-gate usbprn_pwrlvl0(usbprn_state_t *usbprnp)
26787c478bd9Sstevel@tonic-gate {
26797c478bd9Sstevel@tonic-gate 	int	rval;
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
26827c478bd9Sstevel@tonic-gate 	    "usbprn_pwrlvl0:");
26837c478bd9Sstevel@tonic-gate 
26847c478bd9Sstevel@tonic-gate 	switch (usbprnp->usbprn_dev_state) {
26857c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
26867c478bd9Sstevel@tonic-gate 		/* Deny the powerdown request if the device is busy */
26877c478bd9Sstevel@tonic-gate 		if (usbprnp->usbprn_pm->usbprn_pm_busy != 0) {
26887c478bd9Sstevel@tonic-gate 
26897c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
26907c478bd9Sstevel@tonic-gate 		}
26917c478bd9Sstevel@tonic-gate 
26927c478bd9Sstevel@tonic-gate 		/* Issue USB D3 command to the device here */
26937c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl3(usbprnp->usbprn_dip);
26947c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
26957c478bd9Sstevel@tonic-gate 
26967c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_dev_state = USB_DEV_PWRED_DOWN;
26977c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_pm->usbprn_current_power =
2698112116d8Sfb 		    USB_DEV_OS_PWR_OFF;
26997c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
27007c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
27017c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
27027c478bd9Sstevel@tonic-gate 		/* allow a disconnect/cpr'ed device to go to lower power */
27037c478bd9Sstevel@tonic-gate 
27047c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
27057c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
27067c478bd9Sstevel@tonic-gate 	default:
27077c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27087c478bd9Sstevel@tonic-gate 		    "usbprn_pwrlvl0: illegal dev state");
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
27117c478bd9Sstevel@tonic-gate 	}
27127c478bd9Sstevel@tonic-gate }
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate 
27157c478bd9Sstevel@tonic-gate /*
27167c478bd9Sstevel@tonic-gate  * usbprn_pwrlvl1:
27177c478bd9Sstevel@tonic-gate  *	Functions to handle power transition to OS levels -> 2
27187c478bd9Sstevel@tonic-gate  */
27197c478bd9Sstevel@tonic-gate static int
usbprn_pwrlvl1(usbprn_state_t * usbprnp)27207c478bd9Sstevel@tonic-gate usbprn_pwrlvl1(usbprn_state_t *usbprnp)
27217c478bd9Sstevel@tonic-gate {
27227c478bd9Sstevel@tonic-gate 	int	rval;
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27257c478bd9Sstevel@tonic-gate 	    "usbprn_pwrlvl1:");
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 	/* Issue USB D2 command to the device here */
27287c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl2(usbprnp->usbprn_dip);
27297c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
27307c478bd9Sstevel@tonic-gate 
27317c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
27327c478bd9Sstevel@tonic-gate }
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate /*
27367c478bd9Sstevel@tonic-gate  * usbprn_pwrlvl2:
27377c478bd9Sstevel@tonic-gate  *	Functions to handle power transition to OS levels -> 1
27387c478bd9Sstevel@tonic-gate  */
27397c478bd9Sstevel@tonic-gate static int
usbprn_pwrlvl2(usbprn_state_t * usbprnp)27407c478bd9Sstevel@tonic-gate usbprn_pwrlvl2(usbprn_state_t *usbprnp)
27417c478bd9Sstevel@tonic-gate {
27427c478bd9Sstevel@tonic-gate 	int	rval;
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27457c478bd9Sstevel@tonic-gate 	    "usbprn_pwrlvl2:");
27467c478bd9Sstevel@tonic-gate 
27477c478bd9Sstevel@tonic-gate 	/* Issue USB D1 command to the device here */
27487c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl1(usbprnp->usbprn_dip);
27497c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
27507c478bd9Sstevel@tonic-gate 
27517c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
27527c478bd9Sstevel@tonic-gate }
27537c478bd9Sstevel@tonic-gate 
27547c478bd9Sstevel@tonic-gate 
27557c478bd9Sstevel@tonic-gate /*
27567c478bd9Sstevel@tonic-gate  * usbprn_pwrlvl3:
27577c478bd9Sstevel@tonic-gate  *	Functions to handle power transition to OS level -> 0
27587c478bd9Sstevel@tonic-gate  */
27597c478bd9Sstevel@tonic-gate static int
usbprn_pwrlvl3(usbprn_state_t * usbprnp)27607c478bd9Sstevel@tonic-gate usbprn_pwrlvl3(usbprn_state_t *usbprnp)
27617c478bd9Sstevel@tonic-gate {
27627c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27637c478bd9Sstevel@tonic-gate 	    "usbprn_pwrlvl3:");
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	switch (usbprnp->usbprn_dev_state) {
27667c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
27677c478bd9Sstevel@tonic-gate 		/* Issue USB D0 command to the device here */
27687c478bd9Sstevel@tonic-gate 		(void) usb_set_device_pwrlvl0(usbprnp->usbprn_dip);
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
27717c478bd9Sstevel@tonic-gate 		usbprnp->usbprn_pm->usbprn_current_power =
27727c478bd9Sstevel@tonic-gate 		    USB_DEV_OS_FULL_PWR;
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
27757c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
27767c478bd9Sstevel@tonic-gate 		/* we are already in full power */
27777c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
27787c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
27797c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
27807c478bd9Sstevel@tonic-gate 		/*
27817c478bd9Sstevel@tonic-gate 		 * PM framework tries to put us in full power
27827c478bd9Sstevel@tonic-gate 		 * during system shutdown. If we are disconnected/cpr'ed
27837c478bd9Sstevel@tonic-gate 		 * return success anyways
27847c478bd9Sstevel@tonic-gate 		 */
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
27877c478bd9Sstevel@tonic-gate 	default:
27887c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27897c478bd9Sstevel@tonic-gate 		    "usbprn_pwrlvl3:");
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
27937c478bd9Sstevel@tonic-gate 	}
27947c478bd9Sstevel@tonic-gate }
27957c478bd9Sstevel@tonic-gate 
27967c478bd9Sstevel@tonic-gate 
27977c478bd9Sstevel@tonic-gate /*
27987c478bd9Sstevel@tonic-gate  * usbprn_power :
27997c478bd9Sstevel@tonic-gate  *	Power entry point
28007c478bd9Sstevel@tonic-gate  */
28017c478bd9Sstevel@tonic-gate /* ARGSUSED */
28027c478bd9Sstevel@tonic-gate static int
usbprn_power(dev_info_t * dip,int comp,int level)28037c478bd9Sstevel@tonic-gate usbprn_power(dev_info_t *dip, int comp, int level)
28047c478bd9Sstevel@tonic-gate {
28057c478bd9Sstevel@tonic-gate 	usbprn_state_t	*usbprnp;
28067c478bd9Sstevel@tonic-gate 	usbprn_power_t	*pm;
28077c478bd9Sstevel@tonic-gate 	int		rval = USB_FAILURE;
28087c478bd9Sstevel@tonic-gate 
28097c478bd9Sstevel@tonic-gate 	usbprnp = (usbprn_state_t *)ddi_get_soft_state(usbprn_statep,
2810112116d8Sfb 	    ddi_get_instance(dip));
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
28137c478bd9Sstevel@tonic-gate 	    "usbprn_power: Begin: level=%d", level);
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
28187c478bd9Sstevel@tonic-gate 	pm = usbprnp->usbprn_pm;
28197c478bd9Sstevel@tonic-gate 	ASSERT(pm != NULL);
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 	/* Check if we are transitioning to a legal power level */
28227c478bd9Sstevel@tonic-gate 	if (USB_DEV_PWRSTATE_OK(pm->usbprn_pwr_states, level)) {
28237c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
28247c478bd9Sstevel@tonic-gate 		    "usbprn_power: illegal power level=%d "
28257c478bd9Sstevel@tonic-gate 		    "pwr_states=0x%x", level, pm->usbprn_pwr_states);
28267c478bd9Sstevel@tonic-gate 
28277c478bd9Sstevel@tonic-gate 		goto done;
28287c478bd9Sstevel@tonic-gate 	}
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 	switch (level) {
28317c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_OFF :
28327c478bd9Sstevel@tonic-gate 		rval = usbprn_pwrlvl0(usbprnp);
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate 		break;
28357c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_1 :
28367c478bd9Sstevel@tonic-gate 		rval = usbprn_pwrlvl1(usbprnp);
28377c478bd9Sstevel@tonic-gate 
28387c478bd9Sstevel@tonic-gate 		break;
28397c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_2 :
28407c478bd9Sstevel@tonic-gate 		rval = usbprn_pwrlvl2(usbprnp);
28417c478bd9Sstevel@tonic-gate 
28427c478bd9Sstevel@tonic-gate 		break;
28437c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_FULL_PWR :
28447c478bd9Sstevel@tonic-gate 		rval = usbprn_pwrlvl3(usbprnp);
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 		break;
28477c478bd9Sstevel@tonic-gate 	}
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate done:
28507c478bd9Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
28517c478bd9Sstevel@tonic-gate 
28527c478bd9Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
28557c478bd9Sstevel@tonic-gate }
28567c478bd9Sstevel@tonic-gate 
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate /*
28597c478bd9Sstevel@tonic-gate  * usbprn_print_long:
28607c478bd9Sstevel@tonic-gate  *	Breakup a string which is > USBPRN_PRINT_MAXLINE and print it
28617c478bd9Sstevel@tonic-gate  */
28627c478bd9Sstevel@tonic-gate static void
usbprn_print_long(usbprn_state_t * usbprnp,char * str,int len)28637c478bd9Sstevel@tonic-gate usbprn_print_long(usbprn_state_t *usbprnp, char *str, int len)
28647c478bd9Sstevel@tonic-gate {
28657c478bd9Sstevel@tonic-gate 	char *tmp = str;
28667c478bd9Sstevel@tonic-gate 	char pbuf[USBPRN_PRINT_MAXLINE];
28677c478bd9Sstevel@tonic-gate 
28687c478bd9Sstevel@tonic-gate 	for (;;) {
28697c478bd9Sstevel@tonic-gate 		if (len <= USBPRN_PRINT_MAXLINE) {
28707c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_ATTA,
28717c478bd9Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle, "%s", tmp);
28727c478bd9Sstevel@tonic-gate 
28737c478bd9Sstevel@tonic-gate 			break;
28747c478bd9Sstevel@tonic-gate 		} else {
28757c478bd9Sstevel@tonic-gate 			bcopy(tmp, pbuf, USBPRN_PRINT_MAXLINE);
28767c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_ATTA,
28777c478bd9Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle, "%s", pbuf);
28787c478bd9Sstevel@tonic-gate 			tmp += USBPRN_PRINT_MAXLINE;
28797c478bd9Sstevel@tonic-gate 			len -= USBPRN_PRINT_MAXLINE;
28807c478bd9Sstevel@tonic-gate 		}
28817c478bd9Sstevel@tonic-gate 	}
28827c478bd9Sstevel@tonic-gate }
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate static void
usbprn_pm_busy_component(usbprn_state_t * usbprn_statep)28867c478bd9Sstevel@tonic-gate usbprn_pm_busy_component(usbprn_state_t *usbprn_statep)
28877c478bd9Sstevel@tonic-gate {
28887c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprn_statep->usbprn_mutex));
28897c478bd9Sstevel@tonic-gate 	if (usbprn_statep->usbprn_pm != NULL) {
28907c478bd9Sstevel@tonic-gate 		mutex_enter(&usbprn_statep->usbprn_mutex);
28917c478bd9Sstevel@tonic-gate 		usbprn_statep->usbprn_pm->usbprn_pm_busy++;
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_PM, usbprn_statep->usbprn_log_handle,
28947c478bd9Sstevel@tonic-gate 		    "usbprn_pm_busy_component: %d",
28957c478bd9Sstevel@tonic-gate 		    usbprn_statep->usbprn_pm->usbprn_pm_busy);
28967c478bd9Sstevel@tonic-gate 
28977c478bd9Sstevel@tonic-gate 		mutex_exit(&usbprn_statep->usbprn_mutex);
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 		if (pm_busy_component(usbprn_statep->usbprn_dip, 0) !=
29007c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
29017c478bd9Sstevel@tonic-gate 			mutex_enter(&usbprn_statep->usbprn_mutex);
29027c478bd9Sstevel@tonic-gate 			usbprn_statep->usbprn_pm->usbprn_pm_busy--;
29037c478bd9Sstevel@tonic-gate 
29047c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_PM,
29057c478bd9Sstevel@tonic-gate 			    usbprn_statep->usbprn_log_handle,
29067c478bd9Sstevel@tonic-gate 			    "usbprn_pm_busy_component: %d",
29077c478bd9Sstevel@tonic-gate 			    usbprn_statep->usbprn_pm->usbprn_pm_busy);
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate 			mutex_exit(&usbprn_statep->usbprn_mutex);
29107c478bd9Sstevel@tonic-gate 		}
29117c478bd9Sstevel@tonic-gate 
29127c478bd9Sstevel@tonic-gate 	}
29137c478bd9Sstevel@tonic-gate }
29147c478bd9Sstevel@tonic-gate 
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate static void
usbprn_pm_idle_component(usbprn_state_t * usbprn_statep)29177c478bd9Sstevel@tonic-gate usbprn_pm_idle_component(usbprn_state_t *usbprn_statep)
29187c478bd9Sstevel@tonic-gate {
29197c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprn_statep->usbprn_mutex));
29207c478bd9Sstevel@tonic-gate 	if (usbprn_statep->usbprn_pm != NULL) {
29217c478bd9Sstevel@tonic-gate 		if (pm_idle_component(usbprn_statep->usbprn_dip, 0) ==
29227c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
29237c478bd9Sstevel@tonic-gate 			mutex_enter(&usbprn_statep->usbprn_mutex);
29247c478bd9Sstevel@tonic-gate 			ASSERT(usbprn_statep->usbprn_pm->usbprn_pm_busy > 0);
29257c478bd9Sstevel@tonic-gate 			usbprn_statep->usbprn_pm->usbprn_pm_busy--;
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_PM,
29287c478bd9Sstevel@tonic-gate 			    usbprn_statep->usbprn_log_handle,
29297c478bd9Sstevel@tonic-gate 			    "usbprn_pm_idle_component: %d",
29307c478bd9Sstevel@tonic-gate 			    usbprn_statep->usbprn_pm->usbprn_pm_busy);
29317c478bd9Sstevel@tonic-gate 
29327c478bd9Sstevel@tonic-gate 			mutex_exit(&usbprn_statep->usbprn_mutex);
29337c478bd9Sstevel@tonic-gate 		}
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate 	}
29367c478bd9Sstevel@tonic-gate }
2937