usbprn.c revision d29f5a711240f866521445b1656d114da090335e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Printer Class Driver for USB
*
* This driver supports devices that adhere to the USB Printer Class
* specification 1.0.
*
* NOTE: This driver is not DDI compliant in that it uses undocumented
* functions for logging (USB_DPRINTF_L*, usb_alloc_log_hdl, usb_free_log_hdl),
* and serialization (usb_serialize_access, usb_release_access,
* usb_init_serialization, usb_fini_serialization)
*
* Undocumented functions may go away in a future Solaris OS release.
*
* Please see the DDK for sample code of these functions, and for the usbskel
* skeleton template driver which contains scaled-down versions of these
* functions written in a DDI-compliant way.
*/
#define DEBUG
#endif
#ifdef __lock_lint
#define _MULTI_DATAMODEL
#endif
#define USBDRV_MAJOR_VER 2
#define USBDRV_MINOR_VER 0
/* Debugging support */
/* local variables */
static uint_t usbprn_ifcap =
/*
* Function Prototypes
*/
static int usbprn_get_descriptors(usbprn_state_t *);
static int usbprn_get_device_id(usbprn_state_t *);
static int usbprn_get_port_status(usbprn_state_t *);
static int usbprn_open_usb_pipes(usbprn_state_t *);
static void usbprn_close_usb_pipes(usbprn_state_t *);
static void usbprn_minphys(struct buf *);
static int usbprn_strategy(struct buf *);
static int usbprn_testio(usbprn_state_t *, int);
static int usbprn_ioctl_get_status(usbprn_state_t *);
static void usbprn_send_async_bulk_data(usbprn_state_t *);
static void usbprn_bulk_xfer_exc_cb(usb_pipe_handle_t,
usb_bulk_req_t *);
static void usbprn_biodone(usbprn_state_t *, int, int);
static char usbprn_error_state(uchar_t);
static void usbprn_print_long(usbprn_state_t *, char *, int);
/* event handling */
static int usbprn_disconnect_event_cb(dev_info_t *);
static int usbprn_reconnect_event_cb(dev_info_t *);
static int usbprn_cpr_suspend(dev_info_t *);
static void usbprn_cpr_resume(dev_info_t *);
static usb_event_t usbprn_events = {
};
/* PM handling */
static int usbprn_pwrlvl0(usbprn_state_t *);
static int usbprn_pwrlvl1(usbprn_state_t *);
static int usbprn_pwrlvl2(usbprn_state_t *);
static int usbprn_pwrlvl3(usbprn_state_t *);
static void usbprn_pm_busy_component(usbprn_state_t *);
static void usbprn_pm_idle_component(usbprn_state_t *);
/* module loading stuff */
struct cb_ops usbprn_cb_ops = {
usbprn_open, /* open */
usbprn_close, /* close */
nulldev, /* strategy */
nulldev, /* print */
nulldev, /* dump */
usbprn_read, /* read */
usbprn_write, /* write */
usbprn_ioctl, /* ioctl */
nulldev, /* devmap */
nulldev, /* mmap */
nulldev, /* segmap */
usbprn_poll, /* poll */
ddi_prop_op, /* cb_prop_op */
NULL, /* streamtab */
};
static struct dev_ops usbprn_ops = {
DEVO_REV, /* devo_rev, */
0, /* refcnt */
usbprn_info, /* info */
nulldev, /* identify */
nulldev, /* probe */
usbprn_attach, /* attach */
usbprn_detach, /* detach */
nodev, /* reset */
&usbprn_cb_ops, /* driver operations */
NULL, /* bus operations */
usbprn_power /* power */
};
static struct modldrv usbprnmodldrv = {
"USB printer client driver",
};
static struct modlinkage modlinkage = {
NULL,
};
/* local variables */
/* soft state structures */
#define USBPRN_INITIAL_SOFT_SPACE 1
static void *usbprn_statep;
static int usbprn_max_xfer_size = USBPRN_MAX_XFER_SIZE;
/* prnio support */
static const char usbprn_prnio_ifinfo[] = PRN_USB;
int
_init(void)
{
int rval;
sizeof (usbprn_state_t), USBPRN_INITIAL_SOFT_SPACE)) != 0) {
return (rval);
}
}
return (rval);
}
int
_fini(void)
{
int rval;
return (rval);
}
return (rval);
}
int
{
}
/*
* usbprn_info:
* Get minor number, soft state structure, etc.
*/
/*ARGSUSED*/
static int
{
int error = DDI_FAILURE;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
error = DDI_SUCCESS;
}
} else {
}
break;
case DDI_INFO_DEVT2INSTANCE:
error = DDI_SUCCESS;
break;
default:
break;
}
return (error);
}
/*
* usbprn_attach:
* Attach driver
* Get the descriptor information
* Get the device id
* Reset the device
* Get the port status
*/
static int
{
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
return (DDI_FAILURE);
}
"prn", &usbprn_errlevel,
&usbprn_errmask, &usbprn_instance_debug, 0);
"usbprn_attach: cmd=%x", cmd);
"usb_client_attach failed");
goto fail;
}
USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
"usb_get_dev_data failed");
goto fail;
}
/* Initialize locks and conditional variables */
/* Obtain all the relevant descriptors */
"usb get descriptors failed");
goto fail;
}
/* Obtain the device id */
(void) usbprn_get_device_id(usbprnp);
/* Get the port status */
/* some printers fail on the first */
"usb get port status failed");
goto fail;
}
}
"usbprn_attach: error occurred with the printer");
}
/*
* Create minor node based on information from the
* descriptors
*/
DDI_NT_PRINTER, 0)) != DDI_SUCCESS) {
"usbprn_attach: cannot create minor node");
goto fail;
}
goto fail;
}
"usbprn_attach: xfer_size=0x%lx", sz);
/* enable PM */
/* Register for events */
"usbprn_attach: usb_register_event_cbs failed");
goto fail;
}
if (usb_owns_device(dip)) {
/* get a ugen handle */
USB_SUCCESS) {
"usb_ugen_attach failed");
}
}
/* Report device */
"usbprn_attach: done");
return (DDI_SUCCESS);
fail:
if (usbprnp) {
}
return (DDI_FAILURE);
}
/*
* usbprn_detach:
* detach or suspend driver instance
*/
static int
{
int rval = DDI_FAILURE;
"usbprn_detach: cmd=%x", cmd);
switch (cmd) {
case DDI_DETACH:
return (DDI_SUCCESS);
case DDI_SUSPEND:
default:
return (rval);
}
}
/*
* usbprn_cleanup:
* clean up the driver state
*/
static void
{
int rval = 0;
"usbprn_cleanup: Start");
/*
* Disable the event callbacks first, after this point, event
* callbacks will never get called. Note we shouldn't hold
* mutex while unregistering events because there may be a
* competing event callback thread. Event callbacks are done
* with ndi mutex held and this can cause a potential deadlock.
*/
if ((usbprnpm) &&
if (usbprnpm->usbprn_wakeup_enabled) {
(void) pm_raise_power(dip, 0,
USB_SUCCESS) {
"usbprn_cleanup: "
"disable remote wakeup "
"failed, rval=%d", rval);
}
} else {
}
}
if (usbprnp->usbprn_device_id) {
}
}
if (usbprnpm) {
}
"usbprn_cleanup: End");
if (usbprnp->usbprn_ugen_hdl) {
}
/* unregister with USBA */
}
/*
* usbprn_cpr_suspend:
* prepare to be suspended
*/
static int
{
int rval = USB_FAILURE;
"usbprn_cpr_suspend");
"usbprn_cpr_suspend: "
"Device is open. Can't suspend");
} else {
"usbprn_cpr_suspend: SUCCESS");
rval = USB_SUCCESS;
}
}
return (rval);
}
static void
{
"usbprn_cpr_resume");
/* Needed as power up state of dev is "unknown" to system */
if (usbprnp->usbprn_ugen_hdl) {
}
}
/*
* usbprn_get_descriptors:
* Obtain all the descriptors for the device
*/
static int
{
int interface;
/*
* Section 4.2.1 of the spec says the printer could have
* multiple configurations. This driver is just for one
* configuration interface and one interface.
*/
break;
} else {
"alternate %d not supported", alt);
}
}
"usbprn_get_descriptors: no alternate");
return (USB_FAILURE);
}
"usbprn_get_descriptors: set alternate failed (%d)",
rval);
return (rval);
}
/*
* find the endpoint descriptors. There will be a bulk-out endpoint
* and an optional bulk-in endpoint.
*/
}
}
return (USB_SUCCESS);
}
/*
* usbprn_get_device_id:
* Get the device id as described in 4.2.1 of the specification
* Lexmark printer returns 2 bytes when asked for 8 bytes
* We are ignoring data over and underrun.
* This is a synchronous function
*/
static int
{
int len, n;
int rval = USB_FAILURE;
USB_DEV_REQ_DEV_TO_HOST | /* bmRequestType */
USB_PRINTER_GET_DEVICE_ID, /* bRequest */
0, /* wValue: fill in later */
0, /* wIndex: fill in later */
0, /* wLength: fill in later */
0 /* attributes */
};
void *ptr;
"usbprn_get_device_id: Begin");
/*
* This is always a sync request as this will never
* be called in interrupt context.
* First get the first two bytes that gives the length
* of the device id string; then get the whole string
*/
"usbprn_get_device_id: First sync command failed, cr=%d ",
/*
* some devices return more than requested. as long as
* we get the first two bytes, we can continue
*/
if (((completion_reason != USB_CR_DATA_OVERRUN) &&
(completion_reason != USB_CR_DATA_UNDERRUN)) ||
goto done;
}
}
if (n < 2) {
goto done;
}
/*
* Std 1284-1994, chapter 7.6:
* Length values of x'0000', x'0001' and x'0002' are reserved
*/
if (len < 3) {
goto done;
}
"usbprn_get_device_id: device id length=%d", len);
/* did we get enough data */
if (len > n) {
USB_SUCCESS) {
"usbprn_get_device_id: 2nd command failed "
"cr=%d cb_flags=0x%x",
goto done;
}
}
"usbprn_get_device_id: returned data length=%ld",
/* Length is in the first two bytes, dump string in logbuf */
rval = USB_SUCCESS;
done:
"usbprn_get_device_id: rval=%d", rval);
return (rval);
}
/*
* usbprn_get_port_status:
* Get the port status.
* This is a synchronous function
*/
static int
{
USB_DEV_REQ_DEV_TO_HOST | /* bmRequestType */
USB_PRINTER_GET_PORT_STATUS, /* bRequest */
0, /* wValue */
0, /* wIndex: fill in later */
1, /* wLength */
0 /* attributes */
};
"usbprn_get_port_status: Begin");
USB_SUCCESS) {
"usbprn_get_port_status: Sync command failed "
return (USB_FAILURE);
} else {
"usbprn_get_port_status(sync): status=0x%x",
return (USB_SUCCESS);
}
}
/*
* usbprn_open:
* Open the pipes
*/
/*ARGSUSED*/
static int
{
int rval = 0;
return (ENXIO);
}
"usbprn_open:");
/* Fail open on a disconnected device */
return (ENODEV);
}
/* cannot happen? but just in case */
return (EIO);
}
return (rval);
}
/* Exit if this instance is already open */
return (EBUSY);
}
/* raise power */
0, USB_DEV_OS_FULL_PWR);
/* initialize some softstate data */
"usbprn_open: pipe open failed");
return (EIO);
}
/* set last status to online */
"usbprn_open: End");
return (rval);
}
/*
* usbprn_close:
* Close the pipes
*/
/*ARGSUSED*/
static int
{
int rval = 0;
return (ENXIO);
}
"usbprn_close:");
return (rval);
}
/* avoid races with connect/disconnect */
/* Close all usb pipes */
/* prevent any accesses by setting flags to closed */
"usbprn_close: End");
return (rval);
}
/*
* usbprn_read:
* Read entry point (TBD)
*/
/* ARGSUSED */
static int
{
return (ENXIO);
}
int rval;
/* raise power */
0, USB_DEV_OS_FULL_PWR);
USB_WAIT_SIG, 0) == 0) {
return (EINTR);
}
return (rval);
}
/* Do a bulk-in from the printer */
return (EIO);
}
/*
* usbprn_write:
* Write to the printer
*/
/* ARGSUSED2 */
static int
{
int rval;
return (ENXIO);
}
"usbprn_write: Begin usbprnp=0x%p ", (void *)usbprnp);
/* raise power */
0, USB_DEV_OS_FULL_PWR);
USB_WAIT_SIG, 0) == 0) {
return (EINTR);
}
return (rval);
}
/*
* serialize writes
* we cannot use usbprn_ser_acc sync object at this point because
* that would block out the ioctls for the full duration of the write.
*/
USB_WAIT_SIG, 0) == 0) {
return (EINTR);
}
/*
* Check the status of the pipe. If it's not idle,
* then wait.
*/
/* if device is disconnected or pipes closed, fail immediately */
if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
"usbprn_write: device can't be accessed");
return (EIO);
}
/* all pipes must be idle */
/*
* Call physio to do the transfer. physio will
* call the strategy routine, and then call
* biowait() to block until the transfer completes.
*/
"usbprn_write: End");
return (rval);
}
/*
* usbprn_poll
*/
static int
{
return (ENXIO);
}
}
return (ENXIO);
}
/*
* usbprn_strategy:
* service a request to the device.
*/
static int
{
/*
* serialize to avoid races
* access is released in usbprn_biodone()
*/
if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
"usbprn_strategy: device can't be accessed");
return (0);
}
"usbprn_strategy: usbprnp=0x%p bp=0x%p count=%lu",
"usbprn_strategy: allocb failed");
return (0);
}
return (0);
}
/*
* usbprn_ioctl:
* handle the ioctl
*/
/*ARGSUSED4*/
static int
{
int err = 0;
struct ecpp_device_id usbprn_devid;
int len;
"usbprn_ioctl: Begin ");
/*
* only for PRNIOC_GET_STATUS cmd:
* if device is disconnected or pipes closed, fail immediately
*/
if ((cmd == PRNIOC_GET_STATUS) &&
!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
"usbprn_write: device can't be accessed");
return (EIO);
}
switch (cmd) {
case ECPPIOC_GETDEVID:
/*
* With genericized ioctls this interface should change.
* We ignore the mode in USB printer driver because
* it need not be in nibble mode in usb driver unlike
* ecpp to retrieve the device id string. Also we do
* not expect the application to call this twice since
* it doesn't change since attach time and we take care
* of calling it twice: once for getting the length and
* once for getting the actual device id string. So we
* set both the lengths to actual device id string length.
* Ref: PSARC/2000/018
*/
"usbprn_ioctl: ECPPIOC_GETDEVID(0x%x)", cmd);
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
struct ecpp_device_id32 usbprn_devid32;
sizeof (struct ecpp_device_id32), flag)) {
break;
}
break;
}
break;
}
sizeof (struct ecpp_device_id32), flag)) {
break;
}
break;
}
case DDI_MODEL_NONE:
sizeof (struct ecpp_device_id), flag)) {
break;
}
break;
}
break;
}
sizeof (struct ecpp_device_id), flag)) {
break;
}
break;
}
break;
#else
sizeof (struct ecpp_device_id), flag)) {
break;
}
break;
}
break;
}
sizeof (struct ecpp_device_id), flag)) {
break;
}
break;
#endif
case ECPPIOC_SETPARMS:
break;
case ECPPIOC_GETPARMS:
"usbprn_ioctl: ECPPIOC_GETPARMS(0x%x)", cmd);
/* Get the parameters */
break;
case BPPIOC_GETERR:
"usbprn_ioctl: ECPPIOC_GETERR(0x%x)", cmd);
/* Get the error state */
break;
case BPPIOC_TESTIO:
"usbprn_ioctl: BPPIOC_TESTIO(0x%x)", cmd);
/* Get the port status */
break;
case PRNIOC_GET_IFCAP:
"usbprn_ioctl : PRNIOC_GET_IFCAP(0x%x)", cmd);
/* get interface capabilities */
break;
case PRNIOC_SET_IFCAP:
"usbprn_ioctl : PRNIOC_SET_IFCAP(0x%x)", cmd);
/* get interface capabilities */
break;
case PRNIOC_GET_IFINFO:
"usbprn_ioctl : PRNIOC_GET_IFINFO(0x%x)", cmd);
/* get interface information */
break;
case PRNIOC_GET_STATUS:
"usbprn_ioctl : PRNIOC_GET_STATUS(0x%x)", cmd);
/* get prnio status */
break;
case PRNIOC_GET_1284_DEVID:
"usbprn_ioctl : PRNIOC_GET_1284_DEVID(0x%x)", cmd);
/* get device ID */
break;
case PRNIOC_GET_1284_STATUS:
"usbprn_ioctl : PRNIOC_GET_1284_STATUS(0x%x)", cmd);
/* get prnio status */
break;
case PRNIOC_GET_TIMEOUTS:
"usbprn_ioctl : PRNIOC_GET_TIMEOUTS(0x%x)", cmd);
/* Get the parameters */
break;
case PRNIOC_SET_TIMEOUTS:
"usbprn_ioctl : PRNIOC_SET_TIMEOUTS(0x%x)", cmd);
/* Get the parameters */
break;
case PRNIOC_RESET:
"usbprn_ioctl : PRNIOC_RESET(0x%x)", cmd);
/* nothing */
err = 0;
break;
default:
"usbprn_ioctl: unknown(0x%x)", cmd);
}
"usbprn_ioctl: End ");
return (err);
}
/*
* breakup by physio
*/
static void
{
} else {
}
}
/*
* usbprn_open_usb_pipes:
* Open all pipes on the device
*/
static int
{
"usbprn_open_usb_pipes:");
/*
* Intitialize the pipe policy for the bulk out pipe
*/
/* Open bulk_out pipe */
return (USB_FAILURE);
}
#ifdef LATER
/* Open the bulk in pipe if one exists */
/*
* Initialize the pipe policy for the Bulk In pipe
*/
/* Open bulk_in pipe */
USB_SUCCESS) {
return (USB_FAILURE);
}
} else {
}
#else
#endif
"usbprn_open_usb_pipes: success");
return (USB_SUCCESS);
}
/*
* usbprn_close_usb_pipes:
*/
static void
{
"usbprn_close_usb_pipes:");
#ifdef DEBUG
#endif
/*
* close the pipe, if another thread is already closing the
* pipe, we get USB_INVALID_PIPE
*/
"usbprn_close_usb_pipes: Closing bulk out pipe");
}
"usbprn_close_usb_pipes: Closing bulk in pipe");
}
}
/*
* usbprn_getparms:
* Get the parameters for the device
*/
static int
{
return (EFAULT);
}
return (0);
}
/*
* usbprn_setparms:
* Set the parameters for the device
*/
static int
{
struct ecpp_transfer_parms xfer;
sizeof (struct ecpp_transfer_parms), flag)) {
return (EFAULT);
}
return (EINVAL);
}
return (EINVAL);
}
return (EPROTONOSUPPORT);
}
return (0);
}
/*
* usbprn_geterr:
* Return the any device error state
*/
static void
{
struct bpp_error_status bpp_status;
bpp_status.bus_error = 0;
(void) ddi_copyout(&bpp_status,
}
/*
* usbprn_error_state:
* Map the driver error state to that of the application
*/
static char
{
uchar_t app_err_status = 0;
if (!(status & USB_PRINTER_PORT_NO_ERROR)) {
}
if (status & USB_PRINTER_PORT_EMPTY) {
}
if (!(status & USB_PRINTER_PORT_NO_SELECT)) {
}
return (app_err_status);
}
static int
{
/* Check the transfer mode */
/* if device is disconnected or pipes closed, fail immediately */
if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp))) {
"usbprn_ioctl_get_status: device can't be accessed");
return (EIO);
}
return (EIO);
}
return (0);
}
/*
* usbprn_testio:
* Execute the ECPP_TESTIO ioctl
*/
/* ARGSUSED1 */
static int
{
int err;
"usbprn_testio: begin");
return (err);
}
/* There is an error. Return it to the user */
return (EIO);
} else {
return (0);
}
}
/*
* usbprn_prnio_get_status:
* Execute the PRNIOC_GET_STATUS ioctl
*/
static int
{
uint_t prnio_status = 0;
int err;
"usbprn_prnio_get_status: begin");
/* capture printer status */
}
if ((err == 0) &&
}
if (ddi_copyout(&prnio_status,
return (EFAULT);
}
return (0);
}
/*
* usbprn_prnio_get_1284_status:
* Execute the PRNIOC_GET_1284_STATUS ioctl
*/
static int
{
int err;
"usbprn_prnio_get_1284_status: begin");
return (err);
}
/* status was captured successfully */
return (EFAULT);
}
return (0);
}
/*
* usbprn_prnio_get_ifcap:
* Execute the PRNIOC_GET_IFCAP ioctl
*/
/* ARGSUSED */
static int
{
flag)) {
return (EFAULT);
}
return (0);
}
/*
* usbprn_prnio_get_ifcap:
* Execute the PRNIOC_SET_IFCAP ioctl
*/
/* ARGSUSED */
static int
{
return (EFAULT);
}
/* no settable capabilities */
if (usbprn_ifcap != new_ifcap) {
return (EINVAL);
}
return (0);
}
/*
* usbprn_prnio_get_ifinfo:
* Execute the PRNIOC_GET_IFINFO ioctl
*/
/* ARGSUSED */
static int
{
struct prn_interface_info prn_info;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
struct prn_interface_info32 prn_info32;
sizeof (struct prn_interface_info32), flag)) {
return (EFAULT);
}
if (ddi_copyout(&usbprn_prnio_ifinfo[0],
return (EFAULT);
}
sizeof (struct prn_interface_info32), flag)) {
return (EFAULT);
}
break;
}
case DDI_MODEL_NONE:
#endif /* _MULTI_DATAMODEL */
sizeof (struct prn_interface_info), flag)) {
return (EFAULT);
}
if (ddi_copyout(&usbprn_prnio_ifinfo[0],
return (EFAULT);
}
sizeof (struct prn_interface_info), flag)) {
return (EFAULT);
}
#ifdef _MULTI_DATAMODEL
break;
}
#endif /* _MULTI_DATAMODEL */
return (0);
}
/*
* usbprn_prnio_getdevid:
* Execute the PRNIOC_GET_1284_DEVID ioctl
*/
static int
{
struct prn_1284_device_id prn_devid;
int len;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
struct prn_1284_device_id32 prn_devid32;
sizeof (struct prn_1284_device_id32), flag)) {
return (EFAULT);
}
return (EFAULT);
}
sizeof (struct prn_1284_device_id32), flag)) {
return (EFAULT);
}
break;
}
case DDI_MODEL_NONE:
#endif /* _MULTI_DATAMODEL */
sizeof (struct prn_1284_device_id), flag)) {
return (EFAULT);
}
return (EFAULT);
}
sizeof (struct prn_1284_device_id), flag)) {
return (EFAULT);
}
#ifdef _MULTI_DATAMODEL
break;
}
#endif /* _MULTI_DATAMODEL */
return (0);
}
/*
* usbprn_prnio_get_timeouts:
* Return timeout
*/
static int
{
return (EFAULT);
}
return (0);
}
/*
* usbprn_prnio_set_timeouts:
* Set write timeout and prn timeout
*/
static int
{
struct prn_timeouts prn_timeouts;
sizeof (struct prn_timeouts), flag)) {
return (EFAULT);
}
return (EINVAL);
}
return (0);
}
/*
* usbprn_biodone:
* If there is a bp, complete it
*/
static void
{
/* all pipes must be idle now */
if (bp) {
"usbprn_biodone: "
"bp=0x%p bcount=0x%lx resid=0x%lx remaining=0x%x err=%d",
err);
if (err) {
}
}
/* release access */
}
/*
* usbprn_send_async_bulk_data:
* Send bulk data down to the device through the bulk out pipe
*/
static void
{
int rval;
int timeout;
"usbprn_send_async_bulk_data: req = 0x%p "
"max_bulk_xfer_size=%lu mp=0x%p xfer_cnt=%lu timeout=%x",
USB_SUCCESS) {
"usbprn_send_async_bulk_data: Bulk mp=0x%p "
} else {
}
}
/*
* usbprn_bulk_xfer_cb
* Callback for a normal transfer for both bulk pipes.
*/
/*ARGSUSED*/
static void
{
/*
* if device is disconnected or driver close called, return
* The pipe could be closed, or a timeout could have
* come in and the pipe is being reset. If the
* state isn't transferring, then return
*/
if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp)) ||
"usbprn_bulk_xfer_cb: no access or pipe closed");
} else {
/*
* data has been xferred, complete the bp.
*/
"usbprn_bulk_xfer_cb: transaction over");
usbprn_biodone(usbprnp, 0, 0);
}
}
/*
* usbprn_bulk_xfer_exc_cb:
* Exception callback for the bulk pipes
*/
static void
{
int bytes_remaining = 0;
"usbprn_bulk_xfer_exc_cb: "
"pipe=0x%p req=0x%p cr=%d cb_flags=0x%x data=0x%p",
(void *)data);
if (data) {
}
/*
* If the pipe is closed or device not responding or not in
* need of transfer, just give up on this bp.
*/
if (!(USBPRN_DEVICE_ACCESS_OK(usbprnp)) ||
"usbprn_bulk_xfer_exc_cb: "
"device not accesible or wrong state");
} else {
if (completion_reason == USB_CR_TIMEOUT) {
"usbprn_bulk_xfer_exc_cb: timeout error, "
"xferred %lu bytes",
} else {
}
}
}
/*
* usbprn_reconnect_event_cb:
* Called upon when the device is hotplugged back; event handling
*/
/*ARGSUSED*/
static int
{
"usbprn_reconnect_event_cb:");
if (usbprnp->usbprn_ugen_hdl) {
}
return (USB_SUCCESS);
}
/*
* usbprn_disconnect_event_cb:
* callback for disconnect events
*/
/*ARGSUSED*/
static int
{
"usbprn_disconnect_event_cb: Begin");
"device was disconnected while open. "
"Data may have been lost");
}
/* For now, we set the offline bit in usbprn_last_status */
if (usbprnp->usbprn_ugen_hdl) {
}
"usbprn_disconnect_event_cb: End");
return (USB_SUCCESS);
}
/*
* usbprn_restore_device_state:
* set original configuration of the device
* Restores data xfer
*/
static void
{
"usbprn_restore_device_state:");
/* Check if we are talking to the same device */
/* change the device state from suspended to disconnected */
return;
}
"Printer has been reconnected but data may have been lost");
/* set last status to online */
/* Get the port status */
"usbprn_restore_device_state: port status failed");
return;
}
"usbprn_restore_device_state: An error with the printer");
}
}
/* restore alternate */
"usbprn_restore_device_state: set alternate failed (%d)",
rval);
return;
}
(void) usbprn_open_usb_pipes(usbprnp);
}
}
"usbprn_restore_device_state: End");
}
/*
* Create power managements components
*/
static void
{
"usbprn_create_pm_components: Begin");
/* Allocate the state structure */
KM_SLEEP);
USB_SUCCESS) {
"usbprn_create_pm_components: "
"created PM components");
}
} else {
"usbprn_create_pm_components: Failed");
}
"usbprn_create_pm_components: END");
}
/*
* usbprn_pwrlvl0:
* Functions to handle power transition for OS levels 0 -> 3
*/
static int
{
int rval;
"usbprn_pwrlvl0:");
switch (usbprnp->usbprn_dev_state) {
case USB_DEV_ONLINE:
/* Deny the powerdown request if the device is busy */
return (USB_FAILURE);
}
/* Issue USB D3 command to the device here */
/* FALLTHRU */
case USB_DEV_DISCONNECTED:
case USB_DEV_SUSPENDED:
/* allow a disconnect/cpr'ed device to go to lower power */
return (USB_SUCCESS);
case USB_DEV_PWRED_DOWN:
default:
"usbprn_pwrlvl0: illegal dev state");
return (USB_FAILURE);
}
}
/*
* usbprn_pwrlvl1:
* Functions to handle power transition to OS levels -> 2
*/
static int
{
int rval;
"usbprn_pwrlvl1:");
/* Issue USB D2 command to the device here */
return (USB_FAILURE);
}
/*
* usbprn_pwrlvl2:
* Functions to handle power transition to OS levels -> 1
*/
static int
{
int rval;
"usbprn_pwrlvl2:");
/* Issue USB D1 command to the device here */
return (USB_FAILURE);
}
/*
* usbprn_pwrlvl3:
* Functions to handle power transition to OS level -> 0
*/
static int
{
"usbprn_pwrlvl3:");
switch (usbprnp->usbprn_dev_state) {
case USB_DEV_PWRED_DOWN:
/* Issue USB D0 command to the device here */
/* FALLTHRU */
case USB_DEV_ONLINE:
/* we are already in full power */
/* FALLTHRU */
case USB_DEV_DISCONNECTED:
case USB_DEV_SUSPENDED:
/*
* PM framework tries to put us in full power
* during system shutdown. If we are disconnected/cpr'ed
* return success anyways
*/
return (USB_SUCCESS);
default:
"usbprn_pwrlvl3:");
return (USB_FAILURE);
}
}
/*
* usbprn_power :
* Power entry point
*/
/* ARGSUSED */
static int
{
int rval = USB_FAILURE;
"usbprn_power: Begin: level=%d", level);
/* Check if we are transitioning to a legal power level */
"usbprn_power: illegal power level=%d "
goto done;
}
switch (level) {
case USB_DEV_OS_PWR_OFF :
break;
case USB_DEV_OS_PWR_1 :
break;
case USB_DEV_OS_PWR_2 :
break;
case USB_DEV_OS_FULL_PWR :
break;
}
done:
}
/*
* usbprn_print_long:
* Breakup a string which is > USBPRN_PRINT_MAXLINE and print it
*/
static void
{
char pbuf[USBPRN_PRINT_MAXLINE];
for (;;) {
if (len <= USBPRN_PRINT_MAXLINE) {
break;
} else {
}
}
}
static void
{
"usbprn_pm_busy_component: %d",
DDI_SUCCESS) {
"usbprn_pm_busy_component: %d",
}
}
}
static void
{
DDI_SUCCESS) {
"usbprn_pm_idle_component: %d",
}
}
}