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