usbprn.c revision 7492:2387323b838f
155714Skris/*
255714Skris * CDDL HEADER START
355714Skris *
455714Skris * The contents of this file are subject to the terms of the
555714Skris * Common Development and Distribution License (the "License").
655714Skris * You may not use this file except in compliance with the License.
755714Skris *
8296341Sdelphij * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
955714Skris * or http://www.opensolaris.org/os/licensing.
1055714Skris * See the License for the specific language governing permissions
1155714Skris * and limitations under the License.
1255714Skris *
1355714Skris * When distributing Covered Code, include this CDDL HEADER in each
1455714Skris * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15296341Sdelphij * If applicable, add the following below this CDDL HEADER, with the
1655714Skris * fields enclosed by brackets "[]" replaced with your own identifying
1755714Skris * information: Portions Copyright [yyyy] [name of copyright owner]
1855714Skris *
1955714Skris * CDDL HEADER END
2055714Skris *
2155714Skris * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
22296341Sdelphij * Use is subject to license terms.
2355714Skris */
2455714Skris
2555714Skris
2655714Skris/*
2755714Skris * Printer Class Driver for USB
2855714Skris *
2955714Skris * This driver supports devices that adhere to the USB Printer Class
3055714Skris * specification 1.0.
3155714Skris *
3255714Skris * NOTE: This driver is not DDI compliant in that it uses undocumented
3355714Skris * functions for logging (USB_DPRINTF_L*, usb_alloc_log_hdl, usb_free_log_hdl),
3455714Skris * and serialization (usb_serialize_access, usb_release_access,
3555714Skris * usb_init_serialization, usb_fini_serialization)
3655714Skris *
37296341Sdelphij * Undocumented functions may go away in a future Solaris OS release.
3855714Skris *
3955714Skris * Please see the DDK for sample code of these functions, and for the usbskel
40296341Sdelphij * skeleton template driver which contains scaled-down versions of these
4155714Skris * functions written in a DDI-compliant way.
4255714Skris */
4355714Skris
4455714Skris#if defined(lint) && !defined(DEBUG)
4555714Skris#define	DEBUG
4655714Skris#endif
4755714Skris#ifdef __lock_lint
4855714Skris#define	_MULTI_DATAMODEL
4955714Skris#endif
5055714Skris
5155714Skris#define	USBDRV_MAJOR_VER	2
52296341Sdelphij#define	USBDRV_MINOR_VER	0
5355714Skris
5455714Skris#include <sys/usb/usba.h>
5555714Skris#include <sys/usb/usba/usba_ugen.h>
5655714Skris#include <sys/bpp_io.h>
5755714Skris#include <sys/ecppsys.h>
5855714Skris#include <sys/prnio.h>
5955714Skris#include <sys/errno.h>
6055714Skris#include <sys/usb/clients/printer/usb_printer.h>
6155714Skris#include <sys/usb/clients/printer/usbprn.h>
6255714Skris#include <sys/strsun.h>
6355714Skris
6459191Skris/* Debugging support */
65160814Ssimonuint_t	usbprn_errmask		= (uint_t)PRINT_MASK_ALL;
6655714Skrisuint_t	usbprn_errlevel 	= USB_LOG_L4;
6755714Skrisuint_t	usbprn_instance_debug	= (uint_t)-1;
68296341Sdelphij
6955714Skris/* local variables */
7055714Skrisstatic uint_t usbprn_ifcap =
71296341Sdelphij	PRN_HOTPLUG | PRN_1284_DEVID | PRN_1284_STATUS | PRN_TIMEOUTS;
72296341Sdelphij
73296341Sdelphij/*
74100928Snectar * Function Prototypes
75296341Sdelphij */
76100928Snectarstatic int	usbprn_attach(dev_info_t *, ddi_attach_cmd_t);
77296341Sdelphijstatic int	usbprn_detach(dev_info_t *, ddi_detach_cmd_t);
78296341Sdelphijstatic int	usbprn_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
79296341Sdelphijstatic void	usbprn_cleanup(dev_info_t *, usbprn_state_t *);
80296341Sdelphij
81296341Sdelphijstatic int	usbprn_get_descriptors(usbprn_state_t *);
82296341Sdelphijstatic int	usbprn_get_device_id(usbprn_state_t *);
83296341Sdelphijstatic int	usbprn_get_port_status(usbprn_state_t *);
84296341Sdelphij
85296341Sdelphijstatic int	usbprn_open(dev_t *, int, int, cred_t *);
86296341Sdelphijstatic int	usbprn_close(dev_t, int, int, cred_t *);
87296341Sdelphijstatic int	usbprn_open_usb_pipes(usbprn_state_t *);
88296341Sdelphijstatic void	usbprn_close_usb_pipes(usbprn_state_t *);
89100928Snectarstatic int	usbprn_write(dev_t, struct uio *, cred_t *);
90296341Sdelphijstatic int	usbprn_read(dev_t, struct uio *, cred_t *);
91100928Snectarstatic int	usbprn_poll(dev_t, short, int, short *, struct pollhead **);
92296341Sdelphij
93296341Sdelphijstatic int	usbprn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
94127128Snectarstatic void	usbprn_minphys(struct buf *);
95296341Sdelphijstatic int	usbprn_strategy(struct buf *);
96296341Sdelphijstatic int	usbprn_setparms(usbprn_state_t *, intptr_t arg, int);
97296341Sdelphijstatic int	usbprn_getparms(usbprn_state_t *, intptr_t, int);
98296341Sdelphijstatic void	usbprn_geterr(usbprn_state_t *, intptr_t, int);
99296341Sdelphijstatic int	usbprn_testio(usbprn_state_t  *, int);
100296341Sdelphijstatic int	usbprn_ioctl_get_status(usbprn_state_t *);
101296341Sdelphijstatic int	usbprn_prnio_get_status(usbprn_state_t *, intptr_t, int);
102296341Sdelphijstatic int	usbprn_prnio_get_1284_status(usbprn_state_t *, intptr_t, int);
103100928Snectarstatic int	usbprn_prnio_get_ifcap(usbprn_state_t *, intptr_t, int);
104160814Ssimonstatic int	usbprn_prnio_set_ifcap(usbprn_state_t *, intptr_t, int);
105296341Sdelphijstatic int	usbprn_prnio_get_ifinfo(usbprn_state_t *, intptr_t, int);
106296341Sdelphijstatic int	usbprn_prnio_get_1284_devid(usbprn_state_t *, intptr_t, int);
107296341Sdelphijstatic int	usbprn_prnio_get_timeouts(usbprn_state_t *, intptr_t, int);
108296341Sdelphijstatic int	usbprn_prnio_set_timeouts(usbprn_state_t *, intptr_t, int);
109296341Sdelphij
110296341Sdelphijstatic void	usbprn_send_async_bulk_data(usbprn_state_t *);
111296341Sdelphij
112160814Ssimonstatic void	usbprn_bulk_xfer_cb(usb_pipe_handle_t, usb_bulk_req_t *);
113296341Sdelphijstatic void	usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t,
114296341Sdelphij		    usb_bulk_req_t *);
115296341Sdelphij
116296341Sdelphijstatic void	usbprn_biodone(usbprn_state_t *, int, int);
117296341Sdelphijstatic char	usbprn_error_state(uchar_t);
118160814Ssimonstatic void	usbprn_print_long(usbprn_state_t *, char *, int);
119296341Sdelphij
120296341Sdelphij/* event handling */
121296341Sdelphijstatic	void	usbprn_restore_device_state(dev_info_t *, usbprn_state_t *);
122296341Sdelphijstatic	int	usbprn_disconnect_event_cb(dev_info_t *);
123296341Sdelphijstatic	int	usbprn_reconnect_event_cb(dev_info_t *);
124296341Sdelphijstatic	int	usbprn_cpr_suspend(dev_info_t *);
125296341Sdelphijstatic	void	usbprn_cpr_resume(dev_info_t *);
126296341Sdelphij
127160814Ssimonstatic usb_event_t usbprn_events = {
128296341Sdelphij	usbprn_disconnect_event_cb,
129160814Ssimon	usbprn_reconnect_event_cb,
130296341Sdelphij	NULL, NULL
131296341Sdelphij};
132296341Sdelphij
133296341Sdelphij/* PM handling */
134160814Ssimonstatic	void	usbprn_create_pm_components(dev_info_t *, usbprn_state_t *);
135296341Sdelphijstatic	int	usbprn_power(dev_info_t *, int comp, int level);
136160814Ssimonstatic	int	usbprn_pwrlvl0(usbprn_state_t *);
137238405Sjkimstatic	int	usbprn_pwrlvl1(usbprn_state_t *);
138296341Sdelphijstatic	int	usbprn_pwrlvl2(usbprn_state_t *);
139296341Sdelphijstatic	int	usbprn_pwrlvl3(usbprn_state_t *);
140296341Sdelphijstatic	void	usbprn_pm_busy_component(usbprn_state_t *);
141296341Sdelphijstatic	void	usbprn_pm_idle_component(usbprn_state_t *);
142296341Sdelphij
143296341Sdelphij/* module loading stuff */
144296341Sdelphijstruct cb_ops usbprn_cb_ops = {
145238405Sjkim	usbprn_open,		/* open  */
146296341Sdelphij	usbprn_close,		/* close */
147238405Sjkim	nulldev,		/* strategy */
148296341Sdelphij	nulldev,		/* print */
149296341Sdelphij	nulldev,		/* dump */
150238405Sjkim	usbprn_read,		/* read */
151296341Sdelphij	usbprn_write,		/* write */
152296341Sdelphij	usbprn_ioctl,		/* ioctl */
153296341Sdelphij	nulldev,		/* devmap */
154238405Sjkim	nulldev,		/* mmap */
155296341Sdelphij	nulldev,		/* segmap */
156296341Sdelphij	usbprn_poll,		/* poll */
157238405Sjkim	ddi_prop_op,		/* cb_prop_op */
158296341Sdelphij	NULL,			/* streamtab  */
159296341Sdelphij	D_64BIT | D_MP
160296341Sdelphij};
161296341Sdelphij
162296341Sdelphijstatic struct dev_ops usbprn_ops = {
163238405Sjkim	DEVO_REV,		/* devo_rev, */
164296341Sdelphij	0,			/* refcnt  */
165296341Sdelphij	usbprn_info,		/* info */
166238405Sjkim	nulldev,		/* identify */
167296341Sdelphij	nulldev,		/* probe */
168238405Sjkim	usbprn_attach,		/* attach */
169296341Sdelphij	usbprn_detach,		/* detach */
170296341Sdelphij	nodev,			/* reset */
171296341Sdelphij	&usbprn_cb_ops,		/* driver operations */
172296341Sdelphij	NULL,			/* bus operations */
173238405Sjkim	usbprn_power		/* power */
174296341Sdelphij};
175296341Sdelphij
176238405Sjkimstatic struct modldrv usbprnmodldrv =	{
177296341Sdelphij	&mod_driverops,
178296341Sdelphij	"USB printer client driver",
179238405Sjkim	&usbprn_ops
180296341Sdelphij};
181238405Sjkim
182296341Sdelphijstatic struct modlinkage modlinkage = {
183296341Sdelphij	MODREV_1,
184296341Sdelphij	&usbprnmodldrv,
185296341Sdelphij	NULL,
186296341Sdelphij};
187296341Sdelphij
188296341Sdelphij/* local variables */
189296341Sdelphij
190238405Sjkim/* soft state structures */
191296341Sdelphij#define	USBPRN_INITIAL_SOFT_SPACE	1
192238405Sjkimstatic void *usbprn_statep;
193238405Sjkim
194296341Sdelphijstatic int usbprn_max_xfer_size = USBPRN_MAX_XFER_SIZE;
195296341Sdelphij
196296341Sdelphij/* prnio support */
197296341Sdelphijstatic const char usbprn_prnio_ifinfo[] = PRN_USB;
198296341Sdelphij
199238405Sjkim
200296341Sdelphijint
201238405Sjkim_init(void)
202296341Sdelphij{
203296341Sdelphij	int rval;
204296341Sdelphij
205238405Sjkim	if ((rval = ddi_soft_state_init(&usbprn_statep,
206296341Sdelphij	    sizeof (usbprn_state_t), USBPRN_INITIAL_SOFT_SPACE)) != 0) {
207296341Sdelphij
208238405Sjkim		return (rval);
209296341Sdelphij	}
210296341Sdelphij
211296341Sdelphij	if ((rval = mod_install(&modlinkage)) != 0) {
212296341Sdelphij		ddi_soft_state_fini(&usbprn_statep);
213296341Sdelphij	}
214238405Sjkim
215296341Sdelphij	return (rval);
216296341Sdelphij}
217296341Sdelphij
218238405Sjkim
219296341Sdelphijint
220238405Sjkim_fini(void)
221296341Sdelphij{
222296341Sdelphij	int rval;
223296341Sdelphij
224296341Sdelphij	if ((rval = mod_remove(&modlinkage)) != 0) {
225238405Sjkim
226296341Sdelphij		return (rval);
227296341Sdelphij	}
228296341Sdelphij
229296341Sdelphij	ddi_soft_state_fini(&usbprn_statep);
230296341Sdelphij
231296341Sdelphij	return (rval);
232238405Sjkim}
233296341Sdelphij
234238405Sjkim
235296341Sdelphijint
236296341Sdelphij_info(struct modinfo *modinfop)
237296341Sdelphij{
238296341Sdelphij	return (mod_info(&modlinkage, modinfop));
239238405Sjkim}
240296341Sdelphij
241296341Sdelphij
242238405Sjkim/*
243296341Sdelphij * usbprn_info:
244296341Sdelphij *	Get minor number, soft state structure, etc.
245296341Sdelphij */
246296341Sdelphij/*ARGSUSED*/
247296341Sdelphijstatic int
248238405Sjkimusbprn_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
249296341Sdelphij			void *arg, void **result)
250296341Sdelphij{
251238405Sjkim	usbprn_state_t	*usbprnp;
25255714Skris	int		error = DDI_FAILURE;
253296341Sdelphij	minor_t		minor = getminor((dev_t)arg);
254296341Sdelphij	int		instance = USBPRN_MINOR_TO_INSTANCE(minor);
255296341Sdelphij
256296341Sdelphij	switch (infocmd) {
257296341Sdelphij	case DDI_INFO_DEVT2DEVINFO:
258296341Sdelphij		if ((usbprnp = ddi_get_soft_state(usbprn_statep,
259296341Sdelphij		    instance)) != NULL) {
260296341Sdelphij			*result = usbprnp->usbprn_dip;
261296341Sdelphij			if (*result != NULL) {
262296341Sdelphij				error = DDI_SUCCESS;
26355714Skris			}
264296341Sdelphij		} else {
265296341Sdelphij			*result = NULL;
266296341Sdelphij		}
267296341Sdelphij
268296341Sdelphij		break;
269296341Sdelphij	case DDI_INFO_DEVT2INSTANCE:
270296341Sdelphij		*result = (void *)(uintptr_t)instance;
271296341Sdelphij		error = DDI_SUCCESS;
272296341Sdelphij
273296341Sdelphij		break;
274296341Sdelphij	default:
275296341Sdelphij
276296341Sdelphij		break;
277296341Sdelphij	}
278296341Sdelphij
279296341Sdelphij	return (error);
280296341Sdelphij}
281296341Sdelphij
282280268Sdelphij
283296341Sdelphij/*
284296341Sdelphij * usbprn_attach:
28555714Skris *	Attach driver
286296341Sdelphij *	Get the descriptor information
287296341Sdelphij *	Get the device id
288296341Sdelphij *	Reset the device
289296341Sdelphij *	Get the port status
290296341Sdelphij */
291296341Sdelphijstatic int
292296341Sdelphijusbprn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
293296341Sdelphij{
294296341Sdelphij	int			instance = ddi_get_instance(dip);
295296341Sdelphij	usbprn_state_t		*usbprnp = NULL;
296296341Sdelphij	size_t			sz;
297296341Sdelphij	usb_ugen_info_t 	usb_ugen_info;
298296341Sdelphij
299296341Sdelphij	switch (cmd) {
300296341Sdelphij	case DDI_ATTACH:
301296341Sdelphij
302296341Sdelphij		break;
303296341Sdelphij	case DDI_RESUME:
304296341Sdelphij		usbprn_cpr_resume(dip);
305296341Sdelphij
306296341Sdelphij		return (DDI_SUCCESS);
307296341Sdelphij	default:
308296341Sdelphij
309296341Sdelphij		return (DDI_FAILURE);
310296341Sdelphij	}
311296341Sdelphij
312296341Sdelphij	if (ddi_soft_state_zalloc(usbprn_statep, instance) == DDI_SUCCESS) {
313296341Sdelphij		usbprnp = ddi_get_soft_state(usbprn_statep, instance);
314296341Sdelphij	}
315296341Sdelphij	if (usbprnp == NULL)  {
316296341Sdelphij
317296341Sdelphij		return (DDI_FAILURE);
318296341Sdelphij	}
319296341Sdelphij
32055714Skris	usbprnp->usbprn_instance = instance;
321296341Sdelphij	usbprnp->usbprn_dip	= dip;
322296341Sdelphij	usbprnp->usbprn_log_handle = usb_alloc_log_hdl(dip,
323296341Sdelphij	    "prn", &usbprn_errlevel,
32455714Skris	    &usbprn_errmask, &usbprn_instance_debug, 0);
325296341Sdelphij
326296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
32755714Skris	    "usbprn_attach: cmd=%x", cmd);
328296341Sdelphij
329296341Sdelphij	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
330296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
331296341Sdelphij		    "usb_client_attach failed");
332296341Sdelphij
33355714Skris		goto fail;
334296341Sdelphij	}
335296341Sdelphij	if (usb_get_dev_data(dip, &usbprnp->usbprn_dev_data,
336296341Sdelphij	    USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
337296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
338296341Sdelphij		    "usb_get_dev_data failed");
339296341Sdelphij
340296341Sdelphij		goto fail;
341296341Sdelphij	}
342296341Sdelphij
343296341Sdelphij	/* Initialize locks and conditional variables */
344296341Sdelphij	mutex_init(&usbprnp->usbprn_mutex, NULL, MUTEX_DRIVER,
345296341Sdelphij	    usbprnp->usbprn_dev_data->dev_iblock_cookie);
346296341Sdelphij	usbprnp->usbprn_write_acc = usb_init_serialization(dip,
347296341Sdelphij	    USB_INIT_SER_CHECK_SAME_THREAD);
348296341Sdelphij	usbprnp->usbprn_ser_acc = usb_init_serialization(dip,
349296341Sdelphij	    USB_INIT_SER_CHECK_SAME_THREAD);
350296341Sdelphij	usbprnp->usbprn_dev_acc = usb_init_serialization(dip, 0);
35155714Skris
352296341Sdelphij	usbprnp->usbprn_flags |= USBPRN_LOCKS_INIT_DONE;
353296341Sdelphij
354296341Sdelphij	/* Obtain all the relevant descriptors */
355296341Sdelphij	if (usbprn_get_descriptors(usbprnp) != USB_SUCCESS) {
356296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
357296341Sdelphij		    "usb get descriptors failed");
358296341Sdelphij
359296341Sdelphij		goto fail;
360296341Sdelphij	}
36155714Skris
362296341Sdelphij	usbprnp->usbprn_def_ph = usbprnp->usbprn_dev_data->dev_default_ph;
363296341Sdelphij
364296341Sdelphij	/* Obtain the device id */
365296341Sdelphij	(void) usbprn_get_device_id(usbprnp);
366296341Sdelphij
367296341Sdelphij	/* Get the port status */
368296341Sdelphij	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
36955714Skris		/* some printers fail on the first */
370296341Sdelphij		if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
371296341Sdelphij			USB_DPRINTF_L2(PRINT_MASK_ATTA,
372296341Sdelphij			    usbprnp->usbprn_log_handle,
373296341Sdelphij			    "usb get port status failed");
374296341Sdelphij
375296341Sdelphij			goto fail;
37655714Skris		}
377296341Sdelphij	}
378296341Sdelphij
379296341Sdelphij	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
380296341Sdelphij	    "usbprn_attach: printer status=0x%x", usbprnp->usbprn_last_status);
381296341Sdelphij
382296341Sdelphij	if ((usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR) == 0) {
383296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
384296341Sdelphij		    "usbprn_attach: error occurred with the printer");
385296341Sdelphij	}
386296341Sdelphij
387296341Sdelphij	/*
388296341Sdelphij	 * Create minor node based on information from the
389296341Sdelphij	 * descriptors
390296341Sdelphij	 */
391296341Sdelphij	if ((ddi_create_minor_node(dip, "printer", S_IFCHR,
392296341Sdelphij	    instance << USBPRN_MINOR_INSTANCE_SHIFT,
393296341Sdelphij	    DDI_NT_PRINTER, 0)) != DDI_SUCCESS) {
394296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
395296341Sdelphij		    "usbprn_attach: cannot create minor node");
396296341Sdelphij
397296341Sdelphij		goto fail;
398296341Sdelphij	}
399296341Sdelphij
400296341Sdelphij	usbprnp->usbprn_setparms.write_timeout = USBPRN_XFER_TIMEOUT;
401296341Sdelphij	usbprnp->usbprn_setparms.mode =  ECPP_CENTRONICS;
402296341Sdelphij	usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
403296341Sdelphij
40455714Skris	if (usb_pipe_get_max_bulk_transfer_size(usbprnp->usbprn_dip, &sz)) {
405160814Ssimon
406296341Sdelphij		goto fail;
407296341Sdelphij	}
408296341Sdelphij
409296341Sdelphij	usbprnp->usbprn_max_bulk_xfer_size = sz;
410296341Sdelphij
411296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
412296341Sdelphij	    "usbprn_attach: xfer_size=0x%lx", sz);
413296341Sdelphij
414296341Sdelphij	/* enable PM */
415160814Ssimon	usbprn_create_pm_components(dip, usbprnp);
41655714Skris
41755714Skris	/* Register for events */
418296341Sdelphij	if (usb_register_event_cbs(dip, &usbprn_events, 0) != USB_SUCCESS) {
419296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
420296341Sdelphij		    "usbprn_attach: usb_register_event_cbs failed");
421296341Sdelphij
422296341Sdelphij		goto fail;
423296341Sdelphij	}
424296341Sdelphij
425296341Sdelphij	usb_free_dev_data(dip, usbprnp->usbprn_dev_data);
426296341Sdelphij	usbprnp->usbprn_dev_data = NULL;
427296341Sdelphij
428296341Sdelphij	if (usb_owns_device(dip)) {
429296341Sdelphij		/* get a ugen handle */
430296341Sdelphij		bzero(&usb_ugen_info, sizeof (usb_ugen_info));
431296341Sdelphij
43255714Skris		usb_ugen_info.usb_ugen_flags = 0;
433296341Sdelphij		usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
434296341Sdelphij		    (dev_t)USBPRN_MINOR_UGEN_BITS_MASK;
435296341Sdelphij		usb_ugen_info.usb_ugen_minor_node_instance_mask =
436296341Sdelphij		    (dev_t)~USBPRN_MINOR_UGEN_BITS_MASK;
437280268Sdelphij		usbprnp->usbprn_ugen_hdl =
438296341Sdelphij		    usb_ugen_get_hdl(dip, &usb_ugen_info);
439296341Sdelphij
440296341Sdelphij		if (usb_ugen_attach(usbprnp->usbprn_ugen_hdl, cmd) !=
441296341Sdelphij		    USB_SUCCESS) {
442280268Sdelphij			USB_DPRINTF_L2(PRINT_MASK_ATTA,
443296341Sdelphij			    usbprnp->usbprn_log_handle,
444296341Sdelphij			    "usb_ugen_attach failed");
44555714Skris
446296341Sdelphij			usb_ugen_release_hdl(usbprnp->usbprn_ugen_hdl);
447296341Sdelphij			usbprnp->usbprn_ugen_hdl = NULL;
448296341Sdelphij		}
449296341Sdelphij	}
450296341Sdelphij
451296341Sdelphij	/* Report device */
452296341Sdelphij	ddi_report_dev(dip);
453296341Sdelphij
454296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
455296341Sdelphij	    "usbprn_attach: done");
456296341Sdelphij
457296341Sdelphij	return (DDI_SUCCESS);
458296341Sdelphij
459296341Sdelphijfail:
460296341Sdelphij	if (usbprnp) {
461296341Sdelphij		usbprn_cleanup(dip, usbprnp);
462296341Sdelphij	}
463296341Sdelphij
464296341Sdelphij	return (DDI_FAILURE);
465296341Sdelphij}
466296341Sdelphij
467296341Sdelphij
468296341Sdelphij/*
469296341Sdelphij * usbprn_detach:
470296341Sdelphij *	detach or suspend driver instance
471296341Sdelphij */
472296341Sdelphijstatic int
473296341Sdelphijusbprn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
474296341Sdelphij{
475296341Sdelphij	int		instance = ddi_get_instance(dip);
476296341Sdelphij	usbprn_state_t	*usbprnp;
477296341Sdelphij	int		rval = DDI_FAILURE;
478296341Sdelphij
479296341Sdelphij	usbprnp = ddi_get_soft_state(usbprn_statep, instance);
480296341Sdelphij
481296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
482296341Sdelphij	    "usbprn_detach: cmd=%x", cmd);
483296341Sdelphij
484296341Sdelphij	switch (cmd) {
485296341Sdelphij	case DDI_DETACH:
486296341Sdelphij		ASSERT((usbprnp->usbprn_flags & USBPRN_OPEN) == 0);
487296341Sdelphij		usbprn_cleanup(dip, usbprnp);
488296341Sdelphij
489296341Sdelphij		return (DDI_SUCCESS);
490296341Sdelphij	case DDI_SUSPEND:
49155714Skris		rval = usbprn_cpr_suspend(dip);
492284295Sdelphij
493284295Sdelphij		return ((rval == USB_SUCCESS) ? DDI_SUCCESS :
494284295Sdelphij		    DDI_FAILURE);
495284295Sdelphij	default:
496284295Sdelphij
497284295Sdelphij		return (rval);
498296341Sdelphij	}
499296341Sdelphij}
500296341Sdelphij
501296341Sdelphij
502296341Sdelphij/*
503296341Sdelphij * usbprn_cleanup:
504296341Sdelphij *	clean up the driver state
505296341Sdelphij */
50655714Skrisstatic void
507296341Sdelphijusbprn_cleanup(dev_info_t *dip, usbprn_state_t *usbprnp)
508296341Sdelphij{
509296341Sdelphij	usbprn_power_t	*usbprnpm = usbprnp->usbprn_pm;
510296341Sdelphij	int		rval = 0;
511296341Sdelphij
512296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
513296341Sdelphij	    "usbprn_cleanup: Start");
51455714Skris
515296341Sdelphij	ASSERT(usbprnp != NULL);
516296341Sdelphij
517296341Sdelphij	if (usbprnp->usbprn_flags & USBPRN_LOCKS_INIT_DONE) {
518296341Sdelphij		/*
519296341Sdelphij		 * Disable the event callbacks first, after this point, event
520296341Sdelphij		 * callbacks will never get called. Note we shouldn't hold
521296341Sdelphij		 * mutex while unregistering events because there may be a
522296341Sdelphij		 * competing event callback thread. Event callbacks are done
52355714Skris		 * with ndi mutex held and this can cause a potential deadlock.
524296341Sdelphij		 */
52555714Skris		usb_unregister_event_cbs(dip, &usbprn_events);
526296341Sdelphij
527296341Sdelphij		mutex_enter(&usbprnp->usbprn_mutex);
528296341Sdelphij		if ((usbprnpm) &&
529296341Sdelphij		    (usbprnp->usbprn_dev_state != USB_DEV_DISCONNECTED)) {
530296341Sdelphij
531296341Sdelphij			mutex_exit(&usbprnp->usbprn_mutex);
53255714Skris			usbprn_pm_busy_component(usbprnp);
53355714Skris			mutex_enter(&usbprnp->usbprn_mutex);
534296341Sdelphij
535296341Sdelphij			if (usbprnpm->usbprn_wakeup_enabled) {
536296341Sdelphij
537296341Sdelphij				mutex_exit(&usbprnp->usbprn_mutex);
53855714Skris
539296341Sdelphij				(void) pm_raise_power(dip, 0,
540296341Sdelphij				    USB_DEV_OS_FULL_PWR);
541296341Sdelphij
542296341Sdelphij				if ((rval = usb_handle_remote_wakeup(dip,
54355714Skris				    USB_REMOTE_WAKEUP_DISABLE)) !=
544296341Sdelphij				    USB_SUCCESS) {
545296341Sdelphij					USB_DPRINTF_L2(PRINT_MASK_ALL,
546296341Sdelphij					    usbprnp->usbprn_log_handle,
547296341Sdelphij					    "usbprn_cleanup: "
54855714Skris					    "disable remote wakeup "
549296341Sdelphij					    "failed, rval=%d", rval);
550296341Sdelphij				}
551296341Sdelphij			} else {
552296341Sdelphij				mutex_exit(&usbprnp->usbprn_mutex);
553296341Sdelphij			}
554296341Sdelphij
555296341Sdelphij			(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
556296341Sdelphij			usbprn_pm_idle_component(usbprnp);
557296341Sdelphij
558296341Sdelphij			mutex_enter(&usbprnp->usbprn_mutex);
559296341Sdelphij		}
560296341Sdelphij
561296341Sdelphij		ddi_remove_minor_node(dip, NULL);
56255714Skris
563296341Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
564296341Sdelphij
565296341Sdelphij		if (usbprnp->usbprn_device_id) {
566296341Sdelphij			kmem_free(usbprnp->usbprn_device_id,
567296341Sdelphij			    usbprnp->usbprn_device_id_len + 1);
568296341Sdelphij		}
569296341Sdelphij
570296341Sdelphij		mutex_destroy(&usbprnp->usbprn_mutex);
57155714Skris		usb_fini_serialization(usbprnp->usbprn_dev_acc);
572296341Sdelphij		usb_fini_serialization(usbprnp->usbprn_ser_acc);
573296341Sdelphij		usb_fini_serialization(usbprnp->usbprn_write_acc);
574296341Sdelphij	}
575296341Sdelphij
576296341Sdelphij	if (usbprnpm) {
577296341Sdelphij		kmem_free(usbprnpm, sizeof (usbprn_power_t));
578296341Sdelphij	}
579296341Sdelphij
580296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
581296341Sdelphij	    "usbprn_cleanup: End");
58255714Skris
583296341Sdelphij	if (usbprnp->usbprn_ugen_hdl) {
584296341Sdelphij		(void) usb_ugen_detach(usbprnp->usbprn_ugen_hdl, DDI_DETACH);
585296341Sdelphij		usb_ugen_release_hdl(usbprnp->usbprn_ugen_hdl);
586296341Sdelphij	}
587296341Sdelphij
588296341Sdelphij	/* unregister with USBA */
589296341Sdelphij	usb_client_detach(dip, usbprnp->usbprn_dev_data);
590296341Sdelphij
591296341Sdelphij	usb_free_log_hdl(usbprnp->usbprn_log_handle);
592296341Sdelphij	ddi_prop_remove_all(dip);
593296341Sdelphij	ddi_soft_state_free(usbprn_statep, usbprnp->usbprn_instance);
594296341Sdelphij}
595296341Sdelphij
596296341Sdelphij
597296341Sdelphij/*
598296341Sdelphij * usbprn_cpr_suspend:
599296341Sdelphij *	prepare to be suspended
600296341Sdelphij */
60155714Skrisstatic int
602296341Sdelphijusbprn_cpr_suspend(dev_info_t *dip)
603296341Sdelphij{
604296341Sdelphij	usbprn_state_t	*usbprnp;
605296341Sdelphij	int		instance = ddi_get_instance(dip);
606296341Sdelphij	int		rval = USB_FAILURE;
607296341Sdelphij
608296341Sdelphij	usbprnp = ddi_get_soft_state(usbprn_statep, instance);
609296341Sdelphij
610296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
611296341Sdelphij	    "usbprn_cpr_suspend");
612296341Sdelphij
613296341Sdelphij	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
614296341Sdelphij
615296341Sdelphij	mutex_enter(&usbprnp->usbprn_mutex);
616296341Sdelphij
617296341Sdelphij	if ((usbprnp->usbprn_flags & USBPRN_OPEN) != 0) {
618296341Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
619296341Sdelphij
620296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_CPR,
621234954Sbz		    usbprnp->usbprn_log_handle,
622296341Sdelphij		    "usbprn_cpr_suspend: "
623296341Sdelphij		    "Device is open.  Can't suspend");
624296341Sdelphij
625296341Sdelphij	} else {
626296341Sdelphij		usbprnp->usbprn_dev_state = USB_DEV_SUSPENDED;
627296341Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
628296341Sdelphij
629296341Sdelphij		USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
630296341Sdelphij		    "usbprn_cpr_suspend: SUCCESS");
631296341Sdelphij		rval = USB_SUCCESS;
63255714Skris	}
633296341Sdelphij	usb_release_access(usbprnp->usbprn_ser_acc);
634296341Sdelphij
635296341Sdelphij	if ((rval == USB_SUCCESS) && usbprnp->usbprn_ugen_hdl) {
636296341Sdelphij		rval = usb_ugen_detach(usbprnp->usbprn_ugen_hdl,
637296341Sdelphij		    DDI_SUSPEND);
638296341Sdelphij	}
63955714Skris
640296341Sdelphij	return (rval);
641296341Sdelphij}
642296341Sdelphij
643296341Sdelphij
644296341Sdelphijstatic void
645296341Sdelphijusbprn_cpr_resume(dev_info_t *dip)
646296341Sdelphij{
647296341Sdelphij	int		instance = ddi_get_instance(dip);
648296341Sdelphij	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep, instance);
649296341Sdelphij
650296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_CPR, usbprnp->usbprn_log_handle,
65155714Skris	    "usbprn_cpr_resume");
652296341Sdelphij
653296341Sdelphij	/* Needed as power up state of dev is "unknown" to system */
654296341Sdelphij	usbprn_pm_busy_component(usbprnp);
655296341Sdelphij	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
656296341Sdelphij
657296341Sdelphij	usbprn_restore_device_state(dip, usbprnp);
658296341Sdelphij
659296341Sdelphij	usbprn_pm_idle_component(usbprnp);
660296341Sdelphij
661296341Sdelphij	if (usbprnp->usbprn_ugen_hdl) {
662296341Sdelphij		(void) usb_ugen_attach(usbprnp->usbprn_ugen_hdl,
663296341Sdelphij		    DDI_RESUME);
664296341Sdelphij	}
665296341Sdelphij}
666296341Sdelphij
66759191Skris
668296341Sdelphij/*
669296341Sdelphij * usbprn_get_descriptors:
670296341Sdelphij *	Obtain all the descriptors for the device
671296341Sdelphij */
672296341Sdelphijstatic int
673296341Sdelphijusbprn_get_descriptors(usbprn_state_t *usbprnp)
674296341Sdelphij{
675296341Sdelphij	int			interface;
676296341Sdelphij	usb_client_dev_data_t	*dev_data =
677296341Sdelphij	    usbprnp->usbprn_dev_data;
678296341Sdelphij	usb_alt_if_data_t	*altif_data;
679296341Sdelphij	usb_cfg_data_t		*cfg_data;
680296341Sdelphij	usb_ep_data_t		*ep_data;
681296341Sdelphij	dev_info_t		*dip = usbprnp->usbprn_dip;
682296341Sdelphij	int			alt, rval;
683296341Sdelphij
684296341Sdelphij	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
685296341Sdelphij
686296341Sdelphij	/*
687296341Sdelphij	 * Section 4.2.1 of the spec says the printer could have
688296341Sdelphij	 * multiple configurations.  This driver is just for one
689296341Sdelphij	 * configuration interface and one interface.
69055714Skris	 */
691160814Ssimon	interface = dev_data->dev_curr_if;
692296341Sdelphij	cfg_data = dev_data->dev_curr_cfg;
693296341Sdelphij
694296341Sdelphij	/* find alternate that supports BI/UNI protocol */
695296341Sdelphij	for (alt = 0; alt < cfg_data->cfg_if[interface].if_n_alt; alt++) {
696296341Sdelphij		altif_data = &cfg_data->cfg_if[interface].if_alt[alt];
697296341Sdelphij
698296341Sdelphij		if ((altif_data->altif_descr.bInterfaceProtocol ==
699296341Sdelphij		    USB_PROTO_PRINTER_UNI) ||
700296341Sdelphij		    (altif_data->altif_descr.bInterfaceProtocol ==
701296341Sdelphij		    USB_PROTO_PRINTER_BI)) {
702296341Sdelphij
703296341Sdelphij			break;
704296341Sdelphij		} else {
705296341Sdelphij			USB_DPRINTF_L3(PRINT_MASK_ATTA,
706296341Sdelphij			    usbprnp->usbprn_log_handle,
707296341Sdelphij			    "alternate %d not supported", alt);
708296341Sdelphij		}
709296341Sdelphij	}
710296341Sdelphij
711160814Ssimon	if (alt == cfg_data->cfg_if[interface].if_n_alt) {
712238405Sjkim		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
713296341Sdelphij		    "usbprn_get_descriptors: no alternate");
714296341Sdelphij
715296341Sdelphij		return (USB_FAILURE);
716238405Sjkim	}
717296341Sdelphij
718296341Sdelphij
719296341Sdelphij	if ((rval = usb_set_alt_if(dip, interface, alt, USB_FLAGS_SLEEP,
720296341Sdelphij	    NULL, NULL)) != USB_SUCCESS) {
721296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
722296341Sdelphij		    "usbprn_get_descriptors: set alternate failed (%d)",
723296341Sdelphij		    rval);
724238405Sjkim
725296341Sdelphij		return (rval);
726296341Sdelphij	}
727296341Sdelphij
728296341Sdelphij	usbprnp->usbprn_config_descr = cfg_data->cfg_descr;
729296341Sdelphij	usbprnp->usbprn_if_descr = altif_data->altif_descr;
730296341Sdelphij
731296341Sdelphij	/*
732296341Sdelphij	 * find the endpoint descriptors. There will be a bulk-out endpoint
733296341Sdelphij	 * and an optional bulk-in endpoint.
734238405Sjkim	 */
735296341Sdelphij	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, alt, 0,
736296341Sdelphij	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
737296341Sdelphij		usbprnp->usbprn_bulk_out.ps_ept_descr = ep_data->ep_descr;
738238405Sjkim	}
739296341Sdelphij	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, alt, 0,
740296341Sdelphij	    USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
741296341Sdelphij		usbprnp->usbprn_bulk_in.ps_ept_descr = ep_data->ep_descr;
74255714Skris	}
743296341Sdelphij
744296341Sdelphij	return (USB_SUCCESS);
745296341Sdelphij}
746296341Sdelphij
747296341Sdelphij
748296341Sdelphij/*
749296341Sdelphij * usbprn_get_device_id:
750296341Sdelphij *	Get the device id as described in 4.2.1 of the specification
751296341Sdelphij *	Lexmark printer returns 2 bytes when asked for 8 bytes
75255714Skris *	We are ignoring data over and underrun.
753296341Sdelphij *	This is a synchronous function
754296341Sdelphij */
755296341Sdelphijstatic int
756296341Sdelphijusbprn_get_device_id(usbprn_state_t *usbprnp)
757280268Sdelphij{
758296341Sdelphij	int			len, n;
759296341Sdelphij	mblk_t			*data = NULL;
760296341Sdelphij	usb_cr_t		completion_reason;
761296341Sdelphij	usb_cb_flags_t		cb_flags;
762280268Sdelphij	int			rval = USB_FAILURE;
763296341Sdelphij	usb_ctrl_setup_t setup = {
764296341Sdelphij	    USB_DEV_REQ_DEV_TO_HOST |	/* bmRequestType */
765296341Sdelphij	    USB_DEV_REQ_TYPE_CLASS |
76655714Skris	    USB_DEV_REQ_RCPT_IF,
767296341Sdelphij	    USB_PRINTER_GET_DEVICE_ID,	/* bRequest */
768296341Sdelphij	    0,				/* wValue: fill in later */
769296341Sdelphij	    0,				/* wIndex: fill in later  */
770296341Sdelphij	    0,				/* wLength: fill in later */
771296341Sdelphij	    0				/* attributes */
772296341Sdelphij	    };
773296341Sdelphij	void			*ptr;
774296341Sdelphij
775296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
776296341Sdelphij	    "usbprn_get_device_id: Begin");
777296341Sdelphij
778296341Sdelphij	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
779296341Sdelphij
780296341Sdelphij	setup.wIndex = (usbprnp->usbprn_if_descr.bInterfaceNumber << 0x8) |
781296341Sdelphij	    (usbprnp->usbprn_if_descr.bAlternateSetting);
782296341Sdelphij	setup.wLength = USBPRN_MAX_DEVICE_ID_LENGTH;
783296341Sdelphij	setup.wValue = usbprnp->usbprn_config_descr.iConfiguration;
784296341Sdelphij
785296341Sdelphij	/*
786296341Sdelphij	 * This is always a sync request as this will never
787296341Sdelphij	 * be called in interrupt context.
788296341Sdelphij	 * First get the first two bytes that gives the length
789296341Sdelphij	 * of the device id string; then get the whole string
790296341Sdelphij	 */
791296341Sdelphij	if (usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph, &setup,
792296341Sdelphij	    &data, &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
793296341Sdelphij
794296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
795296341Sdelphij		    "usbprn_get_device_id: First sync command failed, cr=%d ",
796296341Sdelphij		    completion_reason);
797296341Sdelphij
798296341Sdelphij		/*
799296341Sdelphij		 * some devices return more than requested. as long as
800296341Sdelphij		 * we get the first two bytes, we can continue
801296341Sdelphij		 */
802296341Sdelphij		if (((completion_reason != USB_CR_DATA_OVERRUN) &&
803296341Sdelphij		    (completion_reason != USB_CR_DATA_UNDERRUN)) ||
804296341Sdelphij		    (data == NULL)) {
805296341Sdelphij
806160814Ssimon			goto done;
807296341Sdelphij		}
808296341Sdelphij	}
809296341Sdelphij
810296341Sdelphij	ASSERT(data);
811296341Sdelphij	n = MBLKL(data);
812296341Sdelphij
813296341Sdelphij	if (n < 2) {
814296341Sdelphij
815296341Sdelphij		goto done;
816160814Ssimon	}
817296341Sdelphij
818296341Sdelphij	len = (((*data->b_rptr) << 0x8) | (*(data->b_rptr+1)));
819296341Sdelphij
820296341Sdelphij	/*
82155714Skris	 * Std 1284-1994, chapter 7.6:
822296341Sdelphij	 *	Length values of x'0000', x'0001' and x'0002' are reserved
823296341Sdelphij	 */
824296341Sdelphij	if (len < 3) {
825296341Sdelphij
826296341Sdelphij		goto done;
82755714Skris	}
828296341Sdelphij
82955714Skris	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
830296341Sdelphij	    "usbprn_get_device_id: device id length=%d", len);
831160814Ssimon
832296341Sdelphij	/* did we get enough data */
833160814Ssimon	if (len > n) {
834296341Sdelphij		freemsg(data);
835296341Sdelphij		data = NULL;
836160814Ssimon
837296341Sdelphij		setup.wLength = (uint16_t)len;
838296341Sdelphij		if ((rval = usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph,
839296341Sdelphij		    &setup, &data, &completion_reason, &cb_flags, 0)) !=
840296341Sdelphij		    USB_SUCCESS) {
841296341Sdelphij			USB_DPRINTF_L2(PRINT_MASK_ATTA,
84255714Skris			    usbprnp->usbprn_log_handle,
843296341Sdelphij			    "usbprn_get_device_id: 2nd command failed "
84455714Skris			    "cr=%d cb_flags=0x%x",
845296341Sdelphij			    completion_reason, cb_flags);
846296341Sdelphij
847296341Sdelphij			goto done;
848296341Sdelphij		}
849296341Sdelphij
850296341Sdelphij		ASSERT(len == MBLKL(data));
851296341Sdelphij	}
852296341Sdelphij
853296341Sdelphij	USB_DPRINTF_L3(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
854296341Sdelphij	    "usbprn_get_device_id: returned data length=%ld",
855296341Sdelphij	    (long)(MBLKL(data)));
856296341Sdelphij
857296341Sdelphij	ptr = kmem_zalloc(len + 1, KM_SLEEP);
858296341Sdelphij
85955714Skris	mutex_enter(&usbprnp->usbprn_mutex);
860296341Sdelphij	usbprnp->usbprn_device_id_len = len;
861296341Sdelphij	usbprnp->usbprn_device_id = ptr;
862296341Sdelphij
863296341Sdelphij	bcopy(data->b_rptr, usbprnp->usbprn_device_id,
864296341Sdelphij	    usbprnp->usbprn_device_id_len);
865296341Sdelphij	usbprnp->usbprn_device_id[usbprnp->usbprn_device_id_len] = '\0';
866296341Sdelphij
867296341Sdelphij	/* Length is in the first two bytes, dump string in logbuf */
868296341Sdelphij	usbprn_print_long(usbprnp, usbprnp->usbprn_device_id + 2,
869296341Sdelphij	    usbprnp->usbprn_device_id_len - 2);
870296341Sdelphij	mutex_exit(&usbprnp->usbprn_mutex);
871296341Sdelphij
872296341Sdelphij	rval = USB_SUCCESS;
873296341Sdelphijdone:
874296341Sdelphij	freemsg(data);
875296341Sdelphij
876296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
87755714Skris	    "usbprn_get_device_id: rval=%d", rval);
878296341Sdelphij
879296341Sdelphij	return (rval);
880296341Sdelphij}
881296341Sdelphij
882296341Sdelphij
883296341Sdelphij/*
884296341Sdelphij * usbprn_get_port_status:
885296341Sdelphij *	Get the port status.
886296341Sdelphij *	This is a synchronous function
887296341Sdelphij */
888296341Sdelphijstatic int
889296341Sdelphijusbprn_get_port_status(usbprn_state_t  *usbprnp)
890296341Sdelphij{
891296341Sdelphij	mblk_t			*data = NULL;
892296341Sdelphij	usb_cr_t		completion_reason;
893296341Sdelphij	usb_cb_flags_t		cb_flags;
894296341Sdelphij	usb_ctrl_setup_t setup = {
895296341Sdelphij	    USB_DEV_REQ_DEV_TO_HOST |	/* bmRequestType */
896296341Sdelphij	    USB_DEV_REQ_TYPE_CLASS |
897296341Sdelphij	    USB_DEV_REQ_RCPT_IF,
898296341Sdelphij	    USB_PRINTER_GET_PORT_STATUS, /* bRequest */
899296341Sdelphij	    0,				/* wValue */
900296341Sdelphij	    0,				/* wIndex: fill in later  */
901296341Sdelphij	    1,				/* wLength */
902296341Sdelphij	    0				/* attributes */
903296341Sdelphij	    };
904296341Sdelphij	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
905296341Sdelphij
906296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
907296341Sdelphij	    "usbprn_get_port_status: Begin");
90855714Skris
909238405Sjkim	setup.wIndex = usbprnp->usbprn_if_descr.bInterfaceNumber;
910296341Sdelphij	if (usb_pipe_ctrl_xfer_wait(usbprnp->usbprn_def_ph,
911296341Sdelphij	    &setup, &data, &completion_reason, &cb_flags, 0) !=
912296341Sdelphij	    USB_SUCCESS) {
913296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
914296341Sdelphij		    "usbprn_get_port_status: Sync command failed "
915296341Sdelphij		    "cr=%d cb_flags=0x%x", completion_reason, cb_flags);
916296341Sdelphij
917238405Sjkim		freemsg(data);
918296341Sdelphij
919296341Sdelphij		return (USB_FAILURE);
920296341Sdelphij	} else {
921238405Sjkim		mutex_enter(&usbprnp->usbprn_mutex);
922296341Sdelphij
923296341Sdelphij		ASSERT(data);
924296341Sdelphij		ASSERT(MBLKL(data) == 1);
925238405Sjkim
926296341Sdelphij		usbprnp->usbprn_last_status = *data->b_rptr;
927296341Sdelphij
928296341Sdelphij		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
929296341Sdelphij		    "usbprn_get_port_status(sync): status=0x%x",
930296341Sdelphij		    usbprnp->usbprn_last_status);
931238405Sjkim
932296341Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
933296341Sdelphij		freemsg(data);
934296341Sdelphij
935296341Sdelphij		return (USB_SUCCESS);
936296341Sdelphij	}
937296341Sdelphij}
938296341Sdelphij
939296341Sdelphij
940296341Sdelphij/*
941296341Sdelphij * usbprn_open:
942296341Sdelphij *	Open the pipes
943296341Sdelphij */
944296341Sdelphij/*ARGSUSED*/
945296341Sdelphijstatic int
946296341Sdelphijusbprn_open(dev_t *devp, int flag, int sflag, cred_t *credp)
947238405Sjkim{
948296341Sdelphij	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
949296341Sdelphij	    USBPRN_MINOR_TO_INSTANCE(getminor(*devp)));
950296341Sdelphij	int rval = 0;
951296341Sdelphij
952296341Sdelphij	if (usbprnp == NULL) {
953238405Sjkim
954296341Sdelphij		return (ENXIO);
955238405Sjkim	}
956296341Sdelphij
957238405Sjkim	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
958296341Sdelphij	    "usbprn_open:");
959238405Sjkim
960296341Sdelphij	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
961296341Sdelphij
962296341Sdelphij	/* Fail open on a disconnected device */
963296341Sdelphij	mutex_enter(&usbprnp->usbprn_mutex);
964296341Sdelphij	if (usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED) {
965238405Sjkim		mutex_exit(&usbprnp->usbprn_mutex);
966296341Sdelphij		usb_release_access(usbprnp->usbprn_ser_acc);
967238405Sjkim
96855714Skris		return (ENODEV);
969296341Sdelphij	}
970296341Sdelphij
971296341Sdelphij	/* cannot happen? but just in case */
972296341Sdelphij	if (usbprnp->usbprn_dev_state == USB_DEV_SUSPENDED) {
973296341Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
974296341Sdelphij		usb_release_access(usbprnp->usbprn_ser_acc);
97555714Skris
976296341Sdelphij		return (EIO);
977296341Sdelphij	}
978296341Sdelphij
979296341Sdelphij	if (getminor(*devp) & USBPRN_MINOR_UGEN_BITS_MASK) {
980280268Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
981296341Sdelphij
982296341Sdelphij		rval = usb_ugen_open(usbprnp->usbprn_ugen_hdl,
983296341Sdelphij		    devp, flag, sflag, credp);
984296341Sdelphij
985280268Sdelphij		usb_release_access(usbprnp->usbprn_ser_acc);
986296341Sdelphij
987296341Sdelphij		return (rval);
988296341Sdelphij	}
989296341Sdelphij
990296341Sdelphij	/* Exit if this instance is already open */
991296341Sdelphij	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
992296341Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
993296341Sdelphij		usb_release_access(usbprnp->usbprn_ser_acc);
994296341Sdelphij
995296341Sdelphij		return (EBUSY);
99655714Skris	}
997296341Sdelphij	mutex_exit(&usbprnp->usbprn_mutex);
99855714Skris
999296341Sdelphij	/* raise power */
1000296341Sdelphij	usbprn_pm_busy_component(usbprnp);
1001296341Sdelphij	(void) pm_raise_power(usbprnp->usbprn_dip,
1002296341Sdelphij	    0, USB_DEV_OS_FULL_PWR);
1003296341Sdelphij	/* initialize some softstate data */
1004296341Sdelphij	mutex_enter(&usbprnp->usbprn_mutex);
100555714Skris	usbprnp->usbprn_prn_timeouts.tmo_forward =
1006296341Sdelphij	    usbprnp->usbprn_setparms.write_timeout;
1007296341Sdelphij	usbprnp->usbprn_prn_timeouts.tmo_reverse = 0;
1008296341Sdelphij	mutex_exit(&usbprnp->usbprn_mutex);
1009296341Sdelphij
1010296341Sdelphij	if (usbprn_open_usb_pipes(usbprnp) != USB_SUCCESS) {
1011296341Sdelphij
1012296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
1013296341Sdelphij		    "usbprn_open: pipe open failed");
1014296341Sdelphij
1015296341Sdelphij		usb_release_access(usbprnp->usbprn_ser_acc);
1016296341Sdelphij		usbprn_pm_idle_component(usbprnp);
1017296341Sdelphij
1018296341Sdelphij		return (EIO);
101955714Skris	}
1020296341Sdelphij
1021296341Sdelphij	mutex_enter(&usbprnp->usbprn_mutex);
1022296341Sdelphij	usbprnp->usbprn_flags |= USBPRN_OPEN;
1023296341Sdelphij
102455714Skris	/* set last status to online */
102555714Skris	usbprnp->usbprn_last_status &= ~USB_PRINTER_PORT_NO_SELECT;
1026296341Sdelphij	mutex_exit(&usbprnp->usbprn_mutex);
1027296341Sdelphij
1028296341Sdelphij	usb_release_access(usbprnp->usbprn_ser_acc);
1029296341Sdelphij
1030296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_OPEN, usbprnp->usbprn_log_handle,
1031296341Sdelphij	    "usbprn_open: End");
1032296341Sdelphij
1033296341Sdelphij	return (rval);
1034296341Sdelphij}
103555714Skris
1036296341Sdelphij
1037109998Smarkm/*
1038296341Sdelphij * usbprn_close:
1039296341Sdelphij *	Close the pipes
1040296341Sdelphij */
1041296341Sdelphij/*ARGSUSED*/
104255714Skrisstatic int
1043296341Sdelphijusbprn_close(dev_t dev, int flag, int otyp, cred_t *credp)
104455714Skris{
1045296341Sdelphij	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep,
1046296341Sdelphij	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
1047296341Sdelphij	int		rval = 0;
1048296341Sdelphij
1049296341Sdelphij	if (usbprnp == NULL) {
1050296341Sdelphij
1051296341Sdelphij		return (ENXIO);
1052296341Sdelphij	}
1053296341Sdelphij
1054296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbprnp->usbprn_log_handle,
1055296341Sdelphij	    "usbprn_close:");
1056296341Sdelphij
1057296341Sdelphij	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
1058296341Sdelphij		rval = usb_ugen_close(usbprnp->usbprn_ugen_hdl,
1059296341Sdelphij		    dev, flag, otyp, credp);
1060296341Sdelphij
1061296341Sdelphij		return (rval);
1062296341Sdelphij	}
1063296341Sdelphij
1064296341Sdelphij	/* avoid races with connect/disconnect */
1065296341Sdelphij	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
1066296341Sdelphij	(void) usb_serialize_access(usbprnp->usbprn_dev_acc, USB_WAIT, 0);
1067296341Sdelphij
106855714Skris	/* Close all usb pipes */
1069296341Sdelphij	usbprn_close_usb_pipes(usbprnp);
1070296341Sdelphij
1071296341Sdelphij	/* prevent any accesses by setting flags to closed */
1072296341Sdelphij	mutex_enter(&usbprnp->usbprn_mutex);
1073296341Sdelphij	usbprnp->usbprn_flags &= ~USBPRN_OPEN;
1074296341Sdelphij	mutex_exit(&usbprnp->usbprn_mutex);
107555714Skris
1076296341Sdelphij	usb_release_access(usbprnp->usbprn_dev_acc);
1077296341Sdelphij	usb_release_access(usbprnp->usbprn_ser_acc);
1078296341Sdelphij
1079296341Sdelphij	usbprn_pm_idle_component(usbprnp);
1080296341Sdelphij
1081296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_CLOSE, usbprnp->usbprn_log_handle,
108255714Skris	    "usbprn_close: End");
1083296341Sdelphij
1084296341Sdelphij	return (rval);
1085296341Sdelphij}
1086296341Sdelphij
1087296341Sdelphij
1088296341Sdelphij/*
1089296341Sdelphij * usbprn_read:
1090296341Sdelphij *	Read entry point (TBD)
1091296341Sdelphij */
1092296341Sdelphij/* ARGSUSED */
109355714Skrisstatic int
1094296341Sdelphijusbprn_read(dev_t dev, struct uio *uiop, cred_t *credp)
1095296341Sdelphij{
1096296341Sdelphij	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1097296341Sdelphij	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
1098296341Sdelphij
1099296341Sdelphij	if (usbprnp == NULL) {
1100296341Sdelphij
1101296341Sdelphij		return (ENXIO);
1102296341Sdelphij	}
110355714Skris
1104296341Sdelphij	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
1105296341Sdelphij		int rval;
1106296341Sdelphij
1107296341Sdelphij		/* raise power */
110855714Skris		usbprn_pm_busy_component(usbprnp);
1109296341Sdelphij		(void) pm_raise_power(usbprnp->usbprn_dip,
1110296341Sdelphij		    0, USB_DEV_OS_FULL_PWR);
111155714Skris
1112296341Sdelphij		if (usb_serialize_access(usbprnp->usbprn_write_acc,
1113296341Sdelphij		    USB_WAIT_SIG, 0) == 0) {
1114296341Sdelphij			usbprn_pm_idle_component(usbprnp);
1115296341Sdelphij
1116296341Sdelphij			return (EINTR);
1117296341Sdelphij		}
1118296341Sdelphij
1119296341Sdelphij		rval = usb_ugen_read(usbprnp->usbprn_ugen_hdl, dev,
1120296341Sdelphij		    uiop, credp);
1121109998Smarkm
1122296341Sdelphij		usb_release_access(usbprnp->usbprn_write_acc);
1123296341Sdelphij
112455714Skris		usbprn_pm_idle_component(usbprnp);
1125296341Sdelphij
1126296341Sdelphij		return (rval);
1127296341Sdelphij	}
1128296341Sdelphij
1129296341Sdelphij	/* Do a bulk-in from the printer */
1130296341Sdelphij
113155714Skris	return (EIO);
1132296341Sdelphij}
1133296341Sdelphij
1134296341Sdelphij
1135296341Sdelphij/*
1136296341Sdelphij * usbprn_write:
1137296341Sdelphij *	Write to the printer
1138296341Sdelphij */
1139296341Sdelphij/* ARGSUSED2 */
1140296341Sdelphijstatic int
1141296341Sdelphijusbprn_write(dev_t dev, struct uio *uiop, cred_t *credp)
1142296341Sdelphij{
1143296341Sdelphij	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
114455714Skris	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
114555714Skris	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
1146296341Sdelphij	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
1147296341Sdelphij	int		rval;
1148296341Sdelphij
1149296341Sdelphij	if (usbprnp == NULL) {
115055714Skris
1151296341Sdelphij		return (ENXIO);
1152296341Sdelphij	}
1153296341Sdelphij
1154296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1155296341Sdelphij	    "usbprn_write: Begin usbprnp=0x%p ", (void *)usbprnp);
1156296341Sdelphij
1157296341Sdelphij	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
1158296341Sdelphij		/* raise power */
1159296341Sdelphij		usbprn_pm_busy_component(usbprnp);
1160296341Sdelphij		(void) pm_raise_power(usbprnp->usbprn_dip,
1161296341Sdelphij		    0, USB_DEV_OS_FULL_PWR);
1162296341Sdelphij
1163296341Sdelphij		if (usb_serialize_access(usbprnp->usbprn_write_acc,
1164296341Sdelphij		    USB_WAIT_SIG, 0) == 0) {
116555714Skris			usbprn_pm_idle_component(usbprnp);
116655714Skris
1167296341Sdelphij			return (EINTR);
1168296341Sdelphij		}
1169296341Sdelphij
117055714Skris		rval = usb_ugen_write(usbprnp->usbprn_ugen_hdl, dev,
117155714Skris		    uiop, credp);
1172296341Sdelphij
1173296341Sdelphij		usb_release_access(usbprnp->usbprn_write_acc);
1174296341Sdelphij
117555714Skris		usbprn_pm_idle_component(usbprnp);
117655714Skris
1177296341Sdelphij		return (rval);
1178296341Sdelphij	}
1179296341Sdelphij
1180296341Sdelphij	/*
118155714Skris	 * serialize writes
1182296341Sdelphij	 * we cannot use usbprn_ser_acc sync object at this point because
1183296341Sdelphij	 * that would block out the ioctls for the full duration of the write.
1184296341Sdelphij	 */
1185296341Sdelphij	if (usb_serialize_access(usbprnp->usbprn_write_acc,
1186296341Sdelphij	    USB_WAIT_SIG, 0) == 0) {
1187296341Sdelphij
1188296341Sdelphij		return (EINTR);
1189296341Sdelphij	}
1190296341Sdelphij
1191296341Sdelphij	/*
1192296341Sdelphij	 * Check the status of the pipe.  If it's not idle,
1193296341Sdelphij	 * then wait.
1194296341Sdelphij	 */
1195296341Sdelphij	mutex_enter(&usbprnp->usbprn_mutex);
119655714Skris
119755714Skris	/* if device is disconnected or pipes closed, fail immediately */
119855714Skris	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
1199296341Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
1200296341Sdelphij
1201296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1202296341Sdelphij		    "usbprn_write: device can't be accessed");
120355714Skris
120455714Skris		usb_release_access(usbprnp->usbprn_write_acc);
120555714Skris
1206296341Sdelphij		return (EIO);
1207296341Sdelphij	}
1208296341Sdelphij
120955714Skris	/* all pipes must be idle */
1210296341Sdelphij	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
1211296341Sdelphij	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
1212296341Sdelphij
1213296341Sdelphij	mutex_exit(&usbprnp->usbprn_mutex);
1214296341Sdelphij
1215296341Sdelphij	/*
1216296341Sdelphij	 * Call physio to do the transfer.  physio will
1217296341Sdelphij	 * call the strategy routine, and then call
1218296341Sdelphij	 * biowait() to block until the transfer completes.
1219296341Sdelphij	 */
1220296341Sdelphij	rval = physio(usbprn_strategy, (struct buf *)0, dev,
1221296341Sdelphij	    B_WRITE, usbprn_minphys, uiop);
1222296341Sdelphij
1223296341Sdelphij	usb_release_access(usbprnp->usbprn_write_acc);
122455714Skris
1225296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1226296341Sdelphij	    "usbprn_write: End");
1227296341Sdelphij
1228296341Sdelphij	return (rval);
122955714Skris}
1230296341Sdelphij
1231296341Sdelphij
1232296341Sdelphij/*
1233296341Sdelphij * usbprn_poll
1234296341Sdelphij */
1235296341Sdelphijstatic int
1236296341Sdelphijusbprn_poll(dev_t dev, short events,
1237296341Sdelphij    int anyyet,  short *reventsp, struct pollhead **phpp)
1238296341Sdelphij{
1239296341Sdelphij	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1240296341Sdelphij	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
1241296341Sdelphij
1242296341Sdelphij	if (usbprnp == NULL) {
1243296341Sdelphij
124455714Skris		return (ENXIO);
124555714Skris	}
1246296341Sdelphij
1247296341Sdelphij	if (getminor(dev) & USBPRN_MINOR_UGEN_BITS_MASK) {
1248296341Sdelphij		return (usb_ugen_poll(usbprnp->usbprn_ugen_hdl, dev, events,
1249296341Sdelphij		    anyyet, reventsp, phpp));
125055714Skris	}
125155714Skris
1252296341Sdelphij	return (ENXIO);
1253296341Sdelphij}
1254296341Sdelphij
1255296341Sdelphij
125655714Skris/*
125755714Skris * usbprn_strategy:
1258296341Sdelphij *	service a request to the device.
1259296341Sdelphij */
1260296341Sdelphijstatic int
126155714Skrisusbprn_strategy(struct buf *bp)
1262296341Sdelphij{
1263296341Sdelphij	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1264296341Sdelphij	    USBPRN_MINOR_TO_INSTANCE(getminor(bp->b_edev)));
1265296341Sdelphij	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
1266296341Sdelphij
1267296341Sdelphij	bp_mapin(bp);
1268296341Sdelphij
1269296341Sdelphij	/*
1270296341Sdelphij	 * serialize to avoid races
1271296341Sdelphij	 * access is released in usbprn_biodone()
1272296341Sdelphij	 */
1273296341Sdelphij	(void) usb_serialize_access(usbprnp->usbprn_dev_acc, USB_WAIT, 0);
1274296341Sdelphij
127555714Skris	mutex_enter(&usbprnp->usbprn_mutex);
1276296341Sdelphij	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
1277296341Sdelphij		usbprn_biodone(usbprnp, EIO, 0);
1278296341Sdelphij		mutex_exit(&usbprnp->usbprn_mutex);
1279296341Sdelphij
1280296341Sdelphij		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1281296341Sdelphij		    "usbprn_strategy: device can't be accessed");
1282296341Sdelphij
1283296341Sdelphij		return (0);
1284296341Sdelphij	}
1285296341Sdelphij
1286296341Sdelphij	bulk_out->ps_flags = USBPRN_PS_NEED_TO_XFER;
1287296341Sdelphij
1288296341Sdelphij	ASSERT(usbprnp->usbprn_bp == NULL);
1289296341Sdelphij	usbprnp->usbprn_bp = bp;
1290296341Sdelphij
1291296341Sdelphij	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1292296341Sdelphij	    "usbprn_strategy: usbprnp=0x%p bp=0x%p count=%lu",
1293296341Sdelphij	    (void *)usbprnp, (void *)bp, bp->b_bcount);
1294296341Sdelphij
1295	ASSERT(usbprnp->usbprn_bulk_mp == NULL);
1296
1297	usbprnp->usbprn_bulk_mp = allocb(bp->b_bcount, BPRI_HI);
1298
1299	if (usbprnp->usbprn_bulk_mp == NULL) {
1300		bulk_out->ps_flags = USBPRN_PS_IDLE;
1301		usbprn_biodone(usbprnp, EIO, 0);
1302		mutex_exit(&usbprnp->usbprn_mutex);
1303
1304		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1305		    "usbprn_strategy: allocb failed");
1306
1307		return (0);
1308	}
1309
1310	bcopy((caddr_t)bp->b_un.b_addr,
1311	    usbprnp->usbprn_bulk_mp->b_datap->db_base, bp->b_bcount);
1312	usbprnp->usbprn_bulk_mp->b_wptr += bp->b_bcount;
1313	mutex_exit(&usbprnp->usbprn_mutex);
1314
1315	usbprn_send_async_bulk_data(usbprnp);
1316
1317	return (0);
1318}
1319
1320
1321/*
1322 * usbprn_ioctl:
1323 *	handle the ioctl
1324 */
1325/*ARGSUSED4*/
1326static int
1327usbprn_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
1328		cred_t *credp, int *rvalp)
1329{
1330	int		err = 0;
1331	usbprn_state_t	*usbprnp = ddi_get_soft_state(usbprn_statep,
1332	    USBPRN_MINOR_TO_INSTANCE(getminor(dev)));
1333	struct ecpp_device_id	usbprn_devid;
1334	int		len;
1335
1336	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1337	    "usbprn_ioctl: Begin ");
1338
1339	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
1340	mutex_enter(&usbprnp->usbprn_mutex);
1341
1342	/*
1343	 * only for PRNIOC_GET_STATUS cmd:
1344	 * if device is disconnected or pipes closed, fail immediately
1345	 */
1346	if ((cmd == PRNIOC_GET_STATUS) &&
1347	    !(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
1348		mutex_exit(&usbprnp->usbprn_mutex);
1349
1350		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1351		    "usbprn_write: device can't be accessed");
1352
1353		usb_release_access(usbprnp->usbprn_ser_acc);
1354
1355		return (EIO);
1356	}
1357	mutex_exit(&usbprnp->usbprn_mutex);
1358
1359	switch (cmd) {
1360	case ECPPIOC_GETDEVID:
1361		/*
1362		 * With genericized ioctls this interface should change.
1363		 * We ignore the mode in USB printer driver because
1364		 * it need not be in nibble mode in usb driver unlike
1365		 * ecpp to retrieve the device id string. Also we do
1366		 * not expect the application to call this twice since
1367		 * it doesn't change since attach time and we take care
1368		 * of calling it twice: once for getting the length and
1369		 * once for getting the actual device id string. So we
1370		 * set both the lengths to actual device id string length.
1371		 * Ref: PSARC/2000/018
1372		 */
1373		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1374		    "usbprn_ioctl: ECPPIOC_GETDEVID(0x%x)", cmd);
1375
1376		bzero(&usbprn_devid, sizeof (usbprn_devid));
1377
1378		ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
1379#ifdef _MULTI_DATAMODEL
1380		switch (ddi_model_convert_from(flag & FMODELS)) {
1381		case DDI_MODEL_ILP32: {
1382			struct ecpp_device_id32	usbprn_devid32;
1383
1384			if (ddi_copyin((caddr_t)arg, &usbprn_devid32,
1385			    sizeof (struct ecpp_device_id32), flag)) {
1386				err = EFAULT;
1387
1388				break;
1389			}
1390
1391			if (usbprnp->usbprn_device_id == NULL) {
1392				err = EIO;
1393
1394				break;
1395			}
1396			ASSERT(usbprnp->usbprn_device_id_len > 2);
1397
1398			usbprn_devid32.rlen = usbprnp->usbprn_device_id_len - 2;
1399			len = min(usbprn_devid32.len, usbprn_devid32.rlen);
1400
1401			if (ddi_copyout(usbprnp->usbprn_device_id + 2,
1402			    (caddr_t)(uintptr_t)usbprn_devid32.addr,
1403			    len, flag)) {
1404				err = EFAULT;
1405
1406				break;
1407			}
1408
1409			if (ddi_copyout(&usbprn_devid32, (caddr_t)arg,
1410			    sizeof (struct ecpp_device_id32), flag)) {
1411				err = EFAULT;
1412
1413				break;
1414			}
1415
1416			break;
1417		}
1418		case DDI_MODEL_NONE:
1419			if (ddi_copyin((caddr_t)arg, &usbprn_devid,
1420			    sizeof (struct ecpp_device_id), flag)) {
1421				err = EFAULT;
1422
1423				break;
1424			}
1425
1426			if (usbprnp->usbprn_device_id == NULL) {
1427				err = EIO;
1428
1429				break;
1430			}
1431			ASSERT(usbprnp->usbprn_device_id_len > 2);
1432
1433			usbprn_devid.rlen = usbprnp->usbprn_device_id_len - 2;
1434			len = min(usbprn_devid.len, usbprn_devid.rlen);
1435
1436			if (ddi_copyout(usbprnp->usbprn_device_id + 2,
1437			    usbprn_devid.addr, len, flag)) {
1438				err = EFAULT;
1439
1440				break;
1441			}
1442
1443			if (ddi_copyout(&usbprn_devid, (caddr_t)arg,
1444			    sizeof (struct ecpp_device_id), flag)) {
1445				err = EFAULT;
1446
1447				break;
1448			}
1449
1450			break;
1451		}
1452
1453		break;
1454#else
1455		if (ddi_copyin((caddr_t)arg, &usbprn_devid,
1456		    sizeof (struct ecpp_device_id), flag)) {
1457			err = EFAULT;
1458
1459			break;
1460		}
1461
1462
1463		if (usbprnp->usbprn_device_id == NULL) {
1464			err = EIO;
1465
1466			break;
1467		}
1468		ASSERT(usbprnp->usbprn_device_id_len > 2);
1469
1470		usbprn_devid.rlen = usbprnp->usbprn_device_id_len - 2;
1471		len = min(usbprn_devid.len, usbprn_devid.rlen);
1472
1473		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
1474		    usbprn_devid.addr, len, flag)) {
1475			err = EFAULT;
1476
1477			break;
1478		}
1479
1480		if (ddi_copyout(&usbprn_devid, (caddr_t)arg,
1481		    sizeof (struct ecpp_device_id), flag)) {
1482			err = EFAULT;
1483
1484			break;
1485		}
1486
1487		break;
1488#endif
1489	case ECPPIOC_SETPARMS:
1490		err = usbprn_setparms(usbprnp, arg, flag);
1491
1492		break;
1493	case ECPPIOC_GETPARMS:
1494		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1495		    "usbprn_ioctl: ECPPIOC_GETPARMS(0x%x)", cmd);
1496
1497		/* Get the parameters */
1498		err = usbprn_getparms(usbprnp, arg, flag);
1499
1500		break;
1501	case BPPIOC_GETERR:
1502		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1503		    "usbprn_ioctl: ECPPIOC_GETERR(0x%x)", cmd);
1504
1505		/* Get the error state */
1506		usbprn_geterr(usbprnp, arg, flag);
1507
1508		break;
1509	case BPPIOC_TESTIO:
1510		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1511		    "usbprn_ioctl: BPPIOC_TESTIO(0x%x)",  cmd);
1512
1513		/* Get the port status */
1514		err = usbprn_testio(usbprnp, flag);
1515
1516		break;
1517	case PRNIOC_GET_IFCAP:
1518		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1519		    "usbprn_ioctl : PRNIOC_GET_IFCAP(0x%x)",  cmd);
1520
1521		/* get interface capabilities */
1522		err = usbprn_prnio_get_ifcap(usbprnp, arg, flag);
1523
1524		break;
1525	case PRNIOC_SET_IFCAP:
1526		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1527		    "usbprn_ioctl : PRNIOC_SET_IFCAP(0x%x)",  cmd);
1528
1529		/* get interface capabilities */
1530		err = usbprn_prnio_set_ifcap(usbprnp, arg, flag);
1531
1532		break;
1533	case PRNIOC_GET_IFINFO:
1534		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1535		    "usbprn_ioctl : PRNIOC_GET_IFINFO(0x%x)",  cmd);
1536
1537		/* get interface information */
1538		err = usbprn_prnio_get_ifinfo(usbprnp, arg, flag);
1539
1540		break;
1541	case PRNIOC_GET_STATUS:
1542		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1543		    "usbprn_ioctl : PRNIOC_GET_STATUS(0x%x)",  cmd);
1544
1545		/* get prnio status */
1546		err = usbprn_prnio_get_status(usbprnp, arg, flag);
1547
1548		break;
1549	case PRNIOC_GET_1284_DEVID:
1550		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1551		    "usbprn_ioctl : PRNIOC_GET_1284_DEVID(0x%x)",  cmd);
1552
1553		/* get device ID */
1554		err = usbprn_prnio_get_1284_devid(usbprnp, arg, flag);
1555
1556		break;
1557	case PRNIOC_GET_1284_STATUS:
1558		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1559		    "usbprn_ioctl : PRNIOC_GET_1284_STATUS(0x%x)",  cmd);
1560
1561		/* get prnio status */
1562		err = usbprn_prnio_get_1284_status(usbprnp, arg, flag);
1563
1564		break;
1565	case PRNIOC_GET_TIMEOUTS:
1566		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1567		    "usbprn_ioctl : PRNIOC_GET_TIMEOUTS(0x%x)", cmd);
1568
1569		/* Get the parameters */
1570		err = usbprn_prnio_get_timeouts(usbprnp, arg, flag);
1571
1572		break;
1573	case PRNIOC_SET_TIMEOUTS:
1574		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1575		    "usbprn_ioctl : PRNIOC_SET_TIMEOUTS(0x%x)", cmd);
1576
1577		/* Get the parameters */
1578		err = usbprn_prnio_set_timeouts(usbprnp, arg, flag);
1579
1580		break;
1581	case PRNIOC_RESET:
1582		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1583		    "usbprn_ioctl : PRNIOC_RESET(0x%x)",  cmd);
1584
1585		/* nothing */
1586		err = 0;
1587
1588		break;
1589	default:
1590		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1591		    "usbprn_ioctl: unknown(0x%x)", cmd);
1592		err = EINVAL;
1593	}
1594
1595	usb_release_access(usbprnp->usbprn_ser_acc);
1596
1597	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1598	    "usbprn_ioctl: End ");
1599
1600	return (err);
1601}
1602
1603
1604/*
1605 * breakup by physio
1606 */
1607static void
1608usbprn_minphys(struct buf *bp)
1609{
1610	usbprn_state_t *usbprnp = ddi_get_soft_state(usbprn_statep,
1611	    USBPRN_MINOR_TO_INSTANCE(getminor(bp->b_edev)));
1612
1613	mutex_enter(&usbprnp->usbprn_mutex);
1614	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1615	    "usbprn_minphys: bcount=%lu", bp->b_bcount);
1616
1617	if (bp->b_bcount > usbprnp->usbprn_max_bulk_xfer_size) {
1618		bp->b_bcount = min(usbprn_max_xfer_size,
1619		    usbprnp->usbprn_max_bulk_xfer_size);
1620	} else {
1621		bp->b_bcount = min(usbprn_max_xfer_size, bp->b_bcount);
1622	}
1623	mutex_exit(&usbprnp->usbprn_mutex);
1624}
1625
1626
1627/*
1628 * usbprn_open_usb_pipes:
1629 *	Open all pipes on the device
1630 */
1631static int
1632usbprn_open_usb_pipes(usbprn_state_t *usbprnp)
1633{
1634	usb_pipe_policy_t *policy;
1635	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
1636	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
1637
1638	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1639	    "usbprn_open_usb_pipes:");
1640
1641	/*
1642	 * Intitialize the pipe policy for the bulk out pipe
1643	 */
1644	mutex_enter(&usbprnp->usbprn_mutex);
1645	policy = &(bulk_out->ps_policy);
1646	policy->pp_max_async_reqs = 1;
1647	mutex_exit(&usbprnp->usbprn_mutex);
1648
1649	/* Open bulk_out pipe */
1650	if (usb_pipe_open(usbprnp->usbprn_dip, &bulk_out->ps_ept_descr,
1651	    policy, USB_FLAGS_SLEEP, &bulk_out->ps_handle) != USB_SUCCESS) {
1652
1653		return (USB_FAILURE);
1654	}
1655
1656#ifdef LATER
1657	mutex_enter(&usbprnp->usbprn_mutex);
1658	/* Open the bulk in pipe if one exists */
1659	if (bulk_in->ps_ept_descr->bLength) {
1660		/*
1661		 * Initialize the pipe policy for the Bulk In pipe
1662		 */
1663		policy = &bulk_in->ps_policy;
1664		bulk_in->ps_flags = USBPRN_PS_IDLE;
1665		policy->pp_max_async_reqs = 1;
1666		mutex_exit(&usbprnp->usbprn_mutex);
1667
1668		/* Open bulk_in pipe */
1669		if (usb_pipe_open(usbprnp->usbprn_dip, bulk_in->ps_ept_descr,
1670		    policy, USB_FLAGS_SLEEP, &bulk_in->ps_handle) !=
1671		    USB_SUCCESS) {
1672
1673			return (USB_FAILURE);
1674		}
1675	} else {
1676		mutex_exit(&usbprnp->usbprn_mutex);
1677	}
1678#else
1679	mutex_enter(&usbprnp->usbprn_mutex);
1680	bulk_in->ps_flags = USBPRN_PS_IDLE;
1681	mutex_exit(&usbprnp->usbprn_mutex);
1682#endif
1683
1684	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1685	    "usbprn_open_usb_pipes: success");
1686
1687	return (USB_SUCCESS);
1688}
1689
1690
1691/*
1692 * usbprn_close_usb_pipes:
1693 *	Close the default/bulk in/out pipes synchronously
1694 */
1695static void
1696usbprn_close_usb_pipes(usbprn_state_t *usbprnp)
1697{
1698	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
1699	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
1700
1701	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1702	    "usbprn_close_usb_pipes:");
1703#ifdef DEBUG
1704	mutex_enter(&usbprnp->usbprn_mutex);
1705	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
1706	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
1707	mutex_exit(&usbprnp->usbprn_mutex);
1708#endif
1709
1710	/*
1711	 * close the pipe, if another thread is already closing the
1712	 * pipe, we get USB_INVALID_PIPE
1713	 */
1714	if (bulk_out->ps_handle) {
1715
1716		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1717		    "usbprn_close_usb_pipes: Closing bulk out pipe");
1718
1719		usb_pipe_close(usbprnp->usbprn_dip, bulk_out->ps_handle,
1720		    USB_FLAGS_SLEEP, NULL, NULL);
1721		bulk_out->ps_handle = NULL;
1722	}
1723	if (bulk_in->ps_handle) {
1724
1725		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1726		    "usbprn_close_usb_pipes: Closing bulk in pipe");
1727
1728		usb_pipe_close(usbprnp->usbprn_dip, bulk_in->ps_handle,
1729		    USB_FLAGS_SLEEP, NULL, NULL);
1730		bulk_in->ps_handle = NULL;
1731	}
1732}
1733
1734
1735/*
1736 * usbprn_getparms:
1737 *	Get the parameters for the device
1738 */
1739static int
1740usbprn_getparms(usbprn_state_t *usbprnp, intptr_t arg, int flag)
1741{
1742	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
1743
1744	if (ddi_copyout(&usbprnp->usbprn_setparms,
1745	    (caddr_t)arg, sizeof (struct ecpp_transfer_parms), flag)) {
1746
1747		return (EFAULT);
1748	}
1749
1750	return (0);
1751}
1752
1753
1754/*
1755 * usbprn_setparms:
1756 *	Set the parameters for the device
1757 */
1758static int
1759usbprn_setparms(usbprn_state_t *usbprnp, intptr_t arg, int flag)
1760{
1761	struct ecpp_transfer_parms xfer;
1762
1763	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
1764
1765	if (ddi_copyin((caddr_t)arg, &xfer,
1766	    sizeof (struct ecpp_transfer_parms), flag)) {
1767
1768		return (EFAULT);
1769	}
1770	if ((xfer.write_timeout < USBPRN_XFER_TIMEOUT_MIN) ||
1771	    (xfer.write_timeout > USBPRN_XFER_TIMEOUT_MAX)) {
1772
1773		return (EINVAL);
1774	}
1775	if (!((xfer.mode == ECPP_CENTRONICS) ||
1776	    (xfer.mode == ECPP_COMPAT_MODE) ||
1777	    (xfer.mode == ECPP_NIBBLE_MODE) ||
1778	    (xfer.mode == ECPP_ECP_MODE) ||
1779	    (xfer.mode == ECPP_DIAG_MODE))) {
1780
1781		return (EINVAL);
1782
1783	}
1784	if (xfer.mode != ECPP_CENTRONICS) {
1785
1786		return (EPROTONOSUPPORT);
1787	}
1788
1789	mutex_enter(&usbprnp->usbprn_mutex);
1790	usbprnp->usbprn_setparms = xfer;
1791	usbprnp->usbprn_prn_timeouts.tmo_forward = xfer.write_timeout;
1792	mutex_exit(&usbprnp->usbprn_mutex);
1793
1794	return (0);
1795}
1796
1797
1798/*
1799 * usbprn_geterr:
1800 *	Return the any device error state
1801 */
1802static void
1803usbprn_geterr(usbprn_state_t *usbprnp, intptr_t arg, int flag)
1804{
1805	struct bpp_error_status bpp_status;
1806
1807	bzero(&bpp_status, sizeof (bpp_status));
1808
1809	mutex_enter(&usbprnp->usbprn_mutex);
1810	bpp_status.bus_error = 0;
1811	bpp_status.timeout_occurred = 0;
1812	bpp_status.pin_status = usbprn_error_state(usbprnp->usbprn_last_status);
1813
1814	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1815	    "usbprn_geterr: status=0x%x", usbprnp->usbprn_last_status);
1816
1817	mutex_exit(&usbprnp->usbprn_mutex);
1818
1819	(void) ddi_copyout(&bpp_status,
1820	    (caddr_t)arg, sizeof (struct bpp_error_status), flag);
1821}
1822
1823
1824/*
1825 * usbprn_error_state:
1826 *	Map the driver error state to that of the application
1827 */
1828static char
1829usbprn_error_state(uchar_t status)
1830{
1831	uchar_t app_err_status = 0;
1832
1833	if (!(status & USB_PRINTER_PORT_NO_ERROR)) {
1834		app_err_status |= USB_PRINTER_ERR_ERR;
1835	}
1836	if (status & USB_PRINTER_PORT_EMPTY) {
1837		app_err_status |= USB_PRINTER_PE_ERR;
1838	}
1839	if (!(status & USB_PRINTER_PORT_NO_SELECT)) {
1840		app_err_status |= USB_PRINTER_SLCT_ERR;
1841	}
1842
1843	return (app_err_status);
1844}
1845
1846
1847static int
1848usbprn_ioctl_get_status(usbprn_state_t *usbprnp)
1849{
1850	/* Check the transfer mode */
1851	mutex_enter(&usbprnp->usbprn_mutex);
1852
1853	/* if device is disconnected or pipes closed, fail immediately */
1854	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
1855		mutex_exit(&usbprnp->usbprn_mutex);
1856
1857		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1858		    "usbprn_ioctl_get_status: device can't be accessed");
1859
1860		return (EIO);
1861	}
1862	mutex_exit(&usbprnp->usbprn_mutex);
1863
1864	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
1865
1866		return (EIO);
1867	}
1868
1869	return (0);
1870}
1871
1872
1873/*
1874 * usbprn_testio:
1875 *	Execute the ECPP_TESTIO ioctl
1876 */
1877/* ARGSUSED1 */
1878static int
1879usbprn_testio(usbprn_state_t *usbprnp, int flag)
1880{
1881	int	err;
1882
1883	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1884	    "usbprn_testio: begin");
1885
1886	if ((err = usbprn_ioctl_get_status(usbprnp)) != 0) {
1887
1888		return (err);
1889	}
1890
1891	/* There is an error.  Return it to the user */
1892	mutex_enter(&usbprnp->usbprn_mutex);
1893
1894	if (usbprn_error_state(usbprnp->usbprn_last_status) != 0) {
1895		mutex_exit(&usbprnp->usbprn_mutex);
1896
1897		return (EIO);
1898
1899	} else {
1900		mutex_exit(&usbprnp->usbprn_mutex);
1901
1902		return (0);
1903	}
1904}
1905
1906
1907/*
1908 * usbprn_prnio_get_status:
1909 *	Execute the PRNIOC_GET_STATUS ioctl
1910 */
1911static int
1912usbprn_prnio_get_status(usbprn_state_t *usbprnp, intptr_t arg, int flag)
1913{
1914	uint_t	prnio_status = 0;
1915	int	err;
1916
1917	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1918	    "usbprn_prnio_get_status: begin");
1919
1920	/* capture printer status */
1921	err = usbprn_ioctl_get_status(usbprnp);
1922
1923	mutex_enter(&usbprnp->usbprn_mutex);
1924
1925	if (usbprnp->usbprn_dev_state == USB_DEV_ONLINE) {
1926		prnio_status |= PRN_ONLINE;
1927	}
1928	if ((err == 0) &&
1929	    (usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR)) {
1930		prnio_status |= PRN_READY;
1931	}
1932
1933	mutex_exit(&usbprnp->usbprn_mutex);
1934
1935	if (ddi_copyout(&prnio_status,
1936	    (caddr_t)arg, sizeof (prnio_status), flag)) {
1937
1938		return (EFAULT);
1939	}
1940
1941	return (0);
1942}
1943
1944
1945/*
1946 * usbprn_prnio_get_1284_status:
1947 *	Execute the PRNIOC_GET_1284_STATUS ioctl
1948 */
1949static int
1950usbprn_prnio_get_1284_status(usbprn_state_t *usbprnp, intptr_t arg, int flag)
1951{
1952	uchar_t		status;
1953	int		err;
1954
1955	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
1956	    "usbprn_prnio_get_1284_status: begin");
1957
1958	if ((err = usbprn_ioctl_get_status(usbprnp)) != 0) {
1959
1960		return (err);
1961	}
1962
1963	/* status was captured successfully */
1964	mutex_enter(&usbprnp->usbprn_mutex);
1965
1966	status = usbprnp->usbprn_last_status & (USB_PRINTER_PORT_NO_ERROR |
1967	    USB_PRINTER_PORT_NO_SELECT | USB_PRINTER_PORT_EMPTY);
1968
1969	mutex_exit(&usbprnp->usbprn_mutex);
1970
1971	if (ddi_copyout(&status, (caddr_t)arg, sizeof (status), flag)) {
1972
1973		return (EFAULT);
1974	}
1975
1976	return (0);
1977}
1978
1979
1980/*
1981 * usbprn_prnio_get_ifcap:
1982 *	Execute the PRNIOC_GET_IFCAP ioctl
1983 */
1984/* ARGSUSED */
1985static int
1986usbprn_prnio_get_ifcap(usbprn_state_t *usbprnp, intptr_t arg, int flag)
1987{
1988	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
1989
1990	if (ddi_copyout(&usbprn_ifcap, (caddr_t)arg, sizeof (usbprn_ifcap),
1991	    flag)) {
1992
1993		return (EFAULT);
1994	}
1995
1996	return (0);
1997}
1998
1999
2000/*
2001 * usbprn_prnio_get_ifcap:
2002 *	Execute the PRNIOC_SET_IFCAP ioctl
2003 */
2004/* ARGSUSED */
2005static int
2006usbprn_prnio_set_ifcap(usbprn_state_t *usbprnp, intptr_t arg, int flag)
2007{
2008	uint_t	new_ifcap;
2009
2010	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
2011
2012	if (ddi_copyin((caddr_t)arg, &new_ifcap, sizeof (new_ifcap), flag)) {
2013
2014		return (EFAULT);
2015	}
2016
2017	/* no settable capabilities */
2018	if (usbprn_ifcap != new_ifcap) {
2019
2020		return (EINVAL);
2021	}
2022
2023	return (0);
2024}
2025
2026
2027/*
2028 * usbprn_prnio_get_ifinfo:
2029 *	Execute the PRNIOC_GET_IFINFO ioctl
2030 */
2031/* ARGSUSED */
2032static int
2033usbprn_prnio_get_ifinfo(usbprn_state_t *usbprnp, intptr_t arg, int flag)
2034{
2035	struct prn_interface_info	prn_info;
2036	int	rlen, len;
2037
2038	rlen = strlen(usbprn_prnio_ifinfo);
2039
2040#ifdef _MULTI_DATAMODEL
2041	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
2042
2043	switch (ddi_model_convert_from(flag & FMODELS)) {
2044	case DDI_MODEL_ILP32: {
2045		struct prn_interface_info32	prn_info32;
2046
2047		if (ddi_copyin((caddr_t)arg, &prn_info32,
2048		    sizeof (struct prn_interface_info32), flag)) {
2049
2050			return (EFAULT);
2051		}
2052
2053		prn_info32.if_rlen = rlen;
2054		len = min(rlen, prn_info32.if_len);
2055
2056		if (ddi_copyout(&usbprn_prnio_ifinfo[0],
2057		    (caddr_t)(uintptr_t)prn_info32.if_data, len, flag)) {
2058
2059			return (EFAULT);
2060		}
2061
2062		if (ddi_copyout(&prn_info32, (caddr_t)arg,
2063		    sizeof (struct prn_interface_info32), flag)) {
2064
2065			return (EFAULT);
2066		}
2067
2068		break;
2069	}
2070	case DDI_MODEL_NONE:
2071#endif /* _MULTI_DATAMODEL */
2072		ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
2073
2074		if (ddi_copyin((caddr_t)arg, &prn_info,
2075		    sizeof (struct prn_interface_info), flag)) {
2076
2077			return (EFAULT);
2078		}
2079
2080		prn_info.if_rlen = rlen;
2081		len = min(rlen, prn_info.if_len);
2082
2083		if (ddi_copyout(&usbprn_prnio_ifinfo[0],
2084		    prn_info.if_data, len, flag)) {
2085
2086			return (EFAULT);
2087		}
2088
2089		if (ddi_copyout(&prn_info, (caddr_t)arg,
2090		    sizeof (struct prn_interface_info), flag)) {
2091
2092			return (EFAULT);
2093		}
2094#ifdef _MULTI_DATAMODEL
2095
2096		break;
2097	}
2098#endif /* _MULTI_DATAMODEL */
2099
2100	return (0);
2101}
2102
2103
2104/*
2105 * usbprn_prnio_getdevid:
2106 *	Execute the PRNIOC_GET_1284_DEVID ioctl
2107 */
2108static int
2109usbprn_prnio_get_1284_devid(usbprn_state_t *usbprnp, intptr_t arg, int flag)
2110{
2111	struct prn_1284_device_id prn_devid;
2112	int	len;
2113
2114	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
2115
2116#ifdef _MULTI_DATAMODEL
2117	switch (ddi_model_convert_from(flag & FMODELS)) {
2118	case DDI_MODEL_ILP32: {
2119		struct prn_1284_device_id32	prn_devid32;
2120
2121		if (ddi_copyin((caddr_t)arg, &prn_devid32,
2122		    sizeof (struct prn_1284_device_id32), flag)) {
2123
2124			return (EFAULT);
2125		}
2126
2127		prn_devid32.id_rlen = usbprnp->usbprn_device_id_len - 2;
2128		len = min(prn_devid32.id_rlen, prn_devid32.id_len);
2129
2130		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
2131		    (caddr_t)(uintptr_t)prn_devid32.id_data, len, flag)) {
2132
2133			return (EFAULT);
2134		}
2135
2136		if (ddi_copyout(&prn_devid32, (caddr_t)arg,
2137		    sizeof (struct prn_1284_device_id32), flag)) {
2138
2139			return (EFAULT);
2140		}
2141
2142		break;
2143	}
2144	case DDI_MODEL_NONE:
2145#endif /* _MULTI_DATAMODEL */
2146		if (ddi_copyin((caddr_t)arg, &prn_devid,
2147		    sizeof (struct prn_1284_device_id), flag)) {
2148
2149			return (EFAULT);
2150		}
2151
2152		prn_devid.id_rlen = usbprnp->usbprn_device_id_len - 2;
2153		len = min(prn_devid.id_rlen, prn_devid.id_len);
2154
2155		if (ddi_copyout(usbprnp->usbprn_device_id + 2,
2156		    prn_devid.id_data, len, flag)) {
2157
2158			return (EFAULT);
2159		}
2160
2161		if (ddi_copyout(&prn_devid, (caddr_t)arg,
2162		    sizeof (struct prn_1284_device_id), flag)) {
2163
2164			return (EFAULT);
2165		}
2166#ifdef _MULTI_DATAMODEL
2167
2168		break;
2169	}
2170#endif /* _MULTI_DATAMODEL */
2171
2172	return (0);
2173}
2174
2175
2176/*
2177 * usbprn_prnio_get_timeouts:
2178 *	Return timeout
2179 */
2180static int
2181usbprn_prnio_get_timeouts(usbprn_state_t *usbprnp, intptr_t arg, int flag)
2182{
2183	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
2184
2185	if (ddi_copyout(&usbprnp->usbprn_prn_timeouts,
2186	    (caddr_t)arg, sizeof (struct prn_timeouts), flag)) {
2187
2188		return (EFAULT);
2189	}
2190
2191	return (0);
2192}
2193
2194
2195/*
2196 * usbprn_prnio_set_timeouts:
2197 *	Set write timeout and prn timeout
2198 */
2199static int
2200usbprn_prnio_set_timeouts(usbprn_state_t *usbprnp, intptr_t arg, int flag)
2201{
2202	struct prn_timeouts prn_timeouts;
2203
2204	ASSERT(!(mutex_owned(&usbprnp->usbprn_mutex)));
2205
2206	if (ddi_copyin((caddr_t)arg, &prn_timeouts,
2207	    sizeof (struct prn_timeouts), flag)) {
2208
2209		return (EFAULT);
2210	}
2211
2212	if ((prn_timeouts.tmo_forward < USBPRN_XFER_TIMEOUT_MIN) ||
2213	    (prn_timeouts.tmo_forward > USBPRN_XFER_TIMEOUT_MAX)) {
2214
2215		return (EINVAL);
2216	}
2217
2218	mutex_enter(&usbprnp->usbprn_mutex);
2219
2220	usbprnp->usbprn_prn_timeouts = prn_timeouts;
2221	usbprnp->usbprn_setparms.write_timeout = prn_timeouts.tmo_forward;
2222
2223	mutex_exit(&usbprnp->usbprn_mutex);
2224
2225	return (0);
2226}
2227
2228
2229/*
2230 * usbprn_biodone:
2231 *	If there is a bp, complete it
2232 */
2233static void
2234usbprn_biodone(usbprn_state_t *usbprnp, int err, int bytes_remaining)
2235{
2236	struct buf *bp = usbprnp->usbprn_bp;
2237	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
2238	usbprn_ps_t	*bulk_in = &usbprnp->usbprn_bulk_in;
2239
2240	ASSERT(mutex_owned(&usbprnp->usbprn_mutex));
2241
2242	/* all pipes must be idle now */
2243	ASSERT(bulk_out->ps_flags == USBPRN_PS_IDLE);
2244	ASSERT(bulk_in->ps_flags == USBPRN_PS_IDLE);
2245
2246	if (bp) {
2247		bp->b_resid = bytes_remaining;
2248
2249		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2250		    "usbprn_biodone: "
2251		    "bp=0x%p bcount=0x%lx resid=0x%lx remaining=0x%x err=%d",
2252		    (void *)bp, bp->b_bcount, bp->b_resid, bytes_remaining,
2253		    err);
2254
2255		if (err) {
2256			bioerror(bp, err);
2257		}
2258
2259		usbprnp->usbprn_bp = NULL;
2260		biodone(bp);
2261	}
2262
2263	/* release access */
2264	usb_release_access(usbprnp->usbprn_dev_acc);
2265}
2266
2267
2268/*
2269 * usbprn_send_async_bulk_data:
2270 *	Send bulk data down to the device through the bulk out pipe
2271 */
2272static void
2273usbprn_send_async_bulk_data(usbprn_state_t *usbprnp)
2274{
2275	int		rval;
2276	int		timeout;
2277	mblk_t		*mp;
2278	size_t		max_xfer_count, xfer_count;
2279	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
2280	usb_bulk_req_t *req;
2281
2282	mutex_enter(&usbprnp->usbprn_mutex);
2283	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
2284
2285	timeout = usbprnp->usbprn_setparms.write_timeout;
2286	max_xfer_count = usbprnp->usbprn_bp->b_bcount;
2287	mp = usbprnp->usbprn_bulk_mp;
2288	ASSERT(mp != NULL);
2289	xfer_count = MBLKL(mp);
2290	mutex_exit(&usbprnp->usbprn_mutex);
2291
2292	req = usb_alloc_bulk_req(usbprnp->usbprn_dip, 0, USB_FLAGS_SLEEP);
2293	req->bulk_len		= (uint_t)xfer_count;
2294	req->bulk_data		= mp;
2295	req->bulk_timeout	= timeout;
2296	req->bulk_cb		= usbprn_bulk_xfer_cb;
2297	req->bulk_exc_cb	= usbprn_bulk_xfer_exc_cb;
2298	req->bulk_client_private = (usb_opaque_t)usbprnp;
2299	req->bulk_attributes	= USB_ATTRS_AUTOCLEARING;
2300
2301	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2302	    "usbprn_send_async_bulk_data: req = 0x%p "
2303	    "max_bulk_xfer_size=%lu mp=0x%p xfer_cnt=%lu timeout=%x",
2304	    (void *)req, max_xfer_count, (void *)mp, xfer_count, timeout);
2305
2306	ASSERT(xfer_count <= max_xfer_count);
2307
2308
2309	if ((rval = usb_pipe_bulk_xfer(bulk_out->ps_handle, req, 0)) !=
2310	    USB_SUCCESS) {
2311
2312		USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2313		    "usbprn_send_async_bulk_data: Bulk mp=0x%p "
2314		    "rval=%d", (void *)mp, rval);
2315
2316		mutex_enter(&usbprnp->usbprn_mutex);
2317		bulk_out->ps_flags = USBPRN_PS_IDLE;
2318		usbprnp->usbprn_bulk_mp = NULL;
2319		usbprn_biodone(usbprnp, EIO, 0);
2320		mutex_exit(&usbprnp->usbprn_mutex);
2321
2322		usb_free_bulk_req(req);
2323	} else {
2324		mutex_enter(&usbprnp->usbprn_mutex);
2325		usbprnp->usbprn_bulk_mp = NULL;
2326		mutex_exit(&usbprnp->usbprn_mutex);
2327	}
2328}
2329
2330
2331/*
2332 * usbprn_bulk_xfer_cb
2333 *	Callback for a normal transfer for both bulk pipes.
2334 */
2335/*ARGSUSED*/
2336static void
2337usbprn_bulk_xfer_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
2338{
2339	usbprn_state_t	*usbprnp = (usbprn_state_t *)req->bulk_client_private;
2340	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
2341
2342	ASSERT(usbprnp != NULL);
2343	ASSERT(!mutex_owned(&usbprnp->usbprn_mutex));
2344
2345	mutex_enter(&usbprnp->usbprn_mutex);
2346
2347	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2348	    "usbprn_bulk_xfer_cb: mp=0x%p ", (void *)usbprnp->usbprn_bulk_mp);
2349
2350	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
2351	ASSERT(usbprnp->usbprn_bp != NULL);
2352	ASSERT((req->bulk_cb_flags & USB_CB_INTR_CONTEXT) == 0);
2353
2354	/*
2355	 * if device is disconnected or driver close called, return
2356	 * The pipe could be closed, or a timeout could have
2357	 * come in and the pipe is being reset.  If the
2358	 * state isn't transferring, then return
2359	 */
2360	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp)) ||
2361	    (bulk_out->ps_flags != USBPRN_PS_NEED_TO_XFER)) {
2362		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2363		    "usbprn_bulk_xfer_cb: no access or pipe closed");
2364
2365		bulk_out->ps_flags = USBPRN_PS_IDLE;
2366		usbprn_biodone(usbprnp, EIO, 0);
2367	} else {
2368
2369		/*
2370		 * data has been xferred, complete the bp.
2371		 */
2372		USB_DPRINTF_L3(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2373		    "usbprn_bulk_xfer_cb: transaction over");
2374
2375		bulk_out->ps_flags = USBPRN_PS_IDLE;
2376		usbprn_biodone(usbprnp, 0, 0);
2377	}
2378
2379	mutex_exit(&usbprnp->usbprn_mutex);
2380
2381	usb_free_bulk_req(req);
2382}
2383
2384
2385/*
2386 * usbprn_bulk_xfer_exc_cb:
2387 *	Exception callback for the bulk pipes
2388 */
2389static void
2390usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
2391{
2392	usbprn_state_t	*usbprnp = (usbprn_state_t *)req->bulk_client_private;
2393	usbprn_ps_t	*bulk_out = &usbprnp->usbprn_bulk_out;
2394	int		bytes_remaining = 0;
2395	mblk_t		*data = req->bulk_data;
2396	usb_cr_t	completion_reason = req->bulk_completion_reason;
2397	usb_cb_flags_t	cb_flags = req->bulk_cb_flags;
2398
2399	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2400	    "usbprn_bulk_xfer_exc_cb: "
2401	    "pipe=0x%p req=0x%p cr=%d cb_flags=0x%x data=0x%p",
2402	    (void *)pipe, (void *)req, completion_reason, cb_flags,
2403	    (void *)data);
2404
2405	ASSERT((req->bulk_cb_flags & USB_CB_INTR_CONTEXT) == 0);
2406	ASSERT(data != NULL);
2407	mutex_enter(&usbprnp->usbprn_mutex);
2408
2409	ASSERT(bulk_out->ps_flags == USBPRN_PS_NEED_TO_XFER);
2410	bulk_out->ps_flags = USBPRN_PS_IDLE;
2411	bulk_out->ps_cr = completion_reason;
2412
2413	if (data) {
2414		bytes_remaining = MBLKL(data);
2415	}
2416
2417	/*
2418	 * If the pipe is closed or device not responding or not in
2419	 * need of transfer, just give up on this bp.
2420	 */
2421	if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp)) ||
2422	    (req->bulk_completion_reason == USB_CR_DEV_NOT_RESP)) {
2423		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2424		    "usbprn_bulk_xfer_exc_cb: "
2425		    "device not accesible or wrong state");
2426		usbprn_biodone(usbprnp, EIO, 0);
2427	} else {
2428		if (completion_reason == USB_CR_TIMEOUT) {
2429			USB_DPRINTF_L2(PRINT_MASK_ALL,
2430			    usbprnp->usbprn_log_handle,
2431			    "usbprn_bulk_xfer_exc_cb: timeout error, "
2432			    "xferred %lu bytes",
2433			    ((usbprnp->usbprn_bp->b_bcount) -
2434			    bytes_remaining));
2435			usbprn_biodone(usbprnp, 0, bytes_remaining);
2436		} else {
2437			usbprn_biodone(usbprnp, EIO, 0);
2438		}
2439
2440	}
2441
2442	mutex_exit(&usbprnp->usbprn_mutex);
2443
2444	usb_free_bulk_req(req);
2445}
2446
2447
2448/*
2449 * usbprn_reconnect_event_cb:
2450 *	Called upon when the device is hotplugged back; event handling
2451 */
2452/*ARGSUSED*/
2453static int
2454usbprn_reconnect_event_cb(dev_info_t *dip)
2455{
2456	usbprn_state_t	*usbprnp =
2457	    (usbprn_state_t *)ddi_get_soft_state(usbprn_statep,
2458	    ddi_get_instance(dip));
2459
2460	ASSERT(usbprnp != NULL);
2461
2462	USB_DPRINTF_L3(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
2463	    "usbprn_reconnect_event_cb:");
2464
2465	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
2466
2467	mutex_enter(&usbprnp->usbprn_mutex);
2468	ASSERT(usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED);
2469
2470	mutex_exit(&usbprnp->usbprn_mutex);
2471
2472	usbprn_restore_device_state(dip, usbprnp);
2473
2474	if (usbprnp->usbprn_ugen_hdl) {
2475		(void) usb_ugen_reconnect_ev_cb(usbprnp->usbprn_ugen_hdl);
2476	}
2477
2478	usb_release_access(usbprnp->usbprn_ser_acc);
2479
2480	return (USB_SUCCESS);
2481}
2482
2483
2484/*
2485 * usbprn_disconnect_event_cb:
2486 *	callback for disconnect events
2487 */
2488/*ARGSUSED*/
2489static int
2490usbprn_disconnect_event_cb(dev_info_t *dip)
2491{
2492	usbprn_state_t	*usbprnp = (usbprn_state_t *)ddi_get_soft_state(
2493	    usbprn_statep, ddi_get_instance(dip));
2494
2495	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2496	    "usbprn_disconnect_event_cb: Begin");
2497
2498	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
2499
2500	mutex_enter(&usbprnp->usbprn_mutex);
2501	usbprnp->usbprn_dev_state = USB_DEV_DISCONNECTED;
2502
2503	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
2504		USB_DPRINTF_L0(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
2505		    "device was disconnected while open. "
2506		    "Data may have been lost");
2507	}
2508
2509	/* For now, we set the offline bit in usbprn_last_status */
2510	usbprnp->usbprn_last_status |= USB_PRINTER_PORT_NO_SELECT;
2511
2512	mutex_exit(&usbprnp->usbprn_mutex);
2513
2514	if (usbprnp->usbprn_ugen_hdl) {
2515		(void) usb_ugen_disconnect_ev_cb(usbprnp->usbprn_ugen_hdl);
2516	}
2517
2518	usb_release_access(usbprnp->usbprn_ser_acc);
2519
2520	USB_DPRINTF_L4(PRINT_MASK_EVENTS, usbprnp->usbprn_log_handle,
2521	    "usbprn_disconnect_event_cb: End");
2522
2523	return (USB_SUCCESS);
2524}
2525
2526
2527/*
2528 * usbprn_restore_device_state:
2529 *	set original configuration of the device
2530 *	Restores data xfer
2531 */
2532static void
2533usbprn_restore_device_state(dev_info_t *dip, usbprn_state_t *usbprnp)
2534{
2535	int alt, rval, iface;
2536
2537	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2538	    "usbprn_restore_device_state:");
2539
2540	mutex_enter(&usbprnp->usbprn_mutex);
2541	ASSERT((usbprnp->usbprn_dev_state == USB_DEV_DISCONNECTED) ||
2542	    (usbprnp->usbprn_dev_state == USB_DEV_SUSPENDED));
2543
2544	mutex_exit(&usbprnp->usbprn_mutex);
2545
2546	/* Check if we are talking to the same device */
2547	if (usb_check_same_device(dip, usbprnp->usbprn_log_handle,
2548	    USB_LOG_L0, PRINT_MASK_ALL,
2549	    USB_CHK_ALL, NULL) != USB_SUCCESS) {
2550
2551		/* change the device state from suspended to disconnected */
2552		mutex_enter(&usbprnp->usbprn_mutex);
2553		usbprnp->usbprn_dev_state = USB_DEV_DISCONNECTED;
2554		mutex_exit(&usbprnp->usbprn_mutex);
2555
2556		return;
2557	}
2558
2559	USB_DPRINTF_L0(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2560	    "Printer has been reconnected but data may have been lost");
2561
2562	mutex_enter(&usbprnp->usbprn_mutex);
2563
2564	/* set last status to online */
2565	usbprnp->usbprn_last_status &= ~USB_PRINTER_PORT_NO_SELECT;
2566	mutex_exit(&usbprnp->usbprn_mutex);
2567
2568	/* Get the port status */
2569	if (usbprn_get_port_status(usbprnp) != USB_SUCCESS) {
2570		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
2571		    "usbprn_restore_device_state: port status failed");
2572
2573		return;
2574	}
2575
2576	mutex_enter(&usbprnp->usbprn_mutex);
2577
2578	if ((usbprnp->usbprn_last_status & USB_PRINTER_PORT_NO_ERROR) == 0) {
2579		USB_DPRINTF_L2(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2580		    "usbprn_restore_device_state: An error with the printer");
2581	}
2582
2583	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
2584		mutex_exit(&usbprnp->usbprn_mutex);
2585		usbprn_close_usb_pipes(usbprnp);
2586		mutex_enter(&usbprnp->usbprn_mutex);
2587	}
2588
2589	/* restore alternate */
2590	alt = usbprnp->usbprn_if_descr.bAlternateSetting,
2591	    mutex_exit(&usbprnp->usbprn_mutex);
2592
2593	iface = usb_owns_device(dip) ? 0 :  usb_get_if_number(dip);
2594	if ((rval = usb_set_alt_if(dip, iface, alt,
2595	    USB_FLAGS_SLEEP, NULL, NULL)) != USB_SUCCESS) {
2596		USB_DPRINTF_L2(PRINT_MASK_ATTA, usbprnp->usbprn_log_handle,
2597		    "usbprn_restore_device_state: set alternate failed (%d)",
2598		    rval);
2599
2600		return;
2601	}
2602
2603	mutex_enter(&usbprnp->usbprn_mutex);
2604
2605	if (usbprnp->usbprn_flags & USBPRN_OPEN) {
2606
2607		mutex_exit(&usbprnp->usbprn_mutex);
2608		(void) usbprn_open_usb_pipes(usbprnp);
2609		mutex_enter(&usbprnp->usbprn_mutex);
2610	}
2611
2612	if (usbprnp->usbprn_pm && usbprnp->usbprn_pm->usbprn_wakeup_enabled) {
2613		mutex_exit(&usbprnp->usbprn_mutex);
2614		(void) usb_handle_remote_wakeup(usbprnp->usbprn_dip,
2615		    USB_REMOTE_WAKEUP_ENABLE);
2616		mutex_enter(&usbprnp->usbprn_mutex);
2617	}
2618
2619	usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
2620	mutex_exit(&usbprnp->usbprn_mutex);
2621
2622	USB_DPRINTF_L4(PRINT_MASK_ALL, usbprnp->usbprn_log_handle,
2623	    "usbprn_restore_device_state: End");
2624}
2625
2626
2627/*
2628 *	Create power managements components
2629 */
2630static void
2631usbprn_create_pm_components(dev_info_t *dip, usbprn_state_t *usbprnp)
2632{
2633	usbprn_power_t	*usbprnpm;
2634	uint_t		pwr_states;
2635
2636	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2637	    "usbprn_create_pm_components: Begin");
2638
2639	/* Allocate the state structure */
2640	usbprnpm = kmem_zalloc(sizeof (usbprn_power_t),
2641	    KM_SLEEP);
2642	usbprnp->usbprn_pm = usbprnpm;
2643	usbprnpm->usbprn_pm_capabilities = 0;
2644	usbprnpm->usbprn_current_power = USB_DEV_OS_FULL_PWR;
2645
2646	if (usb_create_pm_components(dip, &pwr_states) ==
2647	    USB_SUCCESS) {
2648		USB_DPRINTF_L4(PRINT_MASK_PM,
2649		    usbprnp->usbprn_log_handle,
2650		    "usbprn_create_pm_components: "
2651		    "created PM components");
2652
2653		if (usb_handle_remote_wakeup(dip,
2654		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
2655			usbprnpm->usbprn_wakeup_enabled = 1;
2656		}
2657		usbprnpm->usbprn_pwr_states = (uint8_t)pwr_states;
2658		(void) pm_raise_power(usbprnp->usbprn_dip, 0,
2659		    USB_DEV_OS_FULL_PWR);
2660	} else {
2661		USB_DPRINTF_L2(PRINT_MASK_PM,
2662		    usbprnp->usbprn_log_handle,
2663		    "usbprn_create_pm_components: Failed");
2664	}
2665
2666	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2667	    "usbprn_create_pm_components: END");
2668}
2669
2670
2671/*
2672 * usbprn_pwrlvl0:
2673 * Functions to handle power transition for OS levels 0 -> 3
2674 */
2675static int
2676usbprn_pwrlvl0(usbprn_state_t *usbprnp)
2677{
2678	int	rval;
2679
2680	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2681	    "usbprn_pwrlvl0:");
2682
2683	switch (usbprnp->usbprn_dev_state) {
2684	case USB_DEV_ONLINE:
2685		/* Deny the powerdown request if the device is busy */
2686		if (usbprnp->usbprn_pm->usbprn_pm_busy != 0) {
2687
2688			return (USB_FAILURE);
2689		}
2690
2691		/* Issue USB D3 command to the device here */
2692		rval = usb_set_device_pwrlvl3(usbprnp->usbprn_dip);
2693		ASSERT(rval == USB_SUCCESS);
2694
2695		usbprnp->usbprn_dev_state = USB_DEV_PWRED_DOWN;
2696		usbprnp->usbprn_pm->usbprn_current_power =
2697		    USB_DEV_OS_PWR_OFF;
2698		/* FALLTHRU */
2699	case USB_DEV_DISCONNECTED:
2700	case USB_DEV_SUSPENDED:
2701		/* allow a disconnect/cpr'ed device to go to lower power */
2702
2703		return (USB_SUCCESS);
2704	case USB_DEV_PWRED_DOWN:
2705	default:
2706		USB_DPRINTF_L2(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2707		    "usbprn_pwrlvl0: illegal dev state");
2708
2709		return (USB_FAILURE);
2710	}
2711}
2712
2713
2714/*
2715 * usbprn_pwrlvl1:
2716 *	Functions to handle power transition to OS levels -> 2
2717 */
2718static int
2719usbprn_pwrlvl1(usbprn_state_t *usbprnp)
2720{
2721	int	rval;
2722
2723	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2724	    "usbprn_pwrlvl1:");
2725
2726	/* Issue USB D2 command to the device here */
2727	rval = usb_set_device_pwrlvl2(usbprnp->usbprn_dip);
2728	ASSERT(rval == USB_SUCCESS);
2729
2730	return (USB_FAILURE);
2731}
2732
2733
2734/*
2735 * usbprn_pwrlvl2:
2736 *	Functions to handle power transition to OS levels -> 1
2737 */
2738static int
2739usbprn_pwrlvl2(usbprn_state_t *usbprnp)
2740{
2741	int	rval;
2742
2743	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2744	    "usbprn_pwrlvl2:");
2745
2746	/* Issue USB D1 command to the device here */
2747	rval = usb_set_device_pwrlvl1(usbprnp->usbprn_dip);
2748	ASSERT(rval == USB_SUCCESS);
2749
2750	return (USB_FAILURE);
2751}
2752
2753
2754/*
2755 * usbprn_pwrlvl3:
2756 *	Functions to handle power transition to OS level -> 0
2757 */
2758static int
2759usbprn_pwrlvl3(usbprn_state_t *usbprnp)
2760{
2761	USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2762	    "usbprn_pwrlvl3:");
2763
2764	switch (usbprnp->usbprn_dev_state) {
2765	case USB_DEV_PWRED_DOWN:
2766		/* Issue USB D0 command to the device here */
2767		(void) usb_set_device_pwrlvl0(usbprnp->usbprn_dip);
2768
2769		usbprnp->usbprn_dev_state = USB_DEV_ONLINE;
2770		usbprnp->usbprn_pm->usbprn_current_power =
2771		    USB_DEV_OS_FULL_PWR;
2772
2773		/* FALLTHRU */
2774	case USB_DEV_ONLINE:
2775		/* we are already in full power */
2776		/* FALLTHRU */
2777	case USB_DEV_DISCONNECTED:
2778	case USB_DEV_SUSPENDED:
2779		/*
2780		 * PM framework tries to put us in full power
2781		 * during system shutdown. If we are disconnected/cpr'ed
2782		 * return success anyways
2783		 */
2784
2785		return (USB_SUCCESS);
2786	default:
2787		USB_DPRINTF_L4(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2788		    "usbprn_pwrlvl3:");
2789
2790
2791		return (USB_FAILURE);
2792	}
2793}
2794
2795
2796/*
2797 * usbprn_power :
2798 *	Power entry point
2799 */
2800/* ARGSUSED */
2801static int
2802usbprn_power(dev_info_t *dip, int comp, int level)
2803{
2804	usbprn_state_t	*usbprnp;
2805	usbprn_power_t	*pm;
2806	int		rval = USB_FAILURE;
2807
2808	usbprnp = (usbprn_state_t *)ddi_get_soft_state(usbprn_statep,
2809	    ddi_get_instance(dip));
2810
2811	USB_DPRINTF_L3(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2812	    "usbprn_power: Begin: level=%d", level);
2813
2814	(void) usb_serialize_access(usbprnp->usbprn_ser_acc, USB_WAIT, 0);
2815
2816	mutex_enter(&usbprnp->usbprn_mutex);
2817	pm = usbprnp->usbprn_pm;
2818	ASSERT(pm != NULL);
2819
2820	/* Check if we are transitioning to a legal power level */
2821	if (USB_DEV_PWRSTATE_OK(pm->usbprn_pwr_states, level)) {
2822		USB_DPRINTF_L2(PRINT_MASK_PM, usbprnp->usbprn_log_handle,
2823		    "usbprn_power: illegal power level=%d "
2824		    "pwr_states=0x%x", level, pm->usbprn_pwr_states);
2825
2826		goto done;
2827	}
2828
2829	switch (level) {
2830	case USB_DEV_OS_PWR_OFF :
2831		rval = usbprn_pwrlvl0(usbprnp);
2832
2833		break;
2834	case USB_DEV_OS_PWR_1 :
2835		rval = usbprn_pwrlvl1(usbprnp);
2836
2837		break;
2838	case USB_DEV_OS_PWR_2 :
2839		rval = usbprn_pwrlvl2(usbprnp);
2840
2841		break;
2842	case USB_DEV_OS_FULL_PWR :
2843		rval = usbprn_pwrlvl3(usbprnp);
2844
2845		break;
2846	}
2847
2848done:
2849	mutex_exit(&usbprnp->usbprn_mutex);
2850
2851	usb_release_access(usbprnp->usbprn_ser_acc);
2852
2853	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2854}
2855
2856
2857/*
2858 * usbprn_print_long:
2859 *	Breakup a string which is > USBPRN_PRINT_MAXLINE and print it
2860 */
2861static void
2862usbprn_print_long(usbprn_state_t *usbprnp, char *str, int len)
2863{
2864	char *tmp = str;
2865	char pbuf[USBPRN_PRINT_MAXLINE];
2866
2867	for (;;) {
2868		if (len <= USBPRN_PRINT_MAXLINE) {
2869			USB_DPRINTF_L4(PRINT_MASK_ATTA,
2870			    usbprnp->usbprn_log_handle, "%s", tmp);
2871
2872			break;
2873		} else {
2874			bcopy(tmp, pbuf, USBPRN_PRINT_MAXLINE);
2875			USB_DPRINTF_L4(PRINT_MASK_ATTA,
2876			    usbprnp->usbprn_log_handle, "%s", pbuf);
2877			tmp += USBPRN_PRINT_MAXLINE;
2878			len -= USBPRN_PRINT_MAXLINE;
2879		}
2880	}
2881}
2882
2883
2884static void
2885usbprn_pm_busy_component(usbprn_state_t *usbprn_statep)
2886{
2887	ASSERT(!mutex_owned(&usbprn_statep->usbprn_mutex));
2888	if (usbprn_statep->usbprn_pm != NULL) {
2889		mutex_enter(&usbprn_statep->usbprn_mutex);
2890		usbprn_statep->usbprn_pm->usbprn_pm_busy++;
2891
2892		USB_DPRINTF_L4(PRINT_MASK_PM, usbprn_statep->usbprn_log_handle,
2893		    "usbprn_pm_busy_component: %d",
2894		    usbprn_statep->usbprn_pm->usbprn_pm_busy);
2895
2896		mutex_exit(&usbprn_statep->usbprn_mutex);
2897
2898		if (pm_busy_component(usbprn_statep->usbprn_dip, 0) !=
2899		    DDI_SUCCESS) {
2900			mutex_enter(&usbprn_statep->usbprn_mutex);
2901			usbprn_statep->usbprn_pm->usbprn_pm_busy--;
2902
2903			USB_DPRINTF_L2(PRINT_MASK_PM,
2904			    usbprn_statep->usbprn_log_handle,
2905			    "usbprn_pm_busy_component: %d",
2906			    usbprn_statep->usbprn_pm->usbprn_pm_busy);
2907
2908			mutex_exit(&usbprn_statep->usbprn_mutex);
2909		}
2910
2911	}
2912}
2913
2914
2915static void
2916usbprn_pm_idle_component(usbprn_state_t *usbprn_statep)
2917{
2918	ASSERT(!mutex_owned(&usbprn_statep->usbprn_mutex));
2919	if (usbprn_statep->usbprn_pm != NULL) {
2920		if (pm_idle_component(usbprn_statep->usbprn_dip, 0) ==
2921		    DDI_SUCCESS) {
2922			mutex_enter(&usbprn_statep->usbprn_mutex);
2923			ASSERT(usbprn_statep->usbprn_pm->usbprn_pm_busy > 0);
2924			usbprn_statep->usbprn_pm->usbprn_pm_busy--;
2925
2926			USB_DPRINTF_L4(PRINT_MASK_PM,
2927			    usbprn_statep->usbprn_log_handle,
2928			    "usbprn_pm_idle_component: %d",
2929			    usbprn_statep->usbprn_pm->usbprn_pm_busy);
2930
2931			mutex_exit(&usbprn_statep->usbprn_mutex);
2932		}
2933
2934	}
2935}
2936