xref: /onnv-gate/usr/src/uts/common/io/usb/clients/printer/usbprn.c (revision 8688:200c0876aa34)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56898Sfb209375  * Common Development and Distribution License (the "License").
66898Sfb209375  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  *
21*8688SRaymond.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
220Sstevel@tonic-gate  * Use is subject to license terms.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Printer Class Driver for USB
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * This driver supports devices that adhere to the USB Printer Class
300Sstevel@tonic-gate  * specification 1.0.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * NOTE: This driver is not DDI compliant in that it uses undocumented
330Sstevel@tonic-gate  * functions for logging (USB_DPRINTF_L*, usb_alloc_log_hdl, usb_free_log_hdl),
340Sstevel@tonic-gate  * and serialization (usb_serialize_access, usb_release_access,
350Sstevel@tonic-gate  * usb_init_serialization, usb_fini_serialization)
360Sstevel@tonic-gate  *
370Sstevel@tonic-gate  * Undocumented functions may go away in a future Solaris OS release.
380Sstevel@tonic-gate  *
390Sstevel@tonic-gate  * Please see the DDK for sample code of these functions, and for the usbskel
400Sstevel@tonic-gate  * skeleton template driver which contains scaled-down versions of these
410Sstevel@tonic-gate  * functions written in a DDI-compliant way.
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
450Sstevel@tonic-gate #define	DEBUG
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate #ifdef __lock_lint
480Sstevel@tonic-gate #define	_MULTI_DATAMODEL
490Sstevel@tonic-gate #endif
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #define	USBDRV_MAJOR_VER	2
520Sstevel@tonic-gate #define	USBDRV_MINOR_VER	0
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include <sys/usb/usba.h>
550Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
560Sstevel@tonic-gate #include <sys/bpp_io.h>
570Sstevel@tonic-gate #include <sys/ecppsys.h>
580Sstevel@tonic-gate #include <sys/prnio.h>
590Sstevel@tonic-gate #include <sys/errno.h>
600Sstevel@tonic-gate #include <sys/usb/clients/printer/usb_printer.h>
610Sstevel@tonic-gate #include <sys/usb/clients/printer/usbprn.h>
627492SZhigang.Lu@Sun.COM #include <sys/strsun.h>
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /* Debugging support */
65880Sfrits uint_t	usbprn_errmask		= (uint_t)PRINT_MASK_ALL;
66880Sfrits uint_t	usbprn_errlevel 	= USB_LOG_L4;
67880Sfrits uint_t	usbprn_instance_debug	= (uint_t)-1;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate /* local variables */
700Sstevel@tonic-gate static uint_t usbprn_ifcap =
710Sstevel@tonic-gate 	PRN_HOTPLUG | PRN_1284_DEVID | PRN_1284_STATUS | PRN_TIMEOUTS;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * Function Prototypes
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate static int	usbprn_attach(dev_info_t *, ddi_attach_cmd_t);
770Sstevel@tonic-gate static int	usbprn_detach(dev_info_t *, ddi_detach_cmd_t);
780Sstevel@tonic-gate static int	usbprn_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
790Sstevel@tonic-gate static void	usbprn_cleanup(dev_info_t *, usbprn_state_t *);
800Sstevel@tonic-gate 
810Sstevel@tonic-gate static int	usbprn_get_descriptors(usbprn_state_t *);
820Sstevel@tonic-gate static int	usbprn_get_device_id(usbprn_state_t *);
830Sstevel@tonic-gate static int	usbprn_get_port_status(usbprn_state_t *);
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static int	usbprn_open(dev_t *, int, int, cred_t *);
860Sstevel@tonic-gate static int	usbprn_close(dev_t, int, int, cred_t *);
870Sstevel@tonic-gate static int	usbprn_open_usb_pipes(usbprn_state_t *);
880Sstevel@tonic-gate static void	usbprn_close_usb_pipes(usbprn_state_t *);
890Sstevel@tonic-gate static int	usbprn_write(dev_t, struct uio *, cred_t *);
900Sstevel@tonic-gate static int	usbprn_read(dev_t, struct uio *, cred_t *);
910Sstevel@tonic-gate static int	usbprn_poll(dev_t, short, int, short *, struct pollhead **);
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static int	usbprn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
940Sstevel@tonic-gate static void	usbprn_minphys(struct buf *);
950Sstevel@tonic-gate static int	usbprn_strategy(struct buf *);
960Sstevel@tonic-gate static int	usbprn_setparms(usbprn_state_t *, intptr_t arg, int);
970Sstevel@tonic-gate static int	usbprn_getparms(usbprn_state_t *, intptr_t, int);
980Sstevel@tonic-gate static void	usbprn_geterr(usbprn_state_t *, intptr_t, int);
990Sstevel@tonic-gate static int	usbprn_testio(usbprn_state_t  *, int);
1000Sstevel@tonic-gate static int	usbprn_ioctl_get_status(usbprn_state_t *);
1010Sstevel@tonic-gate static int	usbprn_prnio_get_status(usbprn_state_t *, intptr_t, int);
1020Sstevel@tonic-gate static int	usbprn_prnio_get_1284_status(usbprn_state_t *, intptr_t, int);
1030Sstevel@tonic-gate static int	usbprn_prnio_get_ifcap(usbprn_state_t *, intptr_t, int);
1040Sstevel@tonic-gate static int	usbprn_prnio_set_ifcap(usbprn_state_t *, intptr_t, int);
1050Sstevel@tonic-gate static int	usbprn_prnio_get_ifinfo(usbprn_state_t *, intptr_t, int);
1060Sstevel@tonic-gate static int	usbprn_prnio_get_1284_devid(usbprn_state_t *, intptr_t, int);
1070Sstevel@tonic-gate static int	usbprn_prnio_get_timeouts(usbprn_state_t *, intptr_t, int);
1080Sstevel@tonic-gate static int	usbprn_prnio_set_timeouts(usbprn_state_t *, intptr_t, int);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static void	usbprn_send_async_bulk_data(usbprn_state_t *);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate static void	usbprn_bulk_xfer_cb(usb_pipe_handle_t, usb_bulk_req_t *);
1130Sstevel@tonic-gate static void	usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t,
1140Sstevel@tonic-gate 		    usb_bulk_req_t *);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static void	usbprn_biodone(usbprn_state_t *, int, int);
1170Sstevel@tonic-gate static char	usbprn_error_state(uchar_t);
1180Sstevel@tonic-gate static void	usbprn_print_long(usbprn_state_t *, char *, int);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /* event handling */
1210Sstevel@tonic-gate static	void	usbprn_restore_device_state(dev_info_t *, usbprn_state_t *);
1220Sstevel@tonic-gate static	int	usbprn_disconnect_event_cb(dev_info_t *);
1230Sstevel@tonic-gate static	int	usbprn_reconnect_event_cb(dev_info_t *);
1240Sstevel@tonic-gate static	int	usbprn_cpr_suspend(dev_info_t *);
1250Sstevel@tonic-gate static	void	usbprn_cpr_resume(dev_info_t *);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static usb_event_t usbprn_events = {
1280Sstevel@tonic-gate 	usbprn_disconnect_event_cb,
1290Sstevel@tonic-gate 	usbprn_reconnect_event_cb,
1300Sstevel@tonic-gate 	NULL, NULL
1310Sstevel@tonic-gate };
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /* PM handling */
1340Sstevel@tonic-gate static	void	usbprn_create_pm_components(dev_info_t *, usbprn_state_t *);
1350Sstevel@tonic-gate static	int	usbprn_power(dev_info_t *, int comp, int level);
1360Sstevel@tonic-gate static	int	usbprn_pwrlvl0(usbprn_state_t *);
1370Sstevel@tonic-gate static	int	usbprn_pwrlvl1(usbprn_state_t *);
1380Sstevel@tonic-gate static	int	usbprn_pwrlvl2(usbprn_state_t *);
1390Sstevel@tonic-gate static	int	usbprn_pwrlvl3(usbprn_state_t *);
1400Sstevel@tonic-gate static	void	usbprn_pm_busy_component(usbprn_state_t *);
1410Sstevel@tonic-gate static	void	usbprn_pm_idle_component(usbprn_state_t *);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /* module loading stuff */
1440Sstevel@tonic-gate struct cb_ops usbprn_cb_ops = {
1450Sstevel@tonic-gate 	usbprn_open,		/* open  */
1460Sstevel@tonic-gate 	usbprn_close,		/* close */
1470Sstevel@tonic-gate 	nulldev,		/* strategy */
1480Sstevel@tonic-gate 	nulldev,		/* print */
1490Sstevel@tonic-gate 	nulldev,		/* dump */
1500Sstevel@tonic-gate 	usbprn_read,		/* read */
1510Sstevel@tonic-gate 	usbprn_write,		/* write */
1520Sstevel@tonic-gate 	usbprn_ioctl,		/* ioctl */
1530Sstevel@tonic-gate 	nulldev,		/* devmap */
1540Sstevel@tonic-gate 	nulldev,		/* mmap */
1550Sstevel@tonic-gate 	nulldev,		/* segmap */
1560Sstevel@tonic-gate 	usbprn_poll,		/* poll */
1570Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
1580Sstevel@tonic-gate 	NULL,			/* streamtab  */
1590Sstevel@tonic-gate 	D_64BIT | D_MP
1600Sstevel@tonic-gate };
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static struct dev_ops usbprn_ops = {
1630Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1640Sstevel@tonic-gate 	0,			/* refcnt  */
1650Sstevel@tonic-gate 	usbprn_info,		/* info */
1660Sstevel@tonic-gate 	nulldev,		/* identify */
1670Sstevel@tonic-gate 	nulldev,		/* probe */
1680Sstevel@tonic-gate 	usbprn_attach,		/* attach */
1690Sstevel@tonic-gate 	usbprn_detach,		/* detach */
1700Sstevel@tonic-gate 	nodev,			/* reset */
1710Sstevel@tonic-gate 	&usbprn_cb_ops,		/* driver operations */
1720Sstevel@tonic-gate 	NULL,			/* bus operations */
1737656SSherry.Moore@Sun.COM 	usbprn_power,		/* power */
174*8688SRaymond.Chen@Sun.COM 	ddi_quiesce_not_needed,	/* devo_quiesce */
1750Sstevel@tonic-gate };
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static struct modldrv usbprnmodldrv =	{
1780Sstevel@tonic-gate 	&mod_driverops,
1797425SGongtian.Zhao@Sun.COM 	"USB printer client driver",
1800Sstevel@tonic-gate 	&usbprn_ops
1810Sstevel@tonic-gate };
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate static struct modlinkage modlinkage = {
1840Sstevel@tonic-gate 	MODREV_1,
1850Sstevel@tonic-gate 	&usbprnmodldrv,
1860Sstevel@tonic-gate 	NULL,
1870Sstevel@tonic-gate };
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /* local variables */
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate /* soft state structures */
1920Sstevel@tonic-gate #define	USBPRN_INITIAL_SOFT_SPACE	1
1930Sstevel@tonic-gate static void *usbprn_statep;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate static int usbprn_max_xfer_size = USBPRN_MAX_XFER_SIZE;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /* prnio support */
1980Sstevel@tonic-gate static const char usbprn_prnio_ifinfo[] = PRN_USB;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate int
_init(void)2020Sstevel@tonic-gate _init(void)
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate 	int rval;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	if ((rval = ddi_soft_state_init(&usbprn_statep,
2070Sstevel@tonic-gate 	    sizeof (usbprn_state_t), USBPRN_INITIAL_SOFT_SPACE)) != 0) {
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 		return (rval);
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
2130Sstevel@tonic-gate 		ddi_soft_state_fini(&usbprn_statep);
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	return (rval);
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate int
_fini(void)2210Sstevel@tonic-gate _fini(void)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	int rval;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) != 0) {
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		return (rval);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	ddi_soft_state_fini(&usbprn_statep);
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	return (rval);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2370Sstevel@tonic-gate _info(struct modinfo *modinfop)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate  * usbprn_info:
2450Sstevel@tonic-gate  *	Get minor number, soft state structure, etc.
2460Sstevel@tonic-gate  */
2470Sstevel@tonic-gate /*ARGSUSED*/
2480Sstevel@tonic-gate static int
usbprn_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2490Sstevel@tonic-gate usbprn_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
2500Sstevel@tonic-gate 			void *arg, void **result)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	usbprn_state_t	*usbprnp;
2530Sstevel@tonic-gate 	int		error = DDI_FAILURE;
2540Sstevel@tonic-gate 	minor_t		minor = getminor((dev_t)arg);
2550Sstevel@tonic-gate 	int		instance = USBPRN_MINOR_TO_INSTANCE(minor);
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	switch (infocmd) {
2580Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2590Sstevel@tonic-gate 		if ((usbprnp = ddi_get_soft_state(usbprn_statep,
2600Sstevel@tonic-gate 		    instance)) != NULL) {
2610Sstevel@tonic-gate 			*result = usbprnp->usbprn_dip;
2620Sstevel@tonic-gate 			if (*result != NULL) {
2630Sstevel@tonic-gate 				error = DDI_SUCCESS;
2640Sstevel@tonic-gate 			}
2650Sstevel@tonic-gate 		} else {
2660Sstevel@tonic-gate 			*result = NULL;
2670Sstevel@tonic-gate 		}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 		break;
2700Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2710Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
2720Sstevel@tonic-gate 		error = DDI_SUCCESS;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 		break;
2750Sstevel@tonic-gate 	default:
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 		break;
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	return (error);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate  * usbprn_attach:
2860Sstevel@tonic-gate  *	Attach driver
2870Sstevel@tonic-gate  *	Get the descriptor information
2880Sstevel@tonic-gate  *	Get the device id
2890Sstevel@tonic-gate  *	Reset the device
2900Sstevel@tonic-gate  *	Get the port status
2910Sstevel@tonic-gate  */
2920Sstevel@tonic-gate static int
usbprn_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2930Sstevel@tonic-gate usbprn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
2960Sstevel@tonic-gate 	usbprn_state_t		*usbprnp = NULL;
2970Sstevel@tonic-gate 	size_t			sz;
2980Sstevel@tonic-gate 	usb_ugen_info_t 	usb_ugen_info;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	switch (cmd) {
3010Sstevel@tonic-gate 	case DDI_ATTACH:
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 		break;
3040Sstevel@tonic-gate 	case DDI_RESUME:
3050Sstevel@tonic-gate 		usbprn_cpr_resume(dip);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 		return (DDI_SUCCESS);
3080Sstevel@tonic-gate 	default:
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		return (DDI_FAILURE);
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(usbprn_statep, instance) == DDI_SUCCESS) {
3140Sstevel@tonic-gate 		usbprnp = ddi_get_soft_state(usbprn_statep, instance);
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 	if (usbprnp == NULL)  {
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		return (DDI_FAILURE);
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	usbprnp->usbprn_instance = instance;
3220Sstevel@tonic-gate 	usbprnp->usbprn_dip	= dip;
3230Sstevel@tonic-gate 	usbprnp->usbprn_log_handle = usb_alloc_log_hdl(dip,
3246898Sfb209375 	    "prn", &usbprn_errlevel,
3256898Sfb209375 	    &usbprn_errmask, &usbprn_instance_debug, 0);
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3280Sstevel@tonic-gate 	    "usbprn_attach: cmd=%x", cmd);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
3310Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3320Sstevel@tonic-gate 		    "usb_client_attach failed");
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 		goto fail;
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 	if (usb_get_dev_data(dip, &usbprnp->usbprn_dev_data,
3370Sstevel@tonic-gate 	    USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
3380Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3390Sstevel@tonic-gate 		    "usb_get_dev_data failed");
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		goto fail;
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/* Initialize locks and conditional variables */
3450Sstevel@tonic-gate 	mutex_init(&usbprnp->usbprn_mutex, NULL, MUTEX_DRIVER,
3466898Sfb209375 	    usbprnp->usbprn_dev_data->dev_iblock_cookie);
3470Sstevel@tonic-gate 	usbprnp->usbprn_write_acc = usb_init_serialization(dip,
3486898Sfb209375 	    USB_INIT_SER_CHECK_SAME_THREAD);
3490Sstevel@tonic-gate 	usbprnp->usbprn_ser_acc = usb_init_serialization(dip,
3500Sstevel@tonic-gate 	    USB_INIT_SER_CHECK_SAME_THREAD);
3510Sstevel@tonic-gate 	usbprnp->usbprn_dev_acc = usb_init_serialization(dip, 0);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	usbprnp->usbprn_flags |= USBPRN_LOCKS_INIT_DONE;
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	/* Obtain all the relevant descriptors */
3560Sstevel@tonic-gate 	if (usbprn_get_descriptors(usbprnp) != USB_SUCCESS) {
3570Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3580Sstevel@tonic-gate 		    "usb get descriptors failed");
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 		goto fail;
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	usbprnp->usbprn_def_ph = usbprnp->usbprn_dev_data->dev_default_ph;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/* Obtain the device id */
3660Sstevel@tonic-gate 	(void) usbprn_get_device_id(usbprnp);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	/* Get the port status */
3690Sstevel@tonic-gate 	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
3700Sstevel@tonic-gate 		/* some printers fail on the first */
3710Sstevel@tonic-gate 		if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
3720Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
3730Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
3740Sstevel@tonic-gate 			    "usb get port status failed");
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 			goto fail;
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3810Sstevel@tonic-gate 	    "usbprn_attach: printer status=0x%x", usbprnp->usbprn_last_status);
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	if ((usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR) == 0) {
3840Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3850Sstevel@tonic-gate 		    "usbprn_attach: error occurred with the printer");
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	/*
3890Sstevel@tonic-gate 	 * Create minor node based on information from the
3900Sstevel@tonic-gate 	 * descriptors
3910Sstevel@tonic-gate 	 */
3920Sstevel@tonic-gate 	if ((ddi_create_minor_node(dip, "printer", S_IFCHR,
3930Sstevel@tonic-gate 	    instance << USBPRN_MINOR_INSTANCE_SHIFT,
3940Sstevel@tonic-gate 	    DDI_NT_PRINTER, 0)) != DDI_SUCCESS) {
395978Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
3960Sstevel@tonic-gate 		    "usbprn_attach: cannot create minor node");
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		goto fail;
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	usbprnp->usbprn_setparms.write_timeout = USBPRN_XFER_TIMEOUT;
4020Sstevel@tonic-gate 	usbprnp->usbprn_setparms.mode =  ECPP_CENTRONICS;
4030Sstevel@tonic-gate 	usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	if (usb_pipe_get_max_bulk_transfer_size(usbprnp->usbprn_dip, &sz)) {
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 		goto fail;
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	usbprnp->usbprn_max_bulk_xfer_size = sz;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
4130Sstevel@tonic-gate 	    "usbprn_attach: xfer_size=0x%lx", sz);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	/* enable PM */
4160Sstevel@tonic-gate 	usbprn_create_pm_components(dip, usbprnp);
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	/* Register for events */
4190Sstevel@tonic-gate 	if (usb_register_event_cbs(dip, &usbprn_events, 0) != USB_SUCCESS) {
420978Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
4210Sstevel@tonic-gate 		    "usbprn_attach: usb_register_event_cbs failed");
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		goto fail;
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	usb_free_dev_data(dip, usbprnp->usbprn_dev_data);
4270Sstevel@tonic-gate 	usbprnp->usbprn_dev_data = NULL;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	if (usb_owns_device(dip)) {
4300Sstevel@tonic-gate 		/* get a ugen handle */
4310Sstevel@tonic-gate 		bzero(&usb_ugen_info, sizeof (usb_ugen_info));
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_flags = 0;
4340Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
4356898Sfb209375 		    (dev_t)USBPRN_MINOR_UGEN_BITS_MASK;
4360Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_instance_mask =
4376898Sfb209375 		    (dev_t)~USBPRN_MINOR_UGEN_BITS_MASK;
4380Sstevel@tonic-gate 		usbprnp->usbprn_ugen_hdl =
4396898Sfb209375 		    usb_ugen_get_hdl(dip, &usb_ugen_info);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		if (usb_ugen_attach(usbprnp->usbprn_ugen_hdl, cmd) !=
4420Sstevel@tonic-gate 		    USB_SUCCESS) {
4430Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
4440Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
4450Sstevel@tonic-gate 			    "usb_ugen_attach failed");
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 			usb_ugen_release_hdl(usbprnp->usbprn_ugen_hdl);
4480Sstevel@tonic-gate 			usbprnp->usbprn_ugen_hdl = NULL;
4490Sstevel@tonic-gate 		}
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	/* Report device */
4530Sstevel@tonic-gate 	ddi_report_dev(dip);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
4560Sstevel@tonic-gate 	    "usbprn_attach: done");
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	return (DDI_SUCCESS);
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate fail:
4610Sstevel@tonic-gate 	if (usbprnp) {
4620Sstevel@tonic-gate 		usbprn_cleanup(dip, usbprnp);
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	return (DDI_FAILURE);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate  * usbprn_detach:
4710Sstevel@tonic-gate  *	detach or suspend driver instance
4720Sstevel@tonic-gate  */
4730Sstevel@tonic-gate static int
usbprn_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4740Sstevel@tonic-gate usbprn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4750Sstevel@tonic-gate {
4760Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
4770Sstevel@tonic-gate 	usbprn_state_t	*usbprnp;
4780Sstevel@tonic-gate 	int		rval = DDI_FAILURE;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	usbprnp = ddi_get_soft_state(usbprn_statep, instance);
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
4830Sstevel@tonic-gate 	    "usbprn_detach: cmd=%x", cmd);
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	switch (cmd) {
4860Sstevel@tonic-gate 	case DDI_DETACH:
4870Sstevel@tonic-gate 		ASSERT((usbprnp->usbprn_flags & USBPRN_OPEN) == 0);
4880Sstevel@tonic-gate 		usbprn_cleanup(dip, usbprnp);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 		return (DDI_SUCCESS);
4910Sstevel@tonic-gate 	case DDI_SUSPEND:
4920Sstevel@tonic-gate 		rval = usbprn_cpr_suspend(dip);
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS :
4950Sstevel@tonic-gate 		    DDI_FAILURE);
4960Sstevel@tonic-gate 	default:
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 		return (rval);
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate /*
5040Sstevel@tonic-gate  * usbprn_cleanup:
5050Sstevel@tonic-gate  *	clean up the driver state
5060Sstevel@tonic-gate  */
5070Sstevel@tonic-gate static void
usbprn_cleanup(dev_info_t * dip,usbprn_state_t * usbprnp)5080Sstevel@tonic-gate usbprn_cleanup(dev_info_t *dip, usbprn_state_t *usbprnp)
5090Sstevel@tonic-gate {
5100Sstevel@tonic-gate 	usbprn_power_t	*usbprnpm = usbprnp->usbprn_pm;
5110Sstevel@tonic-gate 	int		rval = 0;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
5140Sstevel@tonic-gate 	    "usbprn_cleanup: Start");
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	ASSERT(usbprnp != NULL);
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_LOCKS_INIT_DONE) {
5190Sstevel@tonic-gate 		/*
5200Sstevel@tonic-gate 		 * Disable the event callbacks first, after this point, event
5210Sstevel@tonic-gate 		 * callbacks will never get called. Note we shouldn't hold
5220Sstevel@tonic-gate 		 * mutex while unregistering events because there may be a
5230Sstevel@tonic-gate 		 * competing event callback thread. Event callbacks are done
5240Sstevel@tonic-gate 		 * with ndi mutex held and this can cause a potential deadlock.
5250Sstevel@tonic-gate 		 */
5260Sstevel@tonic-gate 		usb_unregister_event_cbs(dip, &usbprn_events);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
5290Sstevel@tonic-gate 		if ((usbprnpm) &&
5300Sstevel@tonic-gate 		    (usbprnp->usbprn_dev_state != USB_DEV_DISCONNECTED)) {
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 			mutex_exit(&usbprnp->usbprn_mutex);
5330Sstevel@tonic-gate 			usbprn_pm_busy_component(usbprnp);
5340Sstevel@tonic-gate 			mutex_enter(&usbprnp->usbprn_mutex);
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 			if (usbprnpm->usbprn_wakeup_enabled) {
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 				mutex_exit(&usbprnp->usbprn_mutex);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 				(void) pm_raise_power(dip, 0,
5410Sstevel@tonic-gate 				    USB_DEV_OS_FULL_PWR);
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 				if ((rval = usb_handle_remote_wakeup(dip,
5440Sstevel@tonic-gate 				    USB_REMOTE_WAKEUP_DISABLE)) !=
5450Sstevel@tonic-gate 				    USB_SUCCESS) {
5460Sstevel@tonic-gate 					USB_DPRINTF_L2(PRINT_MASK_ALL,
5470Sstevel@tonic-gate 					    usbprnp->usbprn_log_handle,
5480Sstevel@tonic-gate 					    "usbprn_cleanup: "
5490Sstevel@tonic-gate 					    "disable remote wakeup "
5500Sstevel@tonic-gate 					    "failed, rval=%d", rval);
5510Sstevel@tonic-gate 				}
5520Sstevel@tonic-gate 			} else {
5530Sstevel@tonic-gate 				mutex_exit(&usbprnp->usbprn_mutex);
5540Sstevel@tonic-gate 			}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 			(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
5570Sstevel@tonic-gate 			usbprn_pm_idle_component(usbprnp);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 			mutex_enter(&usbprnp->usbprn_mutex);
5600Sstevel@tonic-gate 		}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		if (usbprnp->usbprn_device_id) {
5670Sstevel@tonic-gate 			kmem_free(usbprnp->usbprn_device_id,
5680Sstevel@tonic-gate 			    usbprnp->usbprn_device_id_len + 1);
5690Sstevel@tonic-gate 		}
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 		mutex_destroy(&usbprnp->usbprn_mutex);
5720Sstevel@tonic-gate 		usb_fini_serialization(usbprnp->usbprn_dev_acc);
5730Sstevel@tonic-gate 		usb_fini_serialization(usbprnp->usbprn_ser_acc);
5740Sstevel@tonic-gate 		usb_fini_serialization(usbprnp->usbprn_write_acc);
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	if (usbprnpm) {
5780Sstevel@tonic-gate 		kmem_free(usbprnpm, sizeof (usbprn_power_t));
5790Sstevel@tonic-gate 	}
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
5820Sstevel@tonic-gate 	    "usbprn_cleanup: End");
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (usbprnp->usbprn_ugen_hdl) {
5850Sstevel@tonic-gate 		(void) usb_ugen_detach(usbprnp->usbprn_ugen_hdl, DDI_DETACH);
5860Sstevel@tonic-gate 		usb_ugen_release_hdl(usbprnp->usbprn_ugen_hdl);
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	/* unregister with USBA */
5900Sstevel@tonic-gate 	usb_client_detach(dip, usbprnp->usbprn_dev_data);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	usb_free_log_hdl(usbprnp->usbprn_log_handle);
5930Sstevel@tonic-gate 	ddi_prop_remove_all(dip);
5940Sstevel@tonic-gate 	ddi_soft_state_free(usbprn_statep, usbprnp->usbprn_instance);
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate /*
5990Sstevel@tonic-gate  * usbprn_cpr_suspend:
6000Sstevel@tonic-gate  *	prepare to be suspended
6010Sstevel@tonic-gate  */
6020Sstevel@tonic-gate static int
usbprn_cpr_suspend(dev_info_t * dip)6030Sstevel@tonic-gate usbprn_cpr_suspend(dev_info_t *dip)
6040Sstevel@tonic-gate {
6050Sstevel@tonic-gate 	usbprn_state_t	*usbprnp;
6060Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
6070Sstevel@tonic-gate 	int		rval = USB_FAILURE;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	usbprnp = ddi_get_soft_state(usbprn_statep, instance);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
6120Sstevel@tonic-gate 	    "usbprn_cpr_suspend");
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	if ((usbprnp->usbprn_flags & USBPRN_OPEN) != 0) {
6190Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_CPR,
6220Sstevel@tonic-gate 		    usbprnp->usbprn_log_handle,
6230Sstevel@tonic-gate 		    "usbprn_cpr_suspend: "
6240Sstevel@tonic-gate 		    "Device is open.  Can't suspend");
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	} else {
6270Sstevel@tonic-gate 		usbprnp->usbprn_dev_state = USB_DEV_SUSPENDED;
6280Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
6310Sstevel@tonic-gate 		    "usbprn_cpr_suspend: SUCCESS");
6320Sstevel@tonic-gate 		rval = USB_SUCCESS;
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && usbprnp->usbprn_ugen_hdl) {
6370Sstevel@tonic-gate 		rval = usb_ugen_detach(usbprnp->usbprn_ugen_hdl,
6386898Sfb209375 		    DDI_SUSPEND);
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	return (rval);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate static void
usbprn_cpr_resume(dev_info_t * dip)6460Sstevel@tonic-gate usbprn_cpr_resume(dev_info_t *dip)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
6490Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep, instance);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
6520Sstevel@tonic-gate 	    "usbprn_cpr_resume");
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/* Needed as power up state of dev is "unknown" to system */
6550Sstevel@tonic-gate 	usbprn_pm_busy_component(usbprnp);
6560Sstevel@tonic-gate 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	usbprn_restore_device_state(dip, usbprnp);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	usbprn_pm_idle_component(usbprnp);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	if (usbprnp->usbprn_ugen_hdl) {
6630Sstevel@tonic-gate 		(void) usb_ugen_attach(usbprnp->usbprn_ugen_hdl,
6646898Sfb209375 		    DDI_RESUME);
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate  * usbprn_get_descriptors:
6710Sstevel@tonic-gate  *	Obtain all the descriptors for the device
6720Sstevel@tonic-gate  */
6730Sstevel@tonic-gate static int
usbprn_get_descriptors(usbprn_state_t * usbprnp)6740Sstevel@tonic-gate usbprn_get_descriptors(usbprn_state_t *usbprnp)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate 	int			interface;
6770Sstevel@tonic-gate 	usb_client_dev_data_t	*dev_data =
6786898Sfb209375 	    usbprnp->usbprn_dev_data;
6790Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
6800Sstevel@tonic-gate 	usb_cfg_data_t		*cfg_data;
6810Sstevel@tonic-gate 	usb_ep_data_t		*ep_data;
6820Sstevel@tonic-gate 	dev_info_t		*dip = usbprnp->usbprn_dip;
6830Sstevel@tonic-gate 	int			alt, rval;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	/*
6880Sstevel@tonic-gate 	 * Section 4.2.1 of the spec says the printer could have
6890Sstevel@tonic-gate 	 * multiple configurations.  This driver is just for one
6900Sstevel@tonic-gate 	 * configuration interface and one interface.
6910Sstevel@tonic-gate 	 */
6920Sstevel@tonic-gate 	interface = dev_data->dev_curr_if;
6930Sstevel@tonic-gate 	cfg_data = dev_data->dev_curr_cfg;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/* find alternate that supports BI/UNI protocol */
6960Sstevel@tonic-gate 	for (alt = 0; alt < cfg_data->cfg_if[interface].if_n_alt; alt++) {
6970Sstevel@tonic-gate 		altif_data = &cfg_data->cfg_if[interface].if_alt[alt];
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 		if ((altif_data->altif_descr.bInterfaceProtocol ==
7000Sstevel@tonic-gate 		    USB_PROTO_PRINTER_UNI) ||
7010Sstevel@tonic-gate 		    (altif_data->altif_descr.bInterfaceProtocol ==
7020Sstevel@tonic-gate 		    USB_PROTO_PRINTER_BI)) {
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 			break;
7050Sstevel@tonic-gate 		} else {
7060Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA,
7070Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
7080Sstevel@tonic-gate 			    "alternate %d not supported", alt);
7090Sstevel@tonic-gate 		}
7100Sstevel@tonic-gate 	}
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	if (alt == cfg_data->cfg_if[interface].if_n_alt) {
7130Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
7140Sstevel@tonic-gate 		    "usbprn_get_descriptors: no alternate");
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		return (USB_FAILURE);
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	if ((rval = usb_set_alt_if(dip, interface, alt, USB_FLAGS_SLEEP,
7210Sstevel@tonic-gate 	    NULL, NULL)) != USB_SUCCESS) {
7220Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
7230Sstevel@tonic-gate 		    "usbprn_get_descriptors: set alternate failed (%d)",
7240Sstevel@tonic-gate 		    rval);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 		return (rval);
7270Sstevel@tonic-gate 	}
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	usbprnp->usbprn_config_descr = cfg_data->cfg_descr;
7300Sstevel@tonic-gate 	usbprnp->usbprn_if_descr = altif_data->altif_descr;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	/*
7330Sstevel@tonic-gate 	 * find the endpoint descriptors. There will be a bulk-out endpoint
7340Sstevel@tonic-gate 	 * and an optional bulk-in endpoint.
7350Sstevel@tonic-gate 	 */
7360Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, alt, 0,
7370Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
7380Sstevel@tonic-gate 		usbprnp->usbprn_bulk_out.ps_ept_descr = ep_data->ep_descr;
7390Sstevel@tonic-gate 	}
7400Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, alt, 0,
7410Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
7420Sstevel@tonic-gate 		usbprnp->usbprn_bulk_in.ps_ept_descr = ep_data->ep_descr;
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	return (USB_SUCCESS);
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate /*
7500Sstevel@tonic-gate  * usbprn_get_device_id:
7510Sstevel@tonic-gate  *	Get the device id as described in 4.2.1 of the specification
7520Sstevel@tonic-gate  *	Lexmark printer returns 2 bytes when asked for 8 bytes
7530Sstevel@tonic-gate  *	We are ignoring data over and underrun.
7540Sstevel@tonic-gate  *	This is a synchronous function
7550Sstevel@tonic-gate  */
7560Sstevel@tonic-gate static int
usbprn_get_device_id(usbprn_state_t * usbprnp)7570Sstevel@tonic-gate usbprn_get_device_id(usbprn_state_t *usbprnp)
7580Sstevel@tonic-gate {
7590Sstevel@tonic-gate 	int			len, n;
7600Sstevel@tonic-gate 	mblk_t			*data = NULL;
7610Sstevel@tonic-gate 	usb_cr_t		completion_reason;
7620Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags;
7630Sstevel@tonic-gate 	int			rval = USB_FAILURE;
7640Sstevel@tonic-gate 	usb_ctrl_setup_t setup = {
7650Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST |	/* bmRequestType */
7666898Sfb209375 	    USB_DEV_REQ_TYPE_CLASS |
7676898Sfb209375 	    USB_DEV_REQ_RCPT_IF,
7680Sstevel@tonic-gate 	    USB_PRINTER_GET_DEVICE_ID,	/* bRequest */
7690Sstevel@tonic-gate 	    0,				/* wValue: fill in later */
7700Sstevel@tonic-gate 	    0,				/* wIndex: fill in later  */
7710Sstevel@tonic-gate 	    0,				/* wLength: fill in later */
7720Sstevel@tonic-gate 	    0				/* attributes */
7736898Sfb209375 	    };
7740Sstevel@tonic-gate 	void			*ptr;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
7770Sstevel@tonic-gate 	    "usbprn_get_device_id: Begin");
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	setup.wIndex = (usbprnp->usbprn_if_descr.bInterfaceNumber << 0x8) |
7826898Sfb209375 	    (usbprnp->usbprn_if_descr.bAlternateSetting);
7830Sstevel@tonic-gate 	setup.wLength = USBPRN_MAX_DEVICE_ID_LENGTH;
7840Sstevel@tonic-gate 	setup.wValue = usbprnp->usbprn_config_descr.iConfiguration;
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	/*
7870Sstevel@tonic-gate 	 * This is always a sync request as this will never
7880Sstevel@tonic-gate 	 * be called in interrupt context.
7890Sstevel@tonic-gate 	 * First get the first two bytes that gives the length
7900Sstevel@tonic-gate 	 * of the device id string; then get the whole string
7910Sstevel@tonic-gate 	 */
7920Sstevel@tonic-gate 	if (usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph, &setup,
7930Sstevel@tonic-gate 	    &data, &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
7960Sstevel@tonic-gate 		    "usbprn_get_device_id: First sync command failed, cr=%d ",
7970Sstevel@tonic-gate 		    completion_reason);
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 		/*
8000Sstevel@tonic-gate 		 * some devices return more than requested. as long as
8010Sstevel@tonic-gate 		 * we get the first two bytes, we can continue
8020Sstevel@tonic-gate 		 */
8030Sstevel@tonic-gate 		if (((completion_reason != USB_CR_DATA_OVERRUN) &&
8040Sstevel@tonic-gate 		    (completion_reason != USB_CR_DATA_UNDERRUN)) ||
8050Sstevel@tonic-gate 		    (data == NULL)) {
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 			goto done;
8080Sstevel@tonic-gate 		}
8090Sstevel@tonic-gate 	}
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	ASSERT(data);
8127492SZhigang.Lu@Sun.COM 	n = MBLKL(data);
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (n < 2) {
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 		goto done;
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	len = (((*data->b_rptr) << 0x8) | (*(data->b_rptr+1)));
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	/*
8220Sstevel@tonic-gate 	 * Std 1284-1994, chapter 7.6:
8230Sstevel@tonic-gate 	 *	Length values of x'0000', x'0001' and x'0002' are reserved
8240Sstevel@tonic-gate 	 */
8250Sstevel@tonic-gate 	if (len < 3) {
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 		goto done;
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
8310Sstevel@tonic-gate 	    "usbprn_get_device_id: device id length=%d", len);
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	/* did we get enough data */
8340Sstevel@tonic-gate 	if (len > n) {
8350Sstevel@tonic-gate 		freemsg(data);
8360Sstevel@tonic-gate 		data = NULL;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 		setup.wLength = (uint16_t)len;
8390Sstevel@tonic-gate 		if ((rval = usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph,
8400Sstevel@tonic-gate 		    &setup, &data, &completion_reason, &cb_flags, 0)) !=
8410Sstevel@tonic-gate 		    USB_SUCCESS) {
8420Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
8430Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
8440Sstevel@tonic-gate 			    "usbprn_get_device_id: 2nd command failed "
8450Sstevel@tonic-gate 			    "cr=%d cb_flags=0x%x",
8460Sstevel@tonic-gate 			    completion_reason, cb_flags);
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 			goto done;
8490Sstevel@tonic-gate 		}
8500Sstevel@tonic-gate 
8517492SZhigang.Lu@Sun.COM 		ASSERT(len == MBLKL(data));
8520Sstevel@tonic-gate 	}
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
8556898Sfb209375 	    "usbprn_get_device_id: returned data length=%ld",
8567492SZhigang.Lu@Sun.COM 	    (long)(MBLKL(data)));
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	ptr = kmem_zalloc(len + 1, KM_SLEEP);
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
8610Sstevel@tonic-gate 	usbprnp->usbprn_device_id_len = len;
8620Sstevel@tonic-gate 	usbprnp->usbprn_device_id = ptr;
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	bcopy(data->b_rptr, usbprnp->usbprn_device_id,
8656898Sfb209375 	    usbprnp->usbprn_device_id_len);
8660Sstevel@tonic-gate 	usbprnp->usbprn_device_id[usbprnp->usbprn_device_id_len] = '\0';
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	/* Length is in the first two bytes, dump string in logbuf */
8690Sstevel@tonic-gate 	usbprn_print_long(usbprnp, usbprnp->usbprn_device_id + 2,
8700Sstevel@tonic-gate 	    usbprnp->usbprn_device_id_len - 2);
8710Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	rval = USB_SUCCESS;
8740Sstevel@tonic-gate done:
8750Sstevel@tonic-gate 	freemsg(data);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
8780Sstevel@tonic-gate 	    "usbprn_get_device_id: rval=%d", rval);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	return (rval);
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate /*
8850Sstevel@tonic-gate  * usbprn_get_port_status:
8860Sstevel@tonic-gate  *	Get the port status.
8870Sstevel@tonic-gate  *	This is a synchronous function
8880Sstevel@tonic-gate  */
8890Sstevel@tonic-gate static int
usbprn_get_port_status(usbprn_state_t * usbprnp)8900Sstevel@tonic-gate usbprn_get_port_status(usbprn_state_t  *usbprnp)
8910Sstevel@tonic-gate {
8920Sstevel@tonic-gate 	mblk_t			*data = NULL;
8930Sstevel@tonic-gate 	usb_cr_t		completion_reason;
8940Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags;
8950Sstevel@tonic-gate 	usb_ctrl_setup_t setup = {
8960Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST |	/* bmRequestType */
8976898Sfb209375 	    USB_DEV_REQ_TYPE_CLASS |
8986898Sfb209375 	    USB_DEV_REQ_RCPT_IF,
8990Sstevel@tonic-gate 	    USB_PRINTER_GET_PORT_STATUS, /* bRequest */
9000Sstevel@tonic-gate 	    0,				/* wValue */
9010Sstevel@tonic-gate 	    0,				/* wIndex: fill in later  */
9020Sstevel@tonic-gate 	    1,				/* wLength */
9030Sstevel@tonic-gate 	    0				/* attributes */
9046898Sfb209375 	    };
9050Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
9080Sstevel@tonic-gate 	    "usbprn_get_port_status: Begin");
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	setup.wIndex = usbprnp->usbprn_if_descr.bInterfaceNumber;
9110Sstevel@tonic-gate 	if (usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph,
9120Sstevel@tonic-gate 	    &setup, &data, &completion_reason, &cb_flags, 0) !=
9130Sstevel@tonic-gate 	    USB_SUCCESS) {
9140Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
9150Sstevel@tonic-gate 		    "usbprn_get_port_status: Sync command failed "
9160Sstevel@tonic-gate 		    "cr=%d cb_flags=0x%x", completion_reason, cb_flags);
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 		freemsg(data);
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 		return (USB_FAILURE);
9210Sstevel@tonic-gate 	} else {
9220Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 		ASSERT(data);
9257492SZhigang.Lu@Sun.COM 		ASSERT(MBLKL(data) == 1);
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 		usbprnp->usbprn_last_status = *data->b_rptr;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
9300Sstevel@tonic-gate 		    "usbprn_get_port_status(sync): status=0x%x",
9310Sstevel@tonic-gate 		    usbprnp->usbprn_last_status);
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9340Sstevel@tonic-gate 		freemsg(data);
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 		return (USB_SUCCESS);
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate  * usbprn_open:
9430Sstevel@tonic-gate  *	Open the pipes
9440Sstevel@tonic-gate  */
9450Sstevel@tonic-gate /*ARGSUSED*/
9460Sstevel@tonic-gate static int
usbprn_open(dev_t * devp,int flag,int sflag,cred_t * credp)9470Sstevel@tonic-gate usbprn_open(dev_t *devp, int flag, int sflag, cred_t *credp)
9480Sstevel@tonic-gate {
9490Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
9506898Sfb209375 	    USBPRN_MINOR_TO_INSTANCE(getminor(*devp)));
9510Sstevel@tonic-gate 	int rval = 0;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	if (usbprnp == NULL) {
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 		return (ENXIO);
9560Sstevel@tonic-gate 	}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
9590Sstevel@tonic-gate 	    "usbprn_open:");
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 	/* Fail open on a disconnected device */
9640Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
9650Sstevel@tonic-gate 	if (usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED) {
9660Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9670Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 		return (ENODEV);
9700Sstevel@tonic-gate 	}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	/* cannot happen? but just in case */
9730Sstevel@tonic-gate 	if (usbprnp->usbprn_dev_state == USB_DEV_SUSPENDED) {
9740Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9750Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 		return (EIO);
9780Sstevel@tonic-gate 	}
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	if (getminor(*devp) & USBPRN_MINOR_UGEN_BITS_MASK) {
9810Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 		rval = usb_ugen_open(usbprnp->usbprn_ugen_hdl,
9846898Sfb209375 		    devp, flag, sflag, credp);
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 		return (rval);
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	/* Exit if this instance is already open */
9920Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
9930Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
9940Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 		return (EBUSY);
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	/* raise power */
10010Sstevel@tonic-gate 	usbprn_pm_busy_component(usbprnp);
10020Sstevel@tonic-gate 	(void) pm_raise_power(usbprnp->usbprn_dip,
10036898Sfb209375 	    0, USB_DEV_OS_FULL_PWR);
10040Sstevel@tonic-gate 	/* initialize some softstate data */
10050Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
10060Sstevel@tonic-gate 	usbprnp->usbprn_prn_timeouts.tmo_forward =
10076898Sfb209375 	    usbprnp->usbprn_setparms.write_timeout;
10080Sstevel@tonic-gate 	usbprnp->usbprn_prn_timeouts.tmo_reverse = 0;
10090Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	if (usbprn_open_usb_pipes(usbprnp) != USB_SUCCESS) {
10120Sstevel@tonic-gate 
1013978Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
10140Sstevel@tonic-gate 		    "usbprn_open: pipe open failed");
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
10170Sstevel@tonic-gate 		usbprn_pm_idle_component(usbprnp);
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 		return (EIO);
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
10230Sstevel@tonic-gate 	usbprnp->usbprn_flags |= USBPRN_OPEN;
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	/* set last status to online */
10260Sstevel@tonic-gate 	usbprnp->usbprn_last_status &= ~USB_PRINTER_PORT_NO_SELECT;
10270Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
10320Sstevel@tonic-gate 	    "usbprn_open: End");
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	return (rval);
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate /*
10390Sstevel@tonic-gate  * usbprn_close:
10400Sstevel@tonic-gate  *	Close the pipes
10410Sstevel@tonic-gate  */
10420Sstevel@tonic-gate /*ARGSUSED*/
10430Sstevel@tonic-gate static int
usbprn_close(dev_t dev,int flag,int otyp,cred_t * credp)10440Sstevel@tonic-gate usbprn_close(dev_t dev, int flag, int otyp, cred_t *credp)
10450Sstevel@tonic-gate {
10460Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep,
10476898Sfb209375 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
10480Sstevel@tonic-gate 	int		rval = 0;
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	if (usbprnp == NULL) {
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 		return (ENXIO);
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbprnp->usbprn_log_handle,
10560Sstevel@tonic-gate 	    "usbprn_close:");
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
10590Sstevel@tonic-gate 		rval = usb_ugen_close(usbprnp->usbprn_ugen_hdl,
10606898Sfb209375 		    dev, flag, otyp, credp);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 		return (rval);
10630Sstevel@tonic-gate 	}
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	/* avoid races with connect/disconnect */
10660Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
10670Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_dev_acc, USB_WAIT, 0);
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	/* Close all usb pipes */
10700Sstevel@tonic-gate 	usbprn_close_usb_pipes(usbprnp);
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	/* prevent any accesses by setting flags to closed */
10730Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
10740Sstevel@tonic-gate 	usbprnp->usbprn_flags &= ~USBPRN_OPEN;
10750Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_dev_acc);
10780Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	usbprn_pm_idle_component(usbprnp);
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbprnp->usbprn_log_handle,
10830Sstevel@tonic-gate 	    "usbprn_close: End");
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	return (rval);
10860Sstevel@tonic-gate }
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate /*
10900Sstevel@tonic-gate  * usbprn_read:
10910Sstevel@tonic-gate  *	Read entry point (TBD)
10920Sstevel@tonic-gate  */
10930Sstevel@tonic-gate /* ARGSUSED */
10940Sstevel@tonic-gate static int
usbprn_read(dev_t dev,struct uio * uiop,cred_t * credp)10950Sstevel@tonic-gate usbprn_read(dev_t dev, struct uio *uiop, cred_t *credp)
10960Sstevel@tonic-gate {
10970Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
10986898Sfb209375 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	if (usbprnp == NULL) {
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 		return (ENXIO);
11030Sstevel@tonic-gate 	}
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
11060Sstevel@tonic-gate 		int rval;
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		/* raise power */
11090Sstevel@tonic-gate 		usbprn_pm_busy_component(usbprnp);
11100Sstevel@tonic-gate 		(void) pm_raise_power(usbprnp->usbprn_dip,
11116898Sfb209375 		    0, USB_DEV_OS_FULL_PWR);
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 		if (usb_serialize_access(usbprnp->usbprn_write_acc,
11140Sstevel@tonic-gate 		    USB_WAIT_SIG, 0) == 0) {
11150Sstevel@tonic-gate 			usbprn_pm_idle_component(usbprnp);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 			return (EINTR);
11180Sstevel@tonic-gate 		}
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 		rval = usb_ugen_read(usbprnp->usbprn_ugen_hdl, dev,
11216898Sfb209375 		    uiop, credp);
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_write_acc);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		usbprn_pm_idle_component(usbprnp);
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 		return (rval);
11280Sstevel@tonic-gate 	}
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	/* Do a bulk-in from the printer */
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	return (EIO);
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate /*
11370Sstevel@tonic-gate  * usbprn_write:
11380Sstevel@tonic-gate  *	Write to the printer
11390Sstevel@tonic-gate  */
11400Sstevel@tonic-gate /* ARGSUSED2 */
11410Sstevel@tonic-gate static int
usbprn_write(dev_t dev,struct uio * uiop,cred_t * credp)11420Sstevel@tonic-gate usbprn_write(dev_t dev, struct uio *uiop, cred_t *credp)
11430Sstevel@tonic-gate {
11440Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
11456898Sfb209375 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
11460Sstevel@tonic-gate 	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
11470Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
11480Sstevel@tonic-gate 	int		rval;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	if (usbprnp == NULL) {
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 		return (ENXIO);
11530Sstevel@tonic-gate 	}
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
11566898Sfb209375 	    "usbprn_write: Begin usbprnp=0x%p ", (void *)usbprnp);
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
11590Sstevel@tonic-gate 		/* raise power */
11600Sstevel@tonic-gate 		usbprn_pm_busy_component(usbprnp);
11610Sstevel@tonic-gate 		(void) pm_raise_power(usbprnp->usbprn_dip,
11626898Sfb209375 		    0, USB_DEV_OS_FULL_PWR);
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 		if (usb_serialize_access(usbprnp->usbprn_write_acc,
11650Sstevel@tonic-gate 		    USB_WAIT_SIG, 0) == 0) {
11660Sstevel@tonic-gate 			usbprn_pm_idle_component(usbprnp);
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 			return (EINTR);
11690Sstevel@tonic-gate 		}
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 		rval = usb_ugen_write(usbprnp->usbprn_ugen_hdl, dev,
11726898Sfb209375 		    uiop, credp);
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_write_acc);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 		usbprn_pm_idle_component(usbprnp);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 		return (rval);
11790Sstevel@tonic-gate 	}
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	/*
11820Sstevel@tonic-gate 	 * serialize writes
11830Sstevel@tonic-gate 	 * we cannot use usbprn_ser_acc sync object at this point because
11840Sstevel@tonic-gate 	 * that would block out the ioctls for the full duration of the write.
11850Sstevel@tonic-gate 	 */
11860Sstevel@tonic-gate 	if (usb_serialize_access(usbprnp->usbprn_write_acc,
11870Sstevel@tonic-gate 	    USB_WAIT_SIG, 0) == 0) {
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 		return (EINTR);
11900Sstevel@tonic-gate 	}
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	/*
11930Sstevel@tonic-gate 	 * Check the status of the pipe.  If it's not idle,
11940Sstevel@tonic-gate 	 * then wait.
11950Sstevel@tonic-gate 	 */
11960Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	/* if device is disconnected or pipes closed, fail immediately */
11990Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
12000Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
12030Sstevel@tonic-gate 		    "usbprn_write: device can't be accessed");
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_write_acc);
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 		return (EIO);
12080Sstevel@tonic-gate 	}
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	/* all pipes must be idle */
12110Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
12120Sstevel@tonic-gate 	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	/*
12170Sstevel@tonic-gate 	 * Call physio to do the transfer.  physio will
12180Sstevel@tonic-gate 	 * call the strategy routine, and then call
12190Sstevel@tonic-gate 	 * biowait() to block until the transfer completes.
12200Sstevel@tonic-gate 	 */
12210Sstevel@tonic-gate 	rval = physio(usbprn_strategy, (struct buf *)0, dev,
12220Sstevel@tonic-gate 	    B_WRITE, usbprn_minphys, uiop);
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_write_acc);
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
12270Sstevel@tonic-gate 	    "usbprn_write: End");
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	return (rval);
12300Sstevel@tonic-gate }
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate /*
12340Sstevel@tonic-gate  * usbprn_poll
12350Sstevel@tonic-gate  */
12360Sstevel@tonic-gate static int
usbprn_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)12370Sstevel@tonic-gate usbprn_poll(dev_t dev, short events,
12380Sstevel@tonic-gate     int anyyet,  short *reventsp, struct pollhead **phpp)
12390Sstevel@tonic-gate {
12400Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
12416898Sfb209375 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	if (usbprnp == NULL) {
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 		return (ENXIO);
12460Sstevel@tonic-gate 	}
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
12490Sstevel@tonic-gate 		return (usb_ugen_poll(usbprnp->usbprn_ugen_hdl, dev, events,
12506898Sfb209375 		    anyyet, reventsp, phpp));
12510Sstevel@tonic-gate 	}
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	return (ENXIO);
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate /*
12580Sstevel@tonic-gate  * usbprn_strategy:
12590Sstevel@tonic-gate  *	service a request to the device.
12600Sstevel@tonic-gate  */
12610Sstevel@tonic-gate static int
usbprn_strategy(struct buf * bp)12620Sstevel@tonic-gate usbprn_strategy(struct buf *bp)
12630Sstevel@tonic-gate {
12640Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
12656898Sfb209375 	    USBPRN_MINOR_TO_INSTANCE(getminor(bp->b_edev)));
12660Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	bp_mapin(bp);
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	/*
12710Sstevel@tonic-gate 	 * serialize to avoid races
12720Sstevel@tonic-gate 	 * access is released in usbprn_biodone()
12730Sstevel@tonic-gate 	 */
12740Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_dev_acc, USB_WAIT, 0);
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
12770Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
12780Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
12790Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
12820Sstevel@tonic-gate 		    "usbprn_strategy: device can't be accessed");
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 		return (0);
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	bulk_out->ps_flags = USBPRN_PS_NEED_TO_XFER;
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	ASSERT(usbprnp->usbprn_bp == NULL);
12900Sstevel@tonic-gate 	usbprnp->usbprn_bp = bp;
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
12930Sstevel@tonic-gate 	    "usbprn_strategy: usbprnp=0x%p bp=0x%p count=%lu",
12946898Sfb209375 	    (void *)usbprnp, (void *)bp, bp->b_bcount);
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	ASSERT(usbprnp->usbprn_bulk_mp == NULL);
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	usbprnp->usbprn_bulk_mp = allocb(bp->b_bcount, BPRI_HI);
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	if (usbprnp->usbprn_bulk_mp == NULL) {
13010Sstevel@tonic-gate 		bulk_out->ps_flags = USBPRN_PS_IDLE;
13020Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
13030Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
13060Sstevel@tonic-gate 		    "usbprn_strategy: allocb failed");
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 		return (0);
13090Sstevel@tonic-gate 	}
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	bcopy((caddr_t)bp->b_un.b_addr,
13126898Sfb209375 	    usbprnp->usbprn_bulk_mp->b_datap->db_base, bp->b_bcount);
13130Sstevel@tonic-gate 	usbprnp->usbprn_bulk_mp->b_wptr += bp->b_bcount;
13140Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	usbprn_send_async_bulk_data(usbprnp);
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	return (0);
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate /*
13230Sstevel@tonic-gate  * usbprn_ioctl:
13240Sstevel@tonic-gate  *	handle the ioctl
13250Sstevel@tonic-gate  */
13260Sstevel@tonic-gate /*ARGSUSED4*/
13270Sstevel@tonic-gate static int
usbprn_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * credp,int * rvalp)13280Sstevel@tonic-gate usbprn_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
13290Sstevel@tonic-gate 		cred_t *credp, int *rvalp)
13300Sstevel@tonic-gate {
13310Sstevel@tonic-gate 	int		err = 0;
13320Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep,
13336898Sfb209375 	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
13340Sstevel@tonic-gate 	struct ecpp_device_id	usbprn_devid;
13350Sstevel@tonic-gate 	int		len;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
13380Sstevel@tonic-gate 	    "usbprn_ioctl: Begin ");
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
13410Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	/*
13440Sstevel@tonic-gate 	 * only for PRNIOC_GET_STATUS cmd:
13450Sstevel@tonic-gate 	 * if device is disconnected or pipes closed, fail immediately
13460Sstevel@tonic-gate 	 */
13470Sstevel@tonic-gate 	if ((cmd == PRNIOC_GET_STATUS) &&
13480Sstevel@tonic-gate 	    !(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
13490Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
13520Sstevel@tonic-gate 		    "usbprn_write: device can't be accessed");
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 		usb_release_access(usbprnp->usbprn_ser_acc);
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 		return (EIO);
13570Sstevel@tonic-gate 	}
13580Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	switch (cmd) {
13610Sstevel@tonic-gate 	case ECPPIOC_GETDEVID:
13620Sstevel@tonic-gate 		/*
13630Sstevel@tonic-gate 		 * With genericized ioctls this interface should change.
13640Sstevel@tonic-gate 		 * We ignore the mode in USB printer driver because
13650Sstevel@tonic-gate 		 * it need not be in nibble mode in usb driver unlike
13660Sstevel@tonic-gate 		 * ecpp to retrieve the device id string. Also we do
13670Sstevel@tonic-gate 		 * not expect the application to call this twice since
13680Sstevel@tonic-gate 		 * it doesn't change since attach time and we take care
13690Sstevel@tonic-gate 		 * of calling it twice: once for getting the length and
13700Sstevel@tonic-gate 		 * once for getting the actual device id string. So we
13710Sstevel@tonic-gate 		 * set both the lengths to actual device id string length.
13720Sstevel@tonic-gate 		 * Ref: PSARC/2000/018
13730Sstevel@tonic-gate 		 */
13740Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
13750Sstevel@tonic-gate 		    "usbprn_ioctl: ECPPIOC_GETDEVID(0x%x)", cmd);
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 		bzero(&usbprn_devid, sizeof (usbprn_devid));
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 		ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
13800Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
13810Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
13820Sstevel@tonic-gate 		case DDI_MODEL_ILP32: {
13830Sstevel@tonic-gate 			struct ecpp_device_id32	usbprn_devid32;
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 			if (ddi_copyin((caddr_t)arg, &usbprn_devid32,
13860Sstevel@tonic-gate 			    sizeof (struct ecpp_device_id32), flag)) {
13870Sstevel@tonic-gate 				err = EFAULT;
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 				break;
13900Sstevel@tonic-gate 			}
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 			if (usbprnp->usbprn_device_id == NULL) {
13930Sstevel@tonic-gate 				err = EIO;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 				break;
13960Sstevel@tonic-gate 			}
13970Sstevel@tonic-gate 			ASSERT(usbprnp->usbprn_device_id_len > 2);
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 			usbprn_devid32.rlen = usbprnp->usbprn_device_id_len - 2;
14000Sstevel@tonic-gate 			len = min(usbprn_devid32.len, usbprn_devid32.rlen);
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 			if (ddi_copyout(usbprnp->usbprn_device_id + 2,
14030Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)usbprn_devid32.addr,
14040Sstevel@tonic-gate 			    len, flag)) {
14050Sstevel@tonic-gate 				err = EFAULT;
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 				break;
14080Sstevel@tonic-gate 			}
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 			if (ddi_copyout(&usbprn_devid32, (caddr_t)arg,
14110Sstevel@tonic-gate 			    sizeof (struct ecpp_device_id32), flag)) {
14120Sstevel@tonic-gate 				err = EFAULT;
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 				break;
14150Sstevel@tonic-gate 			}
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 			break;
14180Sstevel@tonic-gate 		}
14190Sstevel@tonic-gate 		case DDI_MODEL_NONE:
14200Sstevel@tonic-gate 			if (ddi_copyin((caddr_t)arg, &usbprn_devid,
14210Sstevel@tonic-gate 			    sizeof (struct ecpp_device_id), flag)) {
14220Sstevel@tonic-gate 				err = EFAULT;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 				break;
14250Sstevel@tonic-gate 			}
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 			if (usbprnp->usbprn_device_id == NULL) {
14280Sstevel@tonic-gate 				err = EIO;
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 				break;
14310Sstevel@tonic-gate 			}
14320Sstevel@tonic-gate 			ASSERT(usbprnp->usbprn_device_id_len > 2);
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 			usbprn_devid.rlen = usbprnp->usbprn_device_id_len - 2;
14350Sstevel@tonic-gate 			len = min(usbprn_devid.len, usbprn_devid.rlen);
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 			if (ddi_copyout(usbprnp->usbprn_device_id + 2,
14380Sstevel@tonic-gate 			    usbprn_devid.addr, len, flag)) {
14390Sstevel@tonic-gate 				err = EFAULT;
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 				break;
14420Sstevel@tonic-gate 			}
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 			if (ddi_copyout(&usbprn_devid, (caddr_t)arg,
14450Sstevel@tonic-gate 			    sizeof (struct ecpp_device_id), flag)) {
14460Sstevel@tonic-gate 				err = EFAULT;
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 				break;
14490Sstevel@tonic-gate 			}
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 			break;
14520Sstevel@tonic-gate 		}
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 		break;
14550Sstevel@tonic-gate #else
14560Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &usbprn_devid,
14570Sstevel@tonic-gate 		    sizeof (struct ecpp_device_id), flag)) {
14580Sstevel@tonic-gate 			err = EFAULT;
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 			break;
14610Sstevel@tonic-gate 		}
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 		if (usbprnp->usbprn_device_id == NULL) {
14650Sstevel@tonic-gate 			err = EIO;
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 			break;
14680Sstevel@tonic-gate 		}
14690Sstevel@tonic-gate 		ASSERT(usbprnp->usbprn_device_id_len > 2);
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate 		usbprn_devid.rlen = usbprnp->usbprn_device_id_len - 2;
14720Sstevel@tonic-gate 		len = min(usbprn_devid.len, usbprn_devid.rlen);
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
14750Sstevel@tonic-gate 		    usbprn_devid.addr, len, flag)) {
14760Sstevel@tonic-gate 			err = EFAULT;
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 			break;
14790Sstevel@tonic-gate 		}
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 		if (ddi_copyout(&usbprn_devid, (caddr_t)arg,
14820Sstevel@tonic-gate 		    sizeof (struct ecpp_device_id), flag)) {
14830Sstevel@tonic-gate 			err = EFAULT;
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 			break;
14860Sstevel@tonic-gate 		}
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 		break;
14890Sstevel@tonic-gate #endif
14900Sstevel@tonic-gate 	case ECPPIOC_SETPARMS:
14910Sstevel@tonic-gate 		err = usbprn_setparms(usbprnp, arg, flag);
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 		break;
14940Sstevel@tonic-gate 	case ECPPIOC_GETPARMS:
14950Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
14960Sstevel@tonic-gate 		    "usbprn_ioctl: ECPPIOC_GETPARMS(0x%x)", cmd);
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 		/* Get the parameters */
14990Sstevel@tonic-gate 		err = usbprn_getparms(usbprnp, arg, flag);
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 		break;
15020Sstevel@tonic-gate 	case BPPIOC_GETERR:
15030Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15040Sstevel@tonic-gate 		    "usbprn_ioctl: ECPPIOC_GETERR(0x%x)", cmd);
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 		/* Get the error state */
15070Sstevel@tonic-gate 		usbprn_geterr(usbprnp, arg, flag);
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 		break;
15100Sstevel@tonic-gate 	case BPPIOC_TESTIO:
15110Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15120Sstevel@tonic-gate 		    "usbprn_ioctl: BPPIOC_TESTIO(0x%x)",  cmd);
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 		/* Get the port status */
15150Sstevel@tonic-gate 		err = usbprn_testio(usbprnp, flag);
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 		break;
15180Sstevel@tonic-gate 	case PRNIOC_GET_IFCAP:
15190Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15200Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_IFCAP(0x%x)",  cmd);
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 		/* get interface capabilities */
15230Sstevel@tonic-gate 		err = usbprn_prnio_get_ifcap(usbprnp, arg, flag);
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 		break;
15260Sstevel@tonic-gate 	case PRNIOC_SET_IFCAP:
15270Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15280Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_SET_IFCAP(0x%x)",  cmd);
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 		/* get interface capabilities */
15310Sstevel@tonic-gate 		err = usbprn_prnio_set_ifcap(usbprnp, arg, flag);
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 		break;
15340Sstevel@tonic-gate 	case PRNIOC_GET_IFINFO:
15350Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15360Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_IFINFO(0x%x)",  cmd);
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 		/* get interface information */
15390Sstevel@tonic-gate 		err = usbprn_prnio_get_ifinfo(usbprnp, arg, flag);
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 		break;
15420Sstevel@tonic-gate 	case PRNIOC_GET_STATUS:
15430Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15440Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_STATUS(0x%x)",  cmd);
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate 		/* get prnio status */
15470Sstevel@tonic-gate 		err = usbprn_prnio_get_status(usbprnp, arg, flag);
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 		break;
15500Sstevel@tonic-gate 	case PRNIOC_GET_1284_DEVID:
15510Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15520Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_1284_DEVID(0x%x)",  cmd);
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 		/* get device ID */
15550Sstevel@tonic-gate 		err = usbprn_prnio_get_1284_devid(usbprnp, arg, flag);
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 		break;
15580Sstevel@tonic-gate 	case PRNIOC_GET_1284_STATUS:
15590Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15600Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_1284_STATUS(0x%x)",  cmd);
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 		/* get prnio status */
15630Sstevel@tonic-gate 		err = usbprn_prnio_get_1284_status(usbprnp, arg, flag);
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 		break;
15660Sstevel@tonic-gate 	case PRNIOC_GET_TIMEOUTS:
15670Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15680Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_GET_TIMEOUTS(0x%x)", cmd);
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 		/* Get the parameters */
15710Sstevel@tonic-gate 		err = usbprn_prnio_get_timeouts(usbprnp, arg, flag);
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 		break;
15740Sstevel@tonic-gate 	case PRNIOC_SET_TIMEOUTS:
15750Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15760Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_SET_TIMEOUTS(0x%x)", cmd);
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 		/* Get the parameters */
15790Sstevel@tonic-gate 		err = usbprn_prnio_set_timeouts(usbprnp, arg, flag);
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 		break;
15820Sstevel@tonic-gate 	case PRNIOC_RESET:
15830Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15840Sstevel@tonic-gate 		    "usbprn_ioctl : PRNIOC_RESET(0x%x)",  cmd);
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate 		/* nothing */
15870Sstevel@tonic-gate 		err = 0;
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 		break;
15900Sstevel@tonic-gate 	default:
15910Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15920Sstevel@tonic-gate 		    "usbprn_ioctl: unknown(0x%x)", cmd);
15930Sstevel@tonic-gate 		err = EINVAL;
15940Sstevel@tonic-gate 	}
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
15990Sstevel@tonic-gate 	    "usbprn_ioctl: End ");
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	return (err);
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate /*
16060Sstevel@tonic-gate  * breakup by physio
16070Sstevel@tonic-gate  */
16080Sstevel@tonic-gate static void
usbprn_minphys(struct buf * bp)16090Sstevel@tonic-gate usbprn_minphys(struct buf *bp)
16100Sstevel@tonic-gate {
16110Sstevel@tonic-gate 	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
16126898Sfb209375 	    USBPRN_MINOR_TO_INSTANCE(getminor(bp->b_edev)));
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
16150Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
16160Sstevel@tonic-gate 	    "usbprn_minphys: bcount=%lu", bp->b_bcount);
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 	if (bp->b_bcount > usbprnp->usbprn_max_bulk_xfer_size) {
16190Sstevel@tonic-gate 		bp->b_bcount = min(usbprn_max_xfer_size,
16200Sstevel@tonic-gate 		    usbprnp->usbprn_max_bulk_xfer_size);
16210Sstevel@tonic-gate 	} else {
16220Sstevel@tonic-gate 		bp->b_bcount = min(usbprn_max_xfer_size, bp->b_bcount);
16230Sstevel@tonic-gate 	}
16240Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
16250Sstevel@tonic-gate }
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate /*
16290Sstevel@tonic-gate  * usbprn_open_usb_pipes:
16300Sstevel@tonic-gate  *	Open all pipes on the device
16310Sstevel@tonic-gate  */
16320Sstevel@tonic-gate static int
usbprn_open_usb_pipes(usbprn_state_t * usbprnp)16330Sstevel@tonic-gate usbprn_open_usb_pipes(usbprn_state_t *usbprnp)
16340Sstevel@tonic-gate {
16350Sstevel@tonic-gate 	usb_pipe_policy_t *policy;
16360Sstevel@tonic-gate 	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
16370Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
16400Sstevel@tonic-gate 	    "usbprn_open_usb_pipes:");
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 	/*
16430Sstevel@tonic-gate 	 * Intitialize the pipe policy for the bulk out pipe
16440Sstevel@tonic-gate 	 */
16450Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
16460Sstevel@tonic-gate 	policy = &(bulk_out->ps_policy);
16470Sstevel@tonic-gate 	policy->pp_max_async_reqs = 1;
16480Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 	/* Open bulk_out pipe */
16510Sstevel@tonic-gate 	if (usb_pipe_open(usbprnp->usbprn_dip, &bulk_out->ps_ept_descr,
16520Sstevel@tonic-gate 	    policy, USB_FLAGS_SLEEP, &bulk_out->ps_handle) != USB_SUCCESS) {
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 		return (USB_FAILURE);
16550Sstevel@tonic-gate 	}
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate #ifdef LATER
16580Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
16590Sstevel@tonic-gate 	/* Open the bulk in pipe if one exists */
16600Sstevel@tonic-gate 	if (bulk_in->ps_ept_descr->bLength) {
16610Sstevel@tonic-gate 		/*
16620Sstevel@tonic-gate 		 * Initialize the pipe policy for the Bulk In pipe
16630Sstevel@tonic-gate 		 */
16640Sstevel@tonic-gate 		policy = &bulk_in->ps_policy;
16650Sstevel@tonic-gate 		bulk_in->ps_flags = USBPRN_PS_IDLE;
16660Sstevel@tonic-gate 		policy->pp_max_async_reqs = 1;
16670Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 		/* Open bulk_in pipe */
16700Sstevel@tonic-gate 		if (usb_pipe_open(usbprnp->usbprn_dip, bulk_in->ps_ept_descr,
16710Sstevel@tonic-gate 		    policy, USB_FLAGS_SLEEP, &bulk_in->ps_handle) !=
16720Sstevel@tonic-gate 		    USB_SUCCESS) {
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 			return (USB_FAILURE);
16750Sstevel@tonic-gate 		}
16760Sstevel@tonic-gate 	} else {
16770Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
16780Sstevel@tonic-gate 	}
16790Sstevel@tonic-gate #else
16800Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
16810Sstevel@tonic-gate 	bulk_in->ps_flags = USBPRN_PS_IDLE;
16820Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
16830Sstevel@tonic-gate #endif
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
16860Sstevel@tonic-gate 	    "usbprn_open_usb_pipes: success");
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 	return (USB_SUCCESS);
16890Sstevel@tonic-gate }
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate /*
16930Sstevel@tonic-gate  * usbprn_close_usb_pipes:
16940Sstevel@tonic-gate  *	Close the default/bulk in/out pipes synchronously
16950Sstevel@tonic-gate  */
16960Sstevel@tonic-gate static void
usbprn_close_usb_pipes(usbprn_state_t * usbprnp)16970Sstevel@tonic-gate usbprn_close_usb_pipes(usbprn_state_t *usbprnp)
16980Sstevel@tonic-gate {
16990Sstevel@tonic-gate 	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
17000Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
17030Sstevel@tonic-gate 	    "usbprn_close_usb_pipes:");
17040Sstevel@tonic-gate #ifdef DEBUG
17050Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
17060Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
17070Sstevel@tonic-gate 	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
17080Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
17090Sstevel@tonic-gate #endif
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 	/*
17120Sstevel@tonic-gate 	 * close the pipe, if another thread is already closing the
17130Sstevel@tonic-gate 	 * pipe, we get USB_INVALID_PIPE
17140Sstevel@tonic-gate 	 */
17150Sstevel@tonic-gate 	if (bulk_out->ps_handle) {
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
17180Sstevel@tonic-gate 		    "usbprn_close_usb_pipes: Closing bulk out pipe");
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 		usb_pipe_close(usbprnp->usbprn_dip, bulk_out->ps_handle,
17216898Sfb209375 		    USB_FLAGS_SLEEP, NULL, NULL);
17220Sstevel@tonic-gate 		bulk_out->ps_handle = NULL;
17230Sstevel@tonic-gate 	}
17240Sstevel@tonic-gate 	if (bulk_in->ps_handle) {
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
17270Sstevel@tonic-gate 		    "usbprn_close_usb_pipes: Closing bulk in pipe");
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 		usb_pipe_close(usbprnp->usbprn_dip, bulk_in->ps_handle,
17306898Sfb209375 		    USB_FLAGS_SLEEP, NULL, NULL);
17310Sstevel@tonic-gate 		bulk_in->ps_handle = NULL;
17320Sstevel@tonic-gate 	}
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate /*
17370Sstevel@tonic-gate  * usbprn_getparms:
17380Sstevel@tonic-gate  *	Get the parameters for the device
17390Sstevel@tonic-gate  */
17400Sstevel@tonic-gate static int
usbprn_getparms(usbprn_state_t * usbprnp,intptr_t arg,int flag)17410Sstevel@tonic-gate usbprn_getparms(usbprn_state_t *usbprnp, intptr_t arg, int flag)
17420Sstevel@tonic-gate {
17430Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	if (ddi_copyout(&usbprnp->usbprn_setparms,
17460Sstevel@tonic-gate 	    (caddr_t)arg, sizeof (struct ecpp_transfer_parms), flag)) {
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 		return (EFAULT);
17490Sstevel@tonic-gate 	}
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 	return (0);
17520Sstevel@tonic-gate }
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate /*
17560Sstevel@tonic-gate  * usbprn_setparms:
17570Sstevel@tonic-gate  *	Set the parameters for the device
17580Sstevel@tonic-gate  */
17590Sstevel@tonic-gate static int
usbprn_setparms(usbprn_state_t * usbprnp,intptr_t arg,int flag)17600Sstevel@tonic-gate usbprn_setparms(usbprn_state_t *usbprnp, intptr_t arg, int flag)
17610Sstevel@tonic-gate {
17620Sstevel@tonic-gate 	struct ecpp_transfer_parms xfer;
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)arg, &xfer,
17670Sstevel@tonic-gate 	    sizeof (struct ecpp_transfer_parms), flag)) {
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 		return (EFAULT);
17700Sstevel@tonic-gate 	}
17710Sstevel@tonic-gate 	if ((xfer.write_timeout < USBPRN_XFER_TIMEOUT_MIN) ||
17720Sstevel@tonic-gate 	    (xfer.write_timeout > USBPRN_XFER_TIMEOUT_MAX)) {
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 		return (EINVAL);
17750Sstevel@tonic-gate 	}
17760Sstevel@tonic-gate 	if (!((xfer.mode == ECPP_CENTRONICS) ||
17770Sstevel@tonic-gate 	    (xfer.mode == ECPP_COMPAT_MODE) ||
17780Sstevel@tonic-gate 	    (xfer.mode == ECPP_NIBBLE_MODE) ||
17790Sstevel@tonic-gate 	    (xfer.mode == ECPP_ECP_MODE) ||
17800Sstevel@tonic-gate 	    (xfer.mode == ECPP_DIAG_MODE))) {
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 		return (EINVAL);
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 	}
17850Sstevel@tonic-gate 	if (xfer.mode != ECPP_CENTRONICS) {
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 		return (EPROTONOSUPPORT);
17880Sstevel@tonic-gate 	}
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
17910Sstevel@tonic-gate 	usbprnp->usbprn_setparms = xfer;
17920Sstevel@tonic-gate 	usbprnp->usbprn_prn_timeouts.tmo_forward = xfer.write_timeout;
17930Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	return (0);
17960Sstevel@tonic-gate }
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate /*
18000Sstevel@tonic-gate  * usbprn_geterr:
18010Sstevel@tonic-gate  *	Return the any device error state
18020Sstevel@tonic-gate  */
18030Sstevel@tonic-gate static void
usbprn_geterr(usbprn_state_t * usbprnp,intptr_t arg,int flag)18040Sstevel@tonic-gate usbprn_geterr(usbprn_state_t *usbprnp, intptr_t arg, int flag)
18050Sstevel@tonic-gate {
18060Sstevel@tonic-gate 	struct bpp_error_status bpp_status;
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	bzero(&bpp_status, sizeof (bpp_status));
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
18110Sstevel@tonic-gate 	bpp_status.bus_error = 0;
18120Sstevel@tonic-gate 	bpp_status.timeout_occurred = 0;
18130Sstevel@tonic-gate 	bpp_status.pin_status = usbprn_error_state(usbprnp->usbprn_last_status);
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
18160Sstevel@tonic-gate 	    "usbprn_geterr: status=0x%x", usbprnp->usbprn_last_status);
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 	(void) ddi_copyout(&bpp_status,
18210Sstevel@tonic-gate 	    (caddr_t)arg, sizeof (struct bpp_error_status), flag);
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate /*
18260Sstevel@tonic-gate  * usbprn_error_state:
18270Sstevel@tonic-gate  *	Map the driver error state to that of the application
18280Sstevel@tonic-gate  */
18290Sstevel@tonic-gate static char
usbprn_error_state(uchar_t status)18300Sstevel@tonic-gate usbprn_error_state(uchar_t status)
18310Sstevel@tonic-gate {
18320Sstevel@tonic-gate 	uchar_t app_err_status = 0;
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 	if (!(status & USB_PRINTER_PORT_NO_ERROR)) {
18350Sstevel@tonic-gate 		app_err_status |= USB_PRINTER_ERR_ERR;
18360Sstevel@tonic-gate 	}
18370Sstevel@tonic-gate 	if (status & USB_PRINTER_PORT_EMPTY) {
18380Sstevel@tonic-gate 		app_err_status |= USB_PRINTER_PE_ERR;
18390Sstevel@tonic-gate 	}
18400Sstevel@tonic-gate 	if (!(status & USB_PRINTER_PORT_NO_SELECT)) {
18410Sstevel@tonic-gate 		app_err_status |= USB_PRINTER_SLCT_ERR;
18420Sstevel@tonic-gate 	}
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 	return (app_err_status);
18450Sstevel@tonic-gate }
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate static int
usbprn_ioctl_get_status(usbprn_state_t * usbprnp)18490Sstevel@tonic-gate usbprn_ioctl_get_status(usbprn_state_t *usbprnp)
18500Sstevel@tonic-gate {
18510Sstevel@tonic-gate 	/* Check the transfer mode */
18520Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 	/* if device is disconnected or pipes closed, fail immediately */
18550Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
18560Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
18590Sstevel@tonic-gate 		    "usbprn_ioctl_get_status: device can't be accessed");
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 		return (EIO);
18620Sstevel@tonic-gate 	}
18630Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate 		return (EIO);
18680Sstevel@tonic-gate 	}
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 	return (0);
18710Sstevel@tonic-gate }
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate /*
18750Sstevel@tonic-gate  * usbprn_testio:
18760Sstevel@tonic-gate  *	Execute the ECPP_TESTIO ioctl
18770Sstevel@tonic-gate  */
18780Sstevel@tonic-gate /* ARGSUSED1 */
18790Sstevel@tonic-gate static int
usbprn_testio(usbprn_state_t * usbprnp,int flag)18800Sstevel@tonic-gate usbprn_testio(usbprn_state_t *usbprnp, int flag)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate 	int	err;
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
18850Sstevel@tonic-gate 	    "usbprn_testio: begin");
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	if ((err = usbprn_ioctl_get_status(usbprnp)) != 0) {
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 		return (err);
18900Sstevel@tonic-gate 	}
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	/* There is an error.  Return it to the user */
18930Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	if (usbprn_error_state(usbprnp->usbprn_last_status) != 0) {
18960Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 		return (EIO);
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 	} else {
19010Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 		return (0);
19040Sstevel@tonic-gate 	}
19050Sstevel@tonic-gate }
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate /*
19090Sstevel@tonic-gate  * usbprn_prnio_get_status:
19100Sstevel@tonic-gate  *	Execute the PRNIOC_GET_STATUS ioctl
19110Sstevel@tonic-gate  */
19120Sstevel@tonic-gate static int
usbprn_prnio_get_status(usbprn_state_t * usbprnp,intptr_t arg,int flag)19130Sstevel@tonic-gate usbprn_prnio_get_status(usbprn_state_t *usbprnp, intptr_t arg, int flag)
19140Sstevel@tonic-gate {
19150Sstevel@tonic-gate 	uint_t	prnio_status = 0;
19160Sstevel@tonic-gate 	int	err;
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
19190Sstevel@tonic-gate 	    "usbprn_prnio_get_status: begin");
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 	/* capture printer status */
19220Sstevel@tonic-gate 	err = usbprn_ioctl_get_status(usbprnp);
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 	if (usbprnp->usbprn_dev_state == USB_DEV_ONLINE) {
19270Sstevel@tonic-gate 		prnio_status |= PRN_ONLINE;
19280Sstevel@tonic-gate 	}
19290Sstevel@tonic-gate 	if ((err == 0) &&
19300Sstevel@tonic-gate 	    (usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR)) {
19310Sstevel@tonic-gate 		prnio_status |= PRN_READY;
19320Sstevel@tonic-gate 	}
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	if (ddi_copyout(&prnio_status,
19370Sstevel@tonic-gate 	    (caddr_t)arg, sizeof (prnio_status), flag)) {
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 		return (EFAULT);
19400Sstevel@tonic-gate 	}
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	return (0);
19430Sstevel@tonic-gate }
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate /*
19470Sstevel@tonic-gate  * usbprn_prnio_get_1284_status:
19480Sstevel@tonic-gate  *	Execute the PRNIOC_GET_1284_STATUS ioctl
19490Sstevel@tonic-gate  */
19500Sstevel@tonic-gate static int
usbprn_prnio_get_1284_status(usbprn_state_t * usbprnp,intptr_t arg,int flag)19510Sstevel@tonic-gate usbprn_prnio_get_1284_status(usbprn_state_t *usbprnp, intptr_t arg, int flag)
19520Sstevel@tonic-gate {
19530Sstevel@tonic-gate 	uchar_t		status;
19540Sstevel@tonic-gate 	int		err;
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
19570Sstevel@tonic-gate 	    "usbprn_prnio_get_1284_status: begin");
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	if ((err = usbprn_ioctl_get_status(usbprnp)) != 0) {
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 		return (err);
19620Sstevel@tonic-gate 	}
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate 	/* status was captured successfully */
19650Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	status = usbprnp->usbprn_last_status & (USB_PRINTER_PORT_NO_ERROR |
19686898Sfb209375 	    USB_PRINTER_PORT_NO_SELECT | USB_PRINTER_PORT_EMPTY);
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 	if (ddi_copyout(&status, (caddr_t)arg, sizeof (status), flag)) {
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 		return (EFAULT);
19750Sstevel@tonic-gate 	}
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	return (0);
19780Sstevel@tonic-gate }
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate /*
19820Sstevel@tonic-gate  * usbprn_prnio_get_ifcap:
19830Sstevel@tonic-gate  *	Execute the PRNIOC_GET_IFCAP ioctl
19840Sstevel@tonic-gate  */
19850Sstevel@tonic-gate /* ARGSUSED */
19860Sstevel@tonic-gate static int
usbprn_prnio_get_ifcap(usbprn_state_t * usbprnp,intptr_t arg,int flag)19870Sstevel@tonic-gate usbprn_prnio_get_ifcap(usbprn_state_t *usbprnp, intptr_t arg, int flag)
19880Sstevel@tonic-gate {
19890Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate 	if (ddi_copyout(&usbprn_ifcap, (caddr_t)arg, sizeof (usbprn_ifcap),
19920Sstevel@tonic-gate 	    flag)) {
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate 		return (EFAULT);
19950Sstevel@tonic-gate 	}
19960Sstevel@tonic-gate 
19970Sstevel@tonic-gate 	return (0);
19980Sstevel@tonic-gate }
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 
20010Sstevel@tonic-gate /*
20020Sstevel@tonic-gate  * usbprn_prnio_get_ifcap:
20030Sstevel@tonic-gate  *	Execute the PRNIOC_SET_IFCAP ioctl
20040Sstevel@tonic-gate  */
20050Sstevel@tonic-gate /* ARGSUSED */
20060Sstevel@tonic-gate static int
usbprn_prnio_set_ifcap(usbprn_state_t * usbprnp,intptr_t arg,int flag)20070Sstevel@tonic-gate usbprn_prnio_set_ifcap(usbprn_state_t *usbprnp, intptr_t arg, int flag)
20080Sstevel@tonic-gate {
20090Sstevel@tonic-gate 	uint_t	new_ifcap;
20100Sstevel@tonic-gate 
20110Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)arg, &new_ifcap, sizeof (new_ifcap), flag)) {
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 		return (EFAULT);
20160Sstevel@tonic-gate 	}
20170Sstevel@tonic-gate 
20180Sstevel@tonic-gate 	/* no settable capabilities */
20190Sstevel@tonic-gate 	if (usbprn_ifcap != new_ifcap) {
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 		return (EINVAL);
20220Sstevel@tonic-gate 	}
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate 	return (0);
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate /*
20290Sstevel@tonic-gate  * usbprn_prnio_get_ifinfo:
20300Sstevel@tonic-gate  *	Execute the PRNIOC_GET_IFINFO ioctl
20310Sstevel@tonic-gate  */
20320Sstevel@tonic-gate /* ARGSUSED */
20330Sstevel@tonic-gate static int
usbprn_prnio_get_ifinfo(usbprn_state_t * usbprnp,intptr_t arg,int flag)20340Sstevel@tonic-gate usbprn_prnio_get_ifinfo(usbprn_state_t *usbprnp, intptr_t arg, int flag)
20350Sstevel@tonic-gate {
20360Sstevel@tonic-gate 	struct prn_interface_info	prn_info;
20370Sstevel@tonic-gate 	int	rlen, len;
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 	rlen = strlen(usbprn_prnio_ifinfo);
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20420Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
20430Sstevel@tonic-gate 
20440Sstevel@tonic-gate 	switch (ddi_model_convert_from(flag & FMODELS)) {
20450Sstevel@tonic-gate 	case DDI_MODEL_ILP32: {
20460Sstevel@tonic-gate 		struct prn_interface_info32	prn_info32;
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &prn_info32,
20490Sstevel@tonic-gate 		    sizeof (struct prn_interface_info32), flag)) {
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 			return (EFAULT);
20520Sstevel@tonic-gate 		}
20530Sstevel@tonic-gate 
20540Sstevel@tonic-gate 		prn_info32.if_rlen = rlen;
20550Sstevel@tonic-gate 		len = min(rlen, prn_info32.if_len);
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 		if (ddi_copyout(&usbprn_prnio_ifinfo[0],
20580Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)prn_info32.if_data, len, flag)) {
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 			return (EFAULT);
20610Sstevel@tonic-gate 		}
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 		if (ddi_copyout(&prn_info32, (caddr_t)arg,
20640Sstevel@tonic-gate 		    sizeof (struct prn_interface_info32), flag)) {
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate 			return (EFAULT);
20670Sstevel@tonic-gate 		}
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 		break;
20700Sstevel@tonic-gate 	}
20710Sstevel@tonic-gate 	case DDI_MODEL_NONE:
20720Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20730Sstevel@tonic-gate 		ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &prn_info,
20760Sstevel@tonic-gate 		    sizeof (struct prn_interface_info), flag)) {
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 			return (EFAULT);
20790Sstevel@tonic-gate 		}
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 		prn_info.if_rlen = rlen;
20820Sstevel@tonic-gate 		len = min(rlen, prn_info.if_len);
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 		if (ddi_copyout(&usbprn_prnio_ifinfo[0],
20850Sstevel@tonic-gate 		    prn_info.if_data, len, flag)) {
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate 			return (EFAULT);
20880Sstevel@tonic-gate 		}
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 		if (ddi_copyout(&prn_info, (caddr_t)arg,
20910Sstevel@tonic-gate 		    sizeof (struct prn_interface_info), flag)) {
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 			return (EFAULT);
20940Sstevel@tonic-gate 		}
20950Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20960Sstevel@tonic-gate 
20970Sstevel@tonic-gate 		break;
20980Sstevel@tonic-gate 	}
20990Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 	return (0);
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate /*
21060Sstevel@tonic-gate  * usbprn_prnio_getdevid:
21070Sstevel@tonic-gate  *	Execute the PRNIOC_GET_1284_DEVID ioctl
21080Sstevel@tonic-gate  */
21090Sstevel@tonic-gate static int
usbprn_prnio_get_1284_devid(usbprn_state_t * usbprnp,intptr_t arg,int flag)21100Sstevel@tonic-gate usbprn_prnio_get_1284_devid(usbprn_state_t *usbprnp, intptr_t arg, int flag)
21110Sstevel@tonic-gate {
21120Sstevel@tonic-gate 	struct prn_1284_device_id prn_devid;
21130Sstevel@tonic-gate 	int	len;
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
21180Sstevel@tonic-gate 	switch (ddi_model_convert_from(flag & FMODELS)) {
21190Sstevel@tonic-gate 	case DDI_MODEL_ILP32: {
21200Sstevel@tonic-gate 		struct prn_1284_device_id32	prn_devid32;
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &prn_devid32,
21230Sstevel@tonic-gate 		    sizeof (struct prn_1284_device_id32), flag)) {
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 			return (EFAULT);
21260Sstevel@tonic-gate 		}
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate 		prn_devid32.id_rlen = usbprnp->usbprn_device_id_len - 2;
21290Sstevel@tonic-gate 		len = min(prn_devid32.id_rlen, prn_devid32.id_len);
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
21320Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)prn_devid32.id_data, len, flag)) {
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 			return (EFAULT);
21350Sstevel@tonic-gate 		}
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate 		if (ddi_copyout(&prn_devid32, (caddr_t)arg,
21380Sstevel@tonic-gate 		    sizeof (struct prn_1284_device_id32), flag)) {
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate 			return (EFAULT);
21410Sstevel@tonic-gate 		}
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 		break;
21440Sstevel@tonic-gate 	}
21450Sstevel@tonic-gate 	case DDI_MODEL_NONE:
21460Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21470Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, &prn_devid,
21480Sstevel@tonic-gate 		    sizeof (struct prn_1284_device_id), flag)) {
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 			return (EFAULT);
21510Sstevel@tonic-gate 		}
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate 		prn_devid.id_rlen = usbprnp->usbprn_device_id_len - 2;
21540Sstevel@tonic-gate 		len = min(prn_devid.id_rlen, prn_devid.id_len);
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
21570Sstevel@tonic-gate 		    prn_devid.id_data, len, flag)) {
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 			return (EFAULT);
21600Sstevel@tonic-gate 		}
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 		if (ddi_copyout(&prn_devid, (caddr_t)arg,
21630Sstevel@tonic-gate 		    sizeof (struct prn_1284_device_id), flag)) {
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 			return (EFAULT);
21660Sstevel@tonic-gate 		}
21670Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 		break;
21700Sstevel@tonic-gate 	}
21710Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 	return (0);
21740Sstevel@tonic-gate }
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate /*
21780Sstevel@tonic-gate  * usbprn_prnio_get_timeouts:
21790Sstevel@tonic-gate  *	Return timeout
21800Sstevel@tonic-gate  */
21810Sstevel@tonic-gate static int
usbprn_prnio_get_timeouts(usbprn_state_t * usbprnp,intptr_t arg,int flag)21820Sstevel@tonic-gate usbprn_prnio_get_timeouts(usbprn_state_t *usbprnp, intptr_t arg, int flag)
21830Sstevel@tonic-gate {
21840Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 	if (ddi_copyout(&usbprnp->usbprn_prn_timeouts,
21870Sstevel@tonic-gate 	    (caddr_t)arg, sizeof (struct prn_timeouts), flag)) {
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 		return (EFAULT);
21900Sstevel@tonic-gate 	}
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate 	return (0);
21930Sstevel@tonic-gate }
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 
21960Sstevel@tonic-gate /*
21970Sstevel@tonic-gate  * usbprn_prnio_set_timeouts:
21980Sstevel@tonic-gate  *	Set write timeout and prn timeout
21990Sstevel@tonic-gate  */
22000Sstevel@tonic-gate static int
usbprn_prnio_set_timeouts(usbprn_state_t * usbprnp,intptr_t arg,int flag)22010Sstevel@tonic-gate usbprn_prnio_set_timeouts(usbprn_state_t *usbprnp, intptr_t arg, int flag)
22020Sstevel@tonic-gate {
22030Sstevel@tonic-gate 	struct prn_timeouts prn_timeouts;
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate 	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)arg, &prn_timeouts,
22080Sstevel@tonic-gate 	    sizeof (struct prn_timeouts), flag)) {
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 		return (EFAULT);
22110Sstevel@tonic-gate 	}
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	if ((prn_timeouts.tmo_forward < USBPRN_XFER_TIMEOUT_MIN) ||
22140Sstevel@tonic-gate 	    (prn_timeouts.tmo_forward > USBPRN_XFER_TIMEOUT_MAX)) {
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 		return (EINVAL);
22170Sstevel@tonic-gate 	}
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 	usbprnp->usbprn_prn_timeouts = prn_timeouts;
22220Sstevel@tonic-gate 	usbprnp->usbprn_setparms.write_timeout = prn_timeouts.tmo_forward;
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 	return (0);
22270Sstevel@tonic-gate }
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate /*
22310Sstevel@tonic-gate  * usbprn_biodone:
22320Sstevel@tonic-gate  *	If there is a bp, complete it
22330Sstevel@tonic-gate  */
22340Sstevel@tonic-gate static void
usbprn_biodone(usbprn_state_t * usbprnp,int err,int bytes_remaining)22350Sstevel@tonic-gate usbprn_biodone(usbprn_state_t *usbprnp, int err, int bytes_remaining)
22360Sstevel@tonic-gate {
22370Sstevel@tonic-gate 	struct buf *bp = usbprnp->usbprn_bp;
22380Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
22390Sstevel@tonic-gate 	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
22400Sstevel@tonic-gate 
22410Sstevel@tonic-gate 	ASSERT(mutex_owned(&usbprnp->usbprn_mutex));
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate 	/* all pipes must be idle now */
22440Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
22450Sstevel@tonic-gate 	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
22460Sstevel@tonic-gate 
22470Sstevel@tonic-gate 	if (bp) {
22480Sstevel@tonic-gate 		bp->b_resid = bytes_remaining;
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
22510Sstevel@tonic-gate 		    "usbprn_biodone: "
22520Sstevel@tonic-gate 		    "bp=0x%p bcount=0x%lx resid=0x%lx remaining=0x%x err=%d",
22530Sstevel@tonic-gate 		    (void *)bp, bp->b_bcount, bp->b_resid, bytes_remaining,
22540Sstevel@tonic-gate 		    err);
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 		if (err) {
22570Sstevel@tonic-gate 			bioerror(bp, err);
22580Sstevel@tonic-gate 		}
22590Sstevel@tonic-gate 
22600Sstevel@tonic-gate 		usbprnp->usbprn_bp = NULL;
22610Sstevel@tonic-gate 		biodone(bp);
22620Sstevel@tonic-gate 	}
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	/* release access */
22650Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_dev_acc);
22660Sstevel@tonic-gate }
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate /*
22700Sstevel@tonic-gate  * usbprn_send_async_bulk_data:
22710Sstevel@tonic-gate  *	Send bulk data down to the device through the bulk out pipe
22720Sstevel@tonic-gate  */
22730Sstevel@tonic-gate static void
usbprn_send_async_bulk_data(usbprn_state_t * usbprnp)22740Sstevel@tonic-gate usbprn_send_async_bulk_data(usbprn_state_t *usbprnp)
22750Sstevel@tonic-gate {
22760Sstevel@tonic-gate 	int		rval;
22770Sstevel@tonic-gate 	int		timeout;
22780Sstevel@tonic-gate 	mblk_t		*mp;
22790Sstevel@tonic-gate 	size_t		max_xfer_count, xfer_count;
22800Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
22810Sstevel@tonic-gate 	usb_bulk_req_t *req;
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
22840Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate 	timeout = usbprnp->usbprn_setparms.write_timeout;
22870Sstevel@tonic-gate 	max_xfer_count = usbprnp->usbprn_bp->b_bcount;
22880Sstevel@tonic-gate 	mp = usbprnp->usbprn_bulk_mp;
22890Sstevel@tonic-gate 	ASSERT(mp != NULL);
22907492SZhigang.Lu@Sun.COM 	xfer_count = MBLKL(mp);
22910Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 	req = usb_alloc_bulk_req(usbprnp->usbprn_dip, 0, USB_FLAGS_SLEEP);
22947492SZhigang.Lu@Sun.COM 	req->bulk_len		= (uint_t)xfer_count;
22950Sstevel@tonic-gate 	req->bulk_data		= mp;
22960Sstevel@tonic-gate 	req->bulk_timeout	= timeout;
22970Sstevel@tonic-gate 	req->bulk_cb		= usbprn_bulk_xfer_cb;
22980Sstevel@tonic-gate 	req->bulk_exc_cb	= usbprn_bulk_xfer_exc_cb;
22990Sstevel@tonic-gate 	req->bulk_client_private = (usb_opaque_t)usbprnp;
23000Sstevel@tonic-gate 	req->bulk_attributes	= USB_ATTRS_AUTOCLEARING;
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23030Sstevel@tonic-gate 	    "usbprn_send_async_bulk_data: req = 0x%p "
23040Sstevel@tonic-gate 	    "max_bulk_xfer_size=%lu mp=0x%p xfer_cnt=%lu timeout=%x",
23056898Sfb209375 	    (void *)req, max_xfer_count, (void *)mp, xfer_count, timeout);
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate 	ASSERT(xfer_count <= max_xfer_count);
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 	if ((rval = usb_pipe_bulk_xfer(bulk_out->ps_handle, req, 0)) !=
23110Sstevel@tonic-gate 	    USB_SUCCESS) {
23120Sstevel@tonic-gate 
23130Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23140Sstevel@tonic-gate 		    "usbprn_send_async_bulk_data: Bulk mp=0x%p "
23156898Sfb209375 		    "rval=%d", (void *)mp, rval);
23160Sstevel@tonic-gate 
23170Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
23180Sstevel@tonic-gate 		bulk_out->ps_flags = USBPRN_PS_IDLE;
23190Sstevel@tonic-gate 		usbprnp->usbprn_bulk_mp = NULL;
23200Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
23210Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 		usb_free_bulk_req(req);
23240Sstevel@tonic-gate 	} else {
23250Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
23260Sstevel@tonic-gate 		usbprnp->usbprn_bulk_mp = NULL;
23270Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
23280Sstevel@tonic-gate 	}
23290Sstevel@tonic-gate }
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate /*
23330Sstevel@tonic-gate  * usbprn_bulk_xfer_cb
23340Sstevel@tonic-gate  *	Callback for a normal transfer for both bulk pipes.
23350Sstevel@tonic-gate  */
23360Sstevel@tonic-gate /*ARGSUSED*/
23370Sstevel@tonic-gate static void
usbprn_bulk_xfer_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)23380Sstevel@tonic-gate usbprn_bulk_xfer_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
23390Sstevel@tonic-gate {
23400Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = (usbprn_state_t *)req->bulk_client_private;
23410Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 	ASSERT(usbprnp != NULL);
23440Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23496898Sfb209375 	    "usbprn_bulk_xfer_cb: mp=0x%p ", (void *)usbprnp->usbprn_bulk_mp);
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
23520Sstevel@tonic-gate 	ASSERT(usbprnp->usbprn_bp != NULL);
23530Sstevel@tonic-gate 	ASSERT((req->bulk_cb_flags & USB_CB_INTR_CONTEXT) == 0);
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 	/*
23560Sstevel@tonic-gate 	 * if device is disconnected or driver close called, return
23570Sstevel@tonic-gate 	 * The pipe could be closed, or a timeout could have
23580Sstevel@tonic-gate 	 * come in and the pipe is being reset.  If the
23590Sstevel@tonic-gate 	 * state isn't transferring, then return
23600Sstevel@tonic-gate 	 */
23610Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp)) ||
23620Sstevel@tonic-gate 	    (bulk_out->ps_flags != USBPRN_PS_NEED_TO_XFER)) {
23630Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23640Sstevel@tonic-gate 		    "usbprn_bulk_xfer_cb: no access or pipe closed");
23650Sstevel@tonic-gate 
23660Sstevel@tonic-gate 		bulk_out->ps_flags = USBPRN_PS_IDLE;
23670Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
23680Sstevel@tonic-gate 	} else {
23690Sstevel@tonic-gate 
23700Sstevel@tonic-gate 		/*
23710Sstevel@tonic-gate 		 * data has been xferred, complete the bp.
23720Sstevel@tonic-gate 		 */
23730Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
23740Sstevel@tonic-gate 		    "usbprn_bulk_xfer_cb: transaction over");
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate 		bulk_out->ps_flags = USBPRN_PS_IDLE;
23770Sstevel@tonic-gate 		usbprn_biodone(usbprnp, 0, 0);
23780Sstevel@tonic-gate 	}
23790Sstevel@tonic-gate 
23800Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
23810Sstevel@tonic-gate 
23820Sstevel@tonic-gate 	usb_free_bulk_req(req);
23830Sstevel@tonic-gate }
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate /*
23870Sstevel@tonic-gate  * usbprn_bulk_xfer_exc_cb:
23880Sstevel@tonic-gate  *	Exception callback for the bulk pipes
23890Sstevel@tonic-gate  */
23900Sstevel@tonic-gate static void
usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)23910Sstevel@tonic-gate usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
23920Sstevel@tonic-gate {
23930Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = (usbprn_state_t *)req->bulk_client_private;
23940Sstevel@tonic-gate 	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
23950Sstevel@tonic-gate 	int		bytes_remaining = 0;
23960Sstevel@tonic-gate 	mblk_t		*data = req->bulk_data;
23970Sstevel@tonic-gate 	usb_cr_t	completion_reason = req->bulk_completion_reason;
23980Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags = req->bulk_cb_flags;
23990Sstevel@tonic-gate 
24000Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
24010Sstevel@tonic-gate 	    "usbprn_bulk_xfer_exc_cb: "
24020Sstevel@tonic-gate 	    "pipe=0x%p req=0x%p cr=%d cb_flags=0x%x data=0x%p",
24036898Sfb209375 	    (void *)pipe, (void *)req, completion_reason, cb_flags,
24046898Sfb209375 	    (void *)data);
24050Sstevel@tonic-gate 
24060Sstevel@tonic-gate 	ASSERT((req->bulk_cb_flags & USB_CB_INTR_CONTEXT) == 0);
24070Sstevel@tonic-gate 	ASSERT(data != NULL);
24080Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
24090Sstevel@tonic-gate 
24100Sstevel@tonic-gate 	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
24110Sstevel@tonic-gate 	bulk_out->ps_flags = USBPRN_PS_IDLE;
24120Sstevel@tonic-gate 	bulk_out->ps_cr = completion_reason;
24130Sstevel@tonic-gate 
24140Sstevel@tonic-gate 	if (data) {
24157492SZhigang.Lu@Sun.COM 		bytes_remaining = MBLKL(data);
24160Sstevel@tonic-gate 	}
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 	/*
24190Sstevel@tonic-gate 	 * If the pipe is closed or device not responding or not in
24200Sstevel@tonic-gate 	 * need of transfer, just give up on this bp.
24210Sstevel@tonic-gate 	 */
24220Sstevel@tonic-gate 	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp)) ||
24230Sstevel@tonic-gate 	    (req->bulk_completion_reason == USB_CR_DEV_NOT_RESP)) {
24240Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
24250Sstevel@tonic-gate 		    "usbprn_bulk_xfer_exc_cb: "
24260Sstevel@tonic-gate 		    "device not accesible or wrong state");
24270Sstevel@tonic-gate 		usbprn_biodone(usbprnp, EIO, 0);
24280Sstevel@tonic-gate 	} else {
24290Sstevel@tonic-gate 		if (completion_reason == USB_CR_TIMEOUT) {
24300Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL,
24310Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle,
24320Sstevel@tonic-gate 			    "usbprn_bulk_xfer_exc_cb: timeout error, "
24330Sstevel@tonic-gate 			    "xferred %lu bytes",
24340Sstevel@tonic-gate 			    ((usbprnp->usbprn_bp->b_bcount) -
24350Sstevel@tonic-gate 			    bytes_remaining));
24360Sstevel@tonic-gate 			usbprn_biodone(usbprnp, 0, bytes_remaining);
24370Sstevel@tonic-gate 		} else {
24380Sstevel@tonic-gate 			usbprn_biodone(usbprnp, EIO, 0);
24390Sstevel@tonic-gate 		}
24400Sstevel@tonic-gate 
24410Sstevel@tonic-gate 	}
24420Sstevel@tonic-gate 
24430Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
24440Sstevel@tonic-gate 
24450Sstevel@tonic-gate 	usb_free_bulk_req(req);
24460Sstevel@tonic-gate }
24470Sstevel@tonic-gate 
24480Sstevel@tonic-gate 
24490Sstevel@tonic-gate /*
24500Sstevel@tonic-gate  * usbprn_reconnect_event_cb:
24510Sstevel@tonic-gate  *	Called upon when the device is hotplugged back; event handling
24520Sstevel@tonic-gate  */
24530Sstevel@tonic-gate /*ARGSUSED*/
24540Sstevel@tonic-gate static int
usbprn_reconnect_event_cb(dev_info_t * dip)24550Sstevel@tonic-gate usbprn_reconnect_event_cb(dev_info_t *dip)
24560Sstevel@tonic-gate {
24570Sstevel@tonic-gate 	usbprn_state_t	*usbprnp =
24586898Sfb209375 	    (usbprn_state_t *)ddi_get_soft_state(usbprn_statep,
24596898Sfb209375 	    ddi_get_instance(dip));
24600Sstevel@tonic-gate 
24610Sstevel@tonic-gate 	ASSERT(usbprnp != NULL);
24620Sstevel@tonic-gate 
24630Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
24640Sstevel@tonic-gate 	    "usbprn_reconnect_event_cb:");
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
24690Sstevel@tonic-gate 	ASSERT(usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED);
24700Sstevel@tonic-gate 
24710Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
24720Sstevel@tonic-gate 
24730Sstevel@tonic-gate 	usbprn_restore_device_state(dip, usbprnp);
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	if (usbprnp->usbprn_ugen_hdl) {
24760Sstevel@tonic-gate 		(void) usb_ugen_reconnect_ev_cb(usbprnp->usbprn_ugen_hdl);
24770Sstevel@tonic-gate 	}
24780Sstevel@tonic-gate 
24790Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	return (USB_SUCCESS);
24820Sstevel@tonic-gate }
24830Sstevel@tonic-gate 
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate /*
24860Sstevel@tonic-gate  * usbprn_disconnect_event_cb:
24870Sstevel@tonic-gate  *	callback for disconnect events
24880Sstevel@tonic-gate  */
24890Sstevel@tonic-gate /*ARGSUSED*/
24900Sstevel@tonic-gate static int
usbprn_disconnect_event_cb(dev_info_t * dip)24910Sstevel@tonic-gate usbprn_disconnect_event_cb(dev_info_t *dip)
24920Sstevel@tonic-gate {
24930Sstevel@tonic-gate 	usbprn_state_t	*usbprnp = (usbprn_state_t *)ddi_get_soft_state(
24946898Sfb209375 	    usbprn_statep, ddi_get_instance(dip));
24950Sstevel@tonic-gate 
24960Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
24970Sstevel@tonic-gate 	    "usbprn_disconnect_event_cb: Begin");
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
25020Sstevel@tonic-gate 	usbprnp->usbprn_dev_state = USB_DEV_DISCONNECTED;
25030Sstevel@tonic-gate 
25040Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
25050Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
25060Sstevel@tonic-gate 		    "device was disconnected while open. "
25070Sstevel@tonic-gate 		    "Data may have been lost");
25080Sstevel@tonic-gate 	}
25090Sstevel@tonic-gate 
25100Sstevel@tonic-gate 	/* For now, we set the offline bit in usbprn_last_status */
25110Sstevel@tonic-gate 	usbprnp->usbprn_last_status |= USB_PRINTER_PORT_NO_SELECT;
25120Sstevel@tonic-gate 
25130Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
25140Sstevel@tonic-gate 
25150Sstevel@tonic-gate 	if (usbprnp->usbprn_ugen_hdl) {
25160Sstevel@tonic-gate 		(void) usb_ugen_disconnect_ev_cb(usbprnp->usbprn_ugen_hdl);
25170Sstevel@tonic-gate 	}
25180Sstevel@tonic-gate 
25190Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
25220Sstevel@tonic-gate 	    "usbprn_disconnect_event_cb: End");
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate 	return (USB_SUCCESS);
25250Sstevel@tonic-gate }
25260Sstevel@tonic-gate 
25270Sstevel@tonic-gate 
25280Sstevel@tonic-gate /*
25290Sstevel@tonic-gate  * usbprn_restore_device_state:
25300Sstevel@tonic-gate  *	set original configuration of the device
25310Sstevel@tonic-gate  *	Restores data xfer
25320Sstevel@tonic-gate  */
25330Sstevel@tonic-gate static void
usbprn_restore_device_state(dev_info_t * dip,usbprn_state_t * usbprnp)25340Sstevel@tonic-gate usbprn_restore_device_state(dev_info_t *dip, usbprn_state_t *usbprnp)
25350Sstevel@tonic-gate {
25360Sstevel@tonic-gate 	int alt, rval, iface;
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
25390Sstevel@tonic-gate 	    "usbprn_restore_device_state:");
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
25420Sstevel@tonic-gate 	ASSERT((usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED) ||
25436898Sfb209375 	    (usbprnp->usbprn_dev_state == USB_DEV_SUSPENDED));
25440Sstevel@tonic-gate 
25450Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate 	/* Check if we are talking to the same device */
25480Sstevel@tonic-gate 	if (usb_check_same_device(dip, usbprnp->usbprn_log_handle,
2549978Sfrits 	    USB_LOG_L0, PRINT_MASK_ALL,
25500Sstevel@tonic-gate 	    USB_CHK_ALL, NULL) != USB_SUCCESS) {
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate 		/* change the device state from suspended to disconnected */
25530Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
25540Sstevel@tonic-gate 		usbprnp->usbprn_dev_state = USB_DEV_DISCONNECTED;
25550Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
25560Sstevel@tonic-gate 
25570Sstevel@tonic-gate 		return;
25580Sstevel@tonic-gate 	}
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 	USB_DPRINTF_L0(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
25610Sstevel@tonic-gate 	    "Printer has been reconnected but data may have been lost");
25620Sstevel@tonic-gate 
25630Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate 	/* set last status to online */
25660Sstevel@tonic-gate 	usbprnp->usbprn_last_status &= ~USB_PRINTER_PORT_NO_SELECT;
25670Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
25680Sstevel@tonic-gate 
25690Sstevel@tonic-gate 	/* Get the port status */
25700Sstevel@tonic-gate 	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
25710Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
25720Sstevel@tonic-gate 		    "usbprn_restore_device_state: port status failed");
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 		return;
25750Sstevel@tonic-gate 	}
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
25780Sstevel@tonic-gate 
25790Sstevel@tonic-gate 	if ((usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR) == 0) {
25800Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
25810Sstevel@tonic-gate 		    "usbprn_restore_device_state: An error with the printer");
25820Sstevel@tonic-gate 	}
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
25850Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
25860Sstevel@tonic-gate 		usbprn_close_usb_pipes(usbprnp);
25870Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
25880Sstevel@tonic-gate 	}
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 	/* restore alternate */
25910Sstevel@tonic-gate 	alt = usbprnp->usbprn_if_descr.bAlternateSetting,
25926898Sfb209375 	    mutex_exit(&usbprnp->usbprn_mutex);
25930Sstevel@tonic-gate 
25940Sstevel@tonic-gate 	iface = usb_owns_device(dip) ? 0 :  usb_get_if_number(dip);
25950Sstevel@tonic-gate 	if ((rval = usb_set_alt_if(dip, iface, alt,
25960Sstevel@tonic-gate 	    USB_FLAGS_SLEEP, NULL, NULL)) != USB_SUCCESS) {
25970Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
25980Sstevel@tonic-gate 		    "usbprn_restore_device_state: set alternate failed (%d)",
25990Sstevel@tonic-gate 		    rval);
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate 		return;
26020Sstevel@tonic-gate 	}
26030Sstevel@tonic-gate 
26040Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
26050Sstevel@tonic-gate 
26060Sstevel@tonic-gate 	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
26070Sstevel@tonic-gate 
26080Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
26090Sstevel@tonic-gate 		(void) usbprn_open_usb_pipes(usbprnp);
26100Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
26110Sstevel@tonic-gate 	}
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate 	if (usbprnp->usbprn_pm && usbprnp->usbprn_pm->usbprn_wakeup_enabled) {
26140Sstevel@tonic-gate 		mutex_exit(&usbprnp->usbprn_mutex);
26150Sstevel@tonic-gate 		(void) usb_handle_remote_wakeup(usbprnp->usbprn_dip,
26160Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE);
26170Sstevel@tonic-gate 		mutex_enter(&usbprnp->usbprn_mutex);
26180Sstevel@tonic-gate 	}
26190Sstevel@tonic-gate 
26200Sstevel@tonic-gate 	usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
26210Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
26220Sstevel@tonic-gate 
26230Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
26240Sstevel@tonic-gate 	    "usbprn_restore_device_state: End");
26250Sstevel@tonic-gate }
26260Sstevel@tonic-gate 
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate /*
26290Sstevel@tonic-gate  *	Create power managements components
26300Sstevel@tonic-gate  */
26310Sstevel@tonic-gate static void
usbprn_create_pm_components(dev_info_t * dip,usbprn_state_t * usbprnp)26320Sstevel@tonic-gate usbprn_create_pm_components(dev_info_t *dip, usbprn_state_t *usbprnp)
26330Sstevel@tonic-gate {
26340Sstevel@tonic-gate 	usbprn_power_t	*usbprnpm;
26350Sstevel@tonic-gate 	uint_t		pwr_states;
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
26380Sstevel@tonic-gate 	    "usbprn_create_pm_components: Begin");
26390Sstevel@tonic-gate 
26400Sstevel@tonic-gate 	/* Allocate the state structure */
26410Sstevel@tonic-gate 	usbprnpm = kmem_zalloc(sizeof (usbprn_power_t),
26426898Sfb209375 	    KM_SLEEP);
26430Sstevel@tonic-gate 	usbprnp->usbprn_pm = usbprnpm;
26440Sstevel@tonic-gate 	usbprnpm->usbprn_pm_capabilities = 0;
26450Sstevel@tonic-gate 	usbprnpm->usbprn_current_power = USB_DEV_OS_FULL_PWR;
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 	if (usb_create_pm_components(dip, &pwr_states) ==
26480Sstevel@tonic-gate 	    USB_SUCCESS) {
26490Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_PM,
26500Sstevel@tonic-gate 		    usbprnp->usbprn_log_handle,
26510Sstevel@tonic-gate 		    "usbprn_create_pm_components: "
26520Sstevel@tonic-gate 		    "created PM components");
26530Sstevel@tonic-gate 
26540Sstevel@tonic-gate 		if (usb_handle_remote_wakeup(dip,
26550Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
26560Sstevel@tonic-gate 			usbprnpm->usbprn_wakeup_enabled = 1;
26570Sstevel@tonic-gate 		}
26580Sstevel@tonic-gate 		usbprnpm->usbprn_pwr_states = (uint8_t)pwr_states;
26590Sstevel@tonic-gate 		(void) pm_raise_power(usbprnp->usbprn_dip, 0,
26606898Sfb209375 		    USB_DEV_OS_FULL_PWR);
26610Sstevel@tonic-gate 	} else {
26620Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM,
26630Sstevel@tonic-gate 		    usbprnp->usbprn_log_handle,
26640Sstevel@tonic-gate 		    "usbprn_create_pm_components: Failed");
26650Sstevel@tonic-gate 	}
26660Sstevel@tonic-gate 
26670Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
26680Sstevel@tonic-gate 	    "usbprn_create_pm_components: END");
26690Sstevel@tonic-gate }
26700Sstevel@tonic-gate 
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate /*
26730Sstevel@tonic-gate  * usbprn_pwrlvl0:
26740Sstevel@tonic-gate  * Functions to handle power transition for OS levels 0 -> 3
26750Sstevel@tonic-gate  */
26760Sstevel@tonic-gate static int
usbprn_pwrlvl0(usbprn_state_t * usbprnp)26770Sstevel@tonic-gate usbprn_pwrlvl0(usbprn_state_t *usbprnp)
26780Sstevel@tonic-gate {
26790Sstevel@tonic-gate 	int	rval;
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
26820Sstevel@tonic-gate 	    "usbprn_pwrlvl0:");
26830Sstevel@tonic-gate 
26840Sstevel@tonic-gate 	switch (usbprnp->usbprn_dev_state) {
26850Sstevel@tonic-gate 	case USB_DEV_ONLINE:
26860Sstevel@tonic-gate 		/* Deny the powerdown request if the device is busy */
26870Sstevel@tonic-gate 		if (usbprnp->usbprn_pm->usbprn_pm_busy != 0) {
26880Sstevel@tonic-gate 
26890Sstevel@tonic-gate 			return (USB_FAILURE);
26900Sstevel@tonic-gate 		}
26910Sstevel@tonic-gate 
26920Sstevel@tonic-gate 		/* Issue USB D3 command to the device here */
26930Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl3(usbprnp->usbprn_dip);
26940Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
26950Sstevel@tonic-gate 
26960Sstevel@tonic-gate 		usbprnp->usbprn_dev_state = USB_DEV_PWRED_DOWN;
26970Sstevel@tonic-gate 		usbprnp->usbprn_pm->usbprn_current_power =
26986898Sfb209375 		    USB_DEV_OS_PWR_OFF;
26990Sstevel@tonic-gate 		/* FALLTHRU */
27000Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
27010Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
27020Sstevel@tonic-gate 		/* allow a disconnect/cpr'ed device to go to lower power */
27030Sstevel@tonic-gate 
27040Sstevel@tonic-gate 		return (USB_SUCCESS);
27050Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
27060Sstevel@tonic-gate 	default:
27070Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27080Sstevel@tonic-gate 		    "usbprn_pwrlvl0: illegal dev state");
27090Sstevel@tonic-gate 
27100Sstevel@tonic-gate 		return (USB_FAILURE);
27110Sstevel@tonic-gate 	}
27120Sstevel@tonic-gate }
27130Sstevel@tonic-gate 
27140Sstevel@tonic-gate 
27150Sstevel@tonic-gate /*
27160Sstevel@tonic-gate  * usbprn_pwrlvl1:
27170Sstevel@tonic-gate  *	Functions to handle power transition to OS levels -> 2
27180Sstevel@tonic-gate  */
27190Sstevel@tonic-gate static int
usbprn_pwrlvl1(usbprn_state_t * usbprnp)27200Sstevel@tonic-gate usbprn_pwrlvl1(usbprn_state_t *usbprnp)
27210Sstevel@tonic-gate {
27220Sstevel@tonic-gate 	int	rval;
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27250Sstevel@tonic-gate 	    "usbprn_pwrlvl1:");
27260Sstevel@tonic-gate 
27270Sstevel@tonic-gate 	/* Issue USB D2 command to the device here */
27280Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl2(usbprnp->usbprn_dip);
27290Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
27300Sstevel@tonic-gate 
27310Sstevel@tonic-gate 	return (USB_FAILURE);
27320Sstevel@tonic-gate }
27330Sstevel@tonic-gate 
27340Sstevel@tonic-gate 
27350Sstevel@tonic-gate /*
27360Sstevel@tonic-gate  * usbprn_pwrlvl2:
27370Sstevel@tonic-gate  *	Functions to handle power transition to OS levels -> 1
27380Sstevel@tonic-gate  */
27390Sstevel@tonic-gate static int
usbprn_pwrlvl2(usbprn_state_t * usbprnp)27400Sstevel@tonic-gate usbprn_pwrlvl2(usbprn_state_t *usbprnp)
27410Sstevel@tonic-gate {
27420Sstevel@tonic-gate 	int	rval;
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27450Sstevel@tonic-gate 	    "usbprn_pwrlvl2:");
27460Sstevel@tonic-gate 
27470Sstevel@tonic-gate 	/* Issue USB D1 command to the device here */
27480Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl1(usbprnp->usbprn_dip);
27490Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
27500Sstevel@tonic-gate 
27510Sstevel@tonic-gate 	return (USB_FAILURE);
27520Sstevel@tonic-gate }
27530Sstevel@tonic-gate 
27540Sstevel@tonic-gate 
27550Sstevel@tonic-gate /*
27560Sstevel@tonic-gate  * usbprn_pwrlvl3:
27570Sstevel@tonic-gate  *	Functions to handle power transition to OS level -> 0
27580Sstevel@tonic-gate  */
27590Sstevel@tonic-gate static int
usbprn_pwrlvl3(usbprn_state_t * usbprnp)27600Sstevel@tonic-gate usbprn_pwrlvl3(usbprn_state_t *usbprnp)
27610Sstevel@tonic-gate {
27620Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27630Sstevel@tonic-gate 	    "usbprn_pwrlvl3:");
27640Sstevel@tonic-gate 
27650Sstevel@tonic-gate 	switch (usbprnp->usbprn_dev_state) {
27660Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
27670Sstevel@tonic-gate 		/* Issue USB D0 command to the device here */
27680Sstevel@tonic-gate 		(void) usb_set_device_pwrlvl0(usbprnp->usbprn_dip);
27690Sstevel@tonic-gate 
27700Sstevel@tonic-gate 		usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
27710Sstevel@tonic-gate 		usbprnp->usbprn_pm->usbprn_current_power =
27720Sstevel@tonic-gate 		    USB_DEV_OS_FULL_PWR;
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate 		/* FALLTHRU */
27750Sstevel@tonic-gate 	case USB_DEV_ONLINE:
27760Sstevel@tonic-gate 		/* we are already in full power */
27770Sstevel@tonic-gate 		/* FALLTHRU */
27780Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
27790Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
27800Sstevel@tonic-gate 		/*
27810Sstevel@tonic-gate 		 * PM framework tries to put us in full power
27820Sstevel@tonic-gate 		 * during system shutdown. If we are disconnected/cpr'ed
27830Sstevel@tonic-gate 		 * return success anyways
27840Sstevel@tonic-gate 		 */
27850Sstevel@tonic-gate 
27860Sstevel@tonic-gate 		return (USB_SUCCESS);
27870Sstevel@tonic-gate 	default:
27880Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
27890Sstevel@tonic-gate 		    "usbprn_pwrlvl3:");
27900Sstevel@tonic-gate 
27910Sstevel@tonic-gate 
27920Sstevel@tonic-gate 		return (USB_FAILURE);
27930Sstevel@tonic-gate 	}
27940Sstevel@tonic-gate }
27950Sstevel@tonic-gate 
27960Sstevel@tonic-gate 
27970Sstevel@tonic-gate /*
27980Sstevel@tonic-gate  * usbprn_power :
27990Sstevel@tonic-gate  *	Power entry point
28000Sstevel@tonic-gate  */
28010Sstevel@tonic-gate /* ARGSUSED */
28020Sstevel@tonic-gate static int
usbprn_power(dev_info_t * dip,int comp,int level)28030Sstevel@tonic-gate usbprn_power(dev_info_t *dip, int comp, int level)
28040Sstevel@tonic-gate {
28050Sstevel@tonic-gate 	usbprn_state_t	*usbprnp;
28060Sstevel@tonic-gate 	usbprn_power_t	*pm;
28070Sstevel@tonic-gate 	int		rval = USB_FAILURE;
28080Sstevel@tonic-gate 
28090Sstevel@tonic-gate 	usbprnp = (usbprn_state_t *)ddi_get_soft_state(usbprn_statep,
28106898Sfb209375 	    ddi_get_instance(dip));
28110Sstevel@tonic-gate 
28120Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
28130Sstevel@tonic-gate 	    "usbprn_power: Begin: level=%d", level);
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate 	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
28160Sstevel@tonic-gate 
28170Sstevel@tonic-gate 	mutex_enter(&usbprnp->usbprn_mutex);
28180Sstevel@tonic-gate 	pm = usbprnp->usbprn_pm;
28190Sstevel@tonic-gate 	ASSERT(pm != NULL);
28200Sstevel@tonic-gate 
28210Sstevel@tonic-gate 	/* Check if we are transitioning to a legal power level */
28220Sstevel@tonic-gate 	if (USB_DEV_PWRSTATE_OK(pm->usbprn_pwr_states, level)) {
28230Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
28240Sstevel@tonic-gate 		    "usbprn_power: illegal power level=%d "
28250Sstevel@tonic-gate 		    "pwr_states=0x%x", level, pm->usbprn_pwr_states);
28260Sstevel@tonic-gate 
28270Sstevel@tonic-gate 		goto done;
28280Sstevel@tonic-gate 	}
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 	switch (level) {
28310Sstevel@tonic-gate 	case USB_DEV_OS_PWR_OFF :
28320Sstevel@tonic-gate 		rval = usbprn_pwrlvl0(usbprnp);
28330Sstevel@tonic-gate 
28340Sstevel@tonic-gate 		break;
28350Sstevel@tonic-gate 	case USB_DEV_OS_PWR_1 :
28360Sstevel@tonic-gate 		rval = usbprn_pwrlvl1(usbprnp);
28370Sstevel@tonic-gate 
28380Sstevel@tonic-gate 		break;
28390Sstevel@tonic-gate 	case USB_DEV_OS_PWR_2 :
28400Sstevel@tonic-gate 		rval = usbprn_pwrlvl2(usbprnp);
28410Sstevel@tonic-gate 
28420Sstevel@tonic-gate 		break;
28430Sstevel@tonic-gate 	case USB_DEV_OS_FULL_PWR :
28440Sstevel@tonic-gate 		rval = usbprn_pwrlvl3(usbprnp);
28450Sstevel@tonic-gate 
28460Sstevel@tonic-gate 		break;
28470Sstevel@tonic-gate 	}
28480Sstevel@tonic-gate 
28490Sstevel@tonic-gate done:
28500Sstevel@tonic-gate 	mutex_exit(&usbprnp->usbprn_mutex);
28510Sstevel@tonic-gate 
28520Sstevel@tonic-gate 	usb_release_access(usbprnp->usbprn_ser_acc);
28530Sstevel@tonic-gate 
28540Sstevel@tonic-gate 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
28550Sstevel@tonic-gate }
28560Sstevel@tonic-gate 
28570Sstevel@tonic-gate 
28580Sstevel@tonic-gate /*
28590Sstevel@tonic-gate  * usbprn_print_long:
28600Sstevel@tonic-gate  *	Breakup a string which is > USBPRN_PRINT_MAXLINE and print it
28610Sstevel@tonic-gate  */
28620Sstevel@tonic-gate static void
usbprn_print_long(usbprn_state_t * usbprnp,char * str,int len)28630Sstevel@tonic-gate usbprn_print_long(usbprn_state_t *usbprnp, char *str, int len)
28640Sstevel@tonic-gate {
28650Sstevel@tonic-gate 	char *tmp = str;
28660Sstevel@tonic-gate 	char pbuf[USBPRN_PRINT_MAXLINE];
28670Sstevel@tonic-gate 
28680Sstevel@tonic-gate 	for (;;) {
28690Sstevel@tonic-gate 		if (len <= USBPRN_PRINT_MAXLINE) {
28700Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_ATTA,
28710Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle, "%s", tmp);
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate 			break;
28740Sstevel@tonic-gate 		} else {
28750Sstevel@tonic-gate 			bcopy(tmp, pbuf, USBPRN_PRINT_MAXLINE);
28760Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_ATTA,
28770Sstevel@tonic-gate 			    usbprnp->usbprn_log_handle, "%s", pbuf);
28780Sstevel@tonic-gate 			tmp += USBPRN_PRINT_MAXLINE;
28790Sstevel@tonic-gate 			len -= USBPRN_PRINT_MAXLINE;
28800Sstevel@tonic-gate 		}
28810Sstevel@tonic-gate 	}
28820Sstevel@tonic-gate }
28830Sstevel@tonic-gate 
28840Sstevel@tonic-gate 
28850Sstevel@tonic-gate static void
usbprn_pm_busy_component(usbprn_state_t * usbprn_statep)28860Sstevel@tonic-gate usbprn_pm_busy_component(usbprn_state_t *usbprn_statep)
28870Sstevel@tonic-gate {
28880Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprn_statep->usbprn_mutex));
28890Sstevel@tonic-gate 	if (usbprn_statep->usbprn_pm != NULL) {
28900Sstevel@tonic-gate 		mutex_enter(&usbprn_statep->usbprn_mutex);
28910Sstevel@tonic-gate 		usbprn_statep->usbprn_pm->usbprn_pm_busy++;
28920Sstevel@tonic-gate 
28930Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_PM, usbprn_statep->usbprn_log_handle,
28940Sstevel@tonic-gate 		    "usbprn_pm_busy_component: %d",
28950Sstevel@tonic-gate 		    usbprn_statep->usbprn_pm->usbprn_pm_busy);
28960Sstevel@tonic-gate 
28970Sstevel@tonic-gate 		mutex_exit(&usbprn_statep->usbprn_mutex);
28980Sstevel@tonic-gate 
28990Sstevel@tonic-gate 		if (pm_busy_component(usbprn_statep->usbprn_dip, 0) !=
29000Sstevel@tonic-gate 		    DDI_SUCCESS) {
29010Sstevel@tonic-gate 			mutex_enter(&usbprn_statep->usbprn_mutex);
29020Sstevel@tonic-gate 			usbprn_statep->usbprn_pm->usbprn_pm_busy--;
29030Sstevel@tonic-gate 
29040Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_PM,
29050Sstevel@tonic-gate 			    usbprn_statep->usbprn_log_handle,
29060Sstevel@tonic-gate 			    "usbprn_pm_busy_component: %d",
29070Sstevel@tonic-gate 			    usbprn_statep->usbprn_pm->usbprn_pm_busy);
29080Sstevel@tonic-gate 
29090Sstevel@tonic-gate 			mutex_exit(&usbprn_statep->usbprn_mutex);
29100Sstevel@tonic-gate 		}
29110Sstevel@tonic-gate 
29120Sstevel@tonic-gate 	}
29130Sstevel@tonic-gate }
29140Sstevel@tonic-gate 
29150Sstevel@tonic-gate 
29160Sstevel@tonic-gate static void
usbprn_pm_idle_component(usbprn_state_t * usbprn_statep)29170Sstevel@tonic-gate usbprn_pm_idle_component(usbprn_state_t *usbprn_statep)
29180Sstevel@tonic-gate {
29190Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usbprn_statep->usbprn_mutex));
29200Sstevel@tonic-gate 	if (usbprn_statep->usbprn_pm != NULL) {
29210Sstevel@tonic-gate 		if (pm_idle_component(usbprn_statep->usbprn_dip, 0) ==
29220Sstevel@tonic-gate 		    DDI_SUCCESS) {
29230Sstevel@tonic-gate 			mutex_enter(&usbprn_statep->usbprn_mutex);
29240Sstevel@tonic-gate 			ASSERT(usbprn_statep->usbprn_pm->usbprn_pm_busy > 0);
29250Sstevel@tonic-gate 			usbprn_statep->usbprn_pm->usbprn_pm_busy--;
29260Sstevel@tonic-gate 
29270Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_PM,
29280Sstevel@tonic-gate 			    usbprn_statep->usbprn_log_handle,
29290Sstevel@tonic-gate 			    "usbprn_pm_idle_component: %d",
29300Sstevel@tonic-gate 			    usbprn_statep->usbprn_pm->usbprn_pm_busy);
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate 			mutex_exit(&usbprn_statep->usbprn_mutex);
29330Sstevel@tonic-gate 		}
29340Sstevel@tonic-gate 
29350Sstevel@tonic-gate 	}
29360Sstevel@tonic-gate }
2937