/* * wusb_df_detach: * detach or suspend driver instance * * Note: in detach, only contention threads is from pm and disconnnect. */ static int wusb_df_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { int instance = ddi_get_instance(dip); wusb_df_state_t *wusb_dfp = ddi_get_soft_state(wusb_df_statep, instance); int rval = DDI_FAILURE; switch (cmd) { case DDI_DETACH: USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, "Detach: enter for detach"); rval = wusb_df_cleanup(dip, wusb_dfp); break; case DDI_SUSPEND: USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, "Detach: enter for suspend"); rval = wusb_df_cpr_suspend(dip); default: break; } return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); }
static void wusb_df_pm_busy_component(wusb_df_state_t *wusb_dfp) { ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex)); mutex_enter(&wusb_dfp->wusb_df_mutex); if (wusb_dfp->wusb_df_pm == NULL) { USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_pm_busy_component: pm = NULL"); goto done; } wusb_dfp->wusb_df_pm->wusb_df_pm_busy++; USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_pm_busy_component: %d", wusb_dfp->wusb_df_pm->wusb_df_pm_busy); mutex_exit(&wusb_dfp->wusb_df_mutex); if (pm_busy_component(wusb_dfp->wusb_df_dip, 0) != DDI_SUCCESS) { mutex_enter(&wusb_dfp->wusb_df_mutex); wusb_dfp->wusb_df_pm->wusb_df_pm_busy--; USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_pm_busy_component: %d", wusb_dfp->wusb_df_pm->wusb_df_pm_busy); mutex_exit(&wusb_dfp->wusb_df_mutex); } return; done: mutex_exit(&wusb_dfp->wusb_df_mutex); }
/* ARGSUSED */ static void ehci_sendup_itd_message( ehci_state_t *ehcip, ehci_pipe_private_t *pp, ehci_isoc_xwrapper_t *itw, ehci_itd_t *td, usb_cr_t error) { usb_isoc_req_t *isoc_reqp = itw->itw_curr_xfer_reqp; usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; size_t length; uchar_t *buf; mblk_t *mp; ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, "ehci_sendup_itd_message:"); ASSERT(itw != NULL); length = itw->itw_length; /* Copy the data into the mblk_t */ buf = (uchar_t *)itw->itw_buf; USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, "ehci_sendup_itd_message: length %d error %d", length, error); /* Get the message block */ mp = isoc_reqp->isoc_data; ASSERT(mp != NULL); if (length) { /* Sync IO buffer */ Sync_IO_Buffer(itw->itw_dmahandle, length); /* Copy the data into the message */ bcopy(buf, mp->b_rptr, length); /* Increment the write pointer */ mp->b_wptr = mp->b_wptr + length; } else { USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, "ehci_sendup_itd_message: Zero length packet"); } ehci_hcdi_isoc_callback(ph, itw, error); }
/*ARGSUSED*/ static int uftdi_close_port(ds_hdl_t hdl, uint_t portno) { uftdi_state_t *uf = (uftdi_state_t *)hdl; USB_DPRINTF_L4(DPRINT_CLOSE, uf->uf_lh, "uftdi_close_port %d", portno); ASSERT(portno == 0); mutex_enter(&uf->uf_lock); /* free resources and finalize state */ freemsg(uf->uf_rx_mp); uf->uf_rx_mp = NULL; freemsg(uf->uf_tx_mp); uf->uf_tx_mp = NULL; uf->uf_port_state = UFTDI_PORT_CLOSED; mutex_exit(&uf->uf_lock); uftdi_pm_set_idle(uf); return (USB_SUCCESS); }
static int uftdi_send_data(uftdi_state_t *uf, mblk_t *data) { usb_bulk_req_t *br; int len = MBLKL(data); int rval; USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_send_data: %d 0x%x 0x%x 0x%x", len, data->b_rptr[0], (len > 1) ? data->b_rptr[1] : 0, (len > 2) ? data->b_rptr[2] : 0); ASSERT(!mutex_owned(&uf->uf_lock)); br = usb_alloc_bulk_req(uf->uf_dip, 0, USB_FLAGS_SLEEP); br->bulk_data = data; br->bulk_len = len; br->bulk_timeout = UFTDI_BULKOUT_TIMEOUT; br->bulk_cb = uftdi_bulkout_cb; br->bulk_exc_cb = uftdi_bulkout_cb; br->bulk_client_private = (usb_opaque_t)uf; br->bulk_attributes = USB_ATTRS_AUTOCLEARING; rval = usb_pipe_bulk_xfer(uf->uf_bulkout_ph, br, 0); if (rval != USB_SUCCESS) { USB_DPRINTF_L2(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_send_data: xfer failed %d", rval); br->bulk_data = NULL; usb_free_bulk_req(br); } return (rval); }
/* * start receiving data */ static int uftdi_rx_start(uftdi_state_t *uf) { usb_bulk_req_t *br; int rval; USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_rx_start"); ASSERT(mutex_owned(&uf->uf_lock)); uf->uf_bulkin_state = UFTDI_PIPE_BUSY; mutex_exit(&uf->uf_lock); br = usb_alloc_bulk_req(uf->uf_dip, uf->uf_xfer_sz, USB_FLAGS_SLEEP); br->bulk_len = uf->uf_xfer_sz; br->bulk_timeout = UFTDI_BULKIN_TIMEOUT; br->bulk_cb = uftdi_bulkin_cb; br->bulk_exc_cb = uftdi_bulkin_cb; br->bulk_client_private = (usb_opaque_t)uf; br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK; rval = usb_pipe_bulk_xfer(uf->uf_bulkin_ph, br, 0); if (rval != USB_SUCCESS) { USB_DPRINTF_L2(DPRINT_IN_PIPE, uf->uf_lh, "uftdi_rx_start: xfer failed %d", rval); usb_free_bulk_req(br); } mutex_enter(&uf->uf_lock); if (rval != USB_SUCCESS) uf->uf_bulkin_state = UFTDI_PIPE_IDLE; return (rval); }
/*ARGSUSED*/ static void uftdi_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) { uftdi_state_t *uf = (uftdi_state_t *)req->bulk_client_private; int data_len; mblk_t *data = req->bulk_data; data_len = data ? MBLKL(data) : 0; USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_bulkout_cb: cr=%d len=%d", req->bulk_completion_reason, data_len); if (uf->uf_port_state == UFTDI_PORT_OPEN && req->bulk_completion_reason && data_len > 0) { uftdi_put_head(&uf->uf_tx_mp, data); req->bulk_data = NULL; } usb_free_bulk_req(req); /* notify GSD */ if (uf->uf_cb.cb_tx) uf->uf_cb.cb_tx(uf->uf_cb.cb_arg); /* send more */ mutex_enter(&uf->uf_lock); uf->uf_bulkout_state = UFTDI_PIPE_IDLE; if (uf->uf_tx_mp == NULL) cv_broadcast(&uf->uf_tx_cv); else uftdi_tx_start(uf, NULL); mutex_exit(&uf->uf_lock); }
static int uftdi_pwrlvl3(uftdi_state_t *uf) { int rval; USB_DPRINTF_L4(DPRINT_PM, uf->uf_lh, "uftdi_pwrlvl3"); switch (uf->uf_dev_state) { case USB_DEV_PWRED_DOWN: /* Issue USB D0 command to the device here */ rval = usb_set_device_pwrlvl0(uf->uf_dip); ASSERT(rval == USB_SUCCESS); uf->uf_dev_state = USB_DEV_ONLINE; uf->uf_pm->pm_cur_power = USB_DEV_OS_FULL_PWR; /*FALLTHROUGH*/ case USB_DEV_ONLINE: /* we are already in full power */ /*FALLTHROUGH*/ case USB_DEV_DISCONNECTED: case USB_DEV_SUSPENDED: return (USB_SUCCESS); default: USB_DPRINTF_L2(DPRINT_PM, uf->uf_lh, "uftdi_pwrlvl3: illegal device state"); return (USB_FAILURE); } }
/* * ehci_reclaim_isoc: * * "Reclaim" itds that were marked as RECLAIM. */ static void ehci_reclaim_isoc( ehci_state_t *ehcip, ehci_isoc_xwrapper_t *itw, ehci_itd_t *itd, ehci_pipe_private_t *pp) { USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, "ehci_reclaim_isoc: itd = 0x%p", itd); /* * These are itds that were marked "RECLAIM" * by the pipe cleanup. * * Decrement the num_itds and the periodic in * request count if necessary. */ if ((--itw->itw_num_itds == 0) && (itw->itw_curr_xfer_reqp)) { if (itw->itw_direction == USB_EP_DIR_IN) { pp->pp_cur_periodic_req_cnt--; ehci_deallocate_isoc_in_resource(ehcip, pp, itw); } else { ehci_hcdi_isoc_callback(pp->pp_pipe_handle, itw, USB_CR_FLUSHED); } } /* Deallocate this transfer descriptor */ ehci_deallocate_itd(ehcip, itw, itd); }
/*ARGSUSED*/ static int uftdi_fifo_flush(ds_hdl_t hdl, uint_t portno, int dir) { uftdi_state_t *uf = (uftdi_state_t *)hdl; ASSERT(portno == 0); USB_DPRINTF_L4(DPRINT_CTLOP, uf->uf_lh, "uftdi_fifo_flush: dir=0x%x", dir); mutex_enter(&uf->uf_lock); ASSERT(uf->uf_port_state == UFTDI_PORT_OPEN); if (dir & DS_TX) { freemsg(uf->uf_tx_mp); uf->uf_tx_mp = NULL; } if (dir & DS_RX) { freemsg(uf->uf_rx_mp); uf->uf_rx_mp = NULL; } mutex_exit(&uf->uf_lock); if (dir & DS_TX) (void) uftdi_cmd_vendor_write0(uf, FTDI_SIO_RESET, FTDI_SIO_RESET_PURGE_TX, uf->uf_hwport); if (dir & DS_RX) (void) uftdi_cmd_vendor_write0(uf, FTDI_SIO_RESET, FTDI_SIO_RESET_PURGE_RX, uf->uf_hwport); return (USB_SUCCESS); }
/* * ehci_hcdi_get_max_isoc_pkts: * * Return maximum isochronous packets per usb isochronous request */ uint_t ehci_hcdi_get_max_isoc_pkts(usba_device_t *usba_device) { ehci_state_t *ehcip = ehci_obtain_state( usba_device->usb_root_hub_dip); uint_t max_isoc_pkts_per_request; int rval; mutex_enter(&ehcip->ehci_int_mutex); rval = ehci_state_is_operational(ehcip); mutex_exit(&ehcip->ehci_int_mutex); if (rval != USB_SUCCESS) { return (rval); } max_isoc_pkts_per_request = EHCI_MAX_ISOC_PKTS_PER_XFER; USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, "ehci_hcdi_get_max_isoc_pkts: maximum isochronous" "packets per usb isochronous request = 0x%x", max_isoc_pkts_per_request); return (max_isoc_pkts_per_request); }
/*ARGSUSED*/ int ehci_hcdi_pipe_stop_isoc_polling( usba_pipe_handle_data_t *ph, usb_flags_t flags) { ehci_state_t *ehcip = ehci_obtain_state( ph->p_usba_device->usb_root_hub_dip); int rval; USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, "ehci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x", (void *)ph, flags); mutex_enter(&ehcip->ehci_int_mutex); rval = ehci_state_is_operational(ehcip); if (rval != USB_SUCCESS) { mutex_exit(&ehcip->ehci_int_mutex); return (rval); } rval = ehci_stop_periodic_pipe_polling(ehcip, ph, flags); mutex_exit(&ehcip->ehci_int_mutex); return (rval); }
/* * Functions to handle power transition for OS levels 0 -> 3 * The same level as OS state, different from USB state */ static int uftdi_pwrlvl0(uftdi_state_t *uf) { int rval; USB_DPRINTF_L4(DPRINT_PM, uf->uf_lh, "uftdi_pwrlvl0"); switch (uf->uf_dev_state) { case USB_DEV_ONLINE: /* issue USB D3 command to the device */ rval = usb_set_device_pwrlvl3(uf->uf_dip); ASSERT(rval == USB_SUCCESS); uf->uf_dev_state = USB_DEV_PWRED_DOWN; uf->uf_pm->pm_cur_power = USB_DEV_OS_PWR_OFF; /*FALLTHROUGH*/ case USB_DEV_DISCONNECTED: case USB_DEV_SUSPENDED: /* allow a disconnect/cpr'ed device to go to lower power */ return (USB_SUCCESS); case USB_DEV_PWRED_DOWN: default: USB_DPRINTF_L2(DPRINT_PM, uf->uf_lh, "uftdi_pwrlvl0: illegal device state"); return (USB_FAILURE); } }
/* * ehci_hcdi_get_current_frame_number: * * Return the current usb frame number */ usb_frame_number_t ehci_hcdi_get_current_frame_number(usba_device_t *usba_device) { ehci_state_t *ehcip = ehci_obtain_state( usba_device->usb_root_hub_dip); usb_frame_number_t frame_number; int rval; ehcip = ehci_obtain_state(usba_device->usb_root_hub_dip); mutex_enter(&ehcip->ehci_int_mutex); rval = ehci_state_is_operational(ehcip); if (rval != USB_SUCCESS) { mutex_exit(&ehcip->ehci_int_mutex); return (rval); } frame_number = ehci_get_current_frame_number(ehcip); mutex_exit(&ehcip->ehci_int_mutex); USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, "ehci_hcdi_get_current_frame_number: " "Current frame number 0x%llx", frame_number); return (frame_number); }
/* ARGSUSED */ int ehci_hcdi_bulk_transfer_size( usba_device_t *usba_device, size_t *size) { ehci_state_t *ehcip = ehci_obtain_state( usba_device->usb_root_hub_dip); int rval; USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, "ehci_hcdi_bulk_transfer_size:"); mutex_enter(&ehcip->ehci_int_mutex); rval = ehci_state_is_operational(ehcip); mutex_exit(&ehcip->ehci_int_mutex); if (rval != USB_SUCCESS) { return (rval); } /* VIA VT6202 may not handle bigger xfers well, workaround. */ if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && (ehci_vt62x2_workaround & EHCI_VIA_REDUCED_MAX_BULK_XFER_SIZE)) { *size = EHCI_VIA_MAX_BULK_XFER_SIZE; } else { *size = EHCI_MAX_BULK_XFER_SIZE; } return (USB_SUCCESS); }
/* ARGSUSED */ int ehci_hcdi_pipe_reset( usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) { ehci_state_t *ehcip = ehci_obtain_state( ph->p_usba_device->usb_root_hub_dip); ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; int error = USB_SUCCESS; USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, "ehci_hcdi_pipe_reset:"); /* * Check and handle root hub pipe reset. */ if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { error = ehci_handle_root_hub_pipe_reset(ph, usb_flags); return (error); } mutex_enter(&ehcip->ehci_int_mutex); /* Set pipe state to pipe reset */ pp->pp_state = EHCI_PIPE_STATE_RESET; ehci_pipe_cleanup(ehcip, ph); mutex_exit(&ehcip->ehci_int_mutex); return (error); }
/* * ehci_insert_isoc_req: * * Insert an isochronous request into the Host Controller's * isochronous list. */ int ehci_insert_isoc_req( ehci_state_t *ehcip, ehci_pipe_private_t *pp, ehci_isoc_xwrapper_t *itw, usb_flags_t usb_flags) { int error; USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, "ehci_insert_isoc_req: flags = 0x%x port status = 0x%x", usb_flags, itw->itw_port_status); ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); ASSERT(itw->itw_curr_xfer_reqp != NULL); ASSERT(itw->itw_curr_xfer_reqp->isoc_pkt_descr != NULL); /* * Save address of first usb isochronous packet descriptor. */ itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr; if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) { error = USB_NOT_SUPPORTED; } else { error = ehci_insert_sitd_req(ehcip, pp, itw, usb_flags); } return (error); }
/* * wusb_df_disconnect_callback: * Called when device hotplug-removed. * Close pipes. (This does not attempt to contact device.) * Set state to DISCONNECTED */ static int wusb_df_disconnect_callback(dev_info_t *dip) { int instance = ddi_get_instance(dip); wusb_df_state_t *wusb_dfp = ddi_get_soft_state(wusb_df_statep, instance); USB_DPRINTF_L4(PRINT_MASK_CB, wusb_dfp->wusb_df_log_hdl, "disconnect: enter"); mutex_enter(&wusb_dfp->wusb_df_mutex); (void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG); /* * Save any state of device or IO in progress required by * wusb_df_restore_device_state for proper device "thawing" later. */ wusb_dfp->wusb_df_dev_state = USB_DEV_DISCONNECTED; wusb_df_release_access(wusb_dfp); mutex_exit(&wusb_dfp->wusb_df_mutex); return (USB_SUCCESS); }
/* * wusb_df_init_power_mgmt: * Initialize power management and remote wakeup functionality. * No mutex is necessary in this function as it's called only by attach. */ static void wusb_df_init_power_mgmt(wusb_df_state_t *wusb_dfp) { wusb_df_power_t *wusb_dfpm; uint_t pwr_states; USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "init_power_mgmt enter"); /* * If remote wakeup is not available you may not want to do * power management. */ /* Allocate the state structure */ wusb_dfpm = kmem_zalloc(sizeof (wusb_df_power_t), KM_SLEEP); wusb_dfp->wusb_df_pm = wusb_dfpm; wusb_dfpm->wusb_df_state = wusb_dfp; wusb_dfpm->wusb_df_pm_capabilities = 0; wusb_dfpm->wusb_df_current_power = USB_DEV_OS_FULL_PWR; if (usb_create_pm_components(wusb_dfp->wusb_df_dip, &pwr_states) == USB_SUCCESS) { USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_init_power_mgmt: created PM components"); wusb_dfpm->wusb_df_pwr_states = (uint8_t)pwr_states; (void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_FULL_PWR); if (usb_handle_remote_wakeup(wusb_dfp->wusb_df_dip, USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { wusb_dfpm->wusb_df_wakeup_enabled = 1; } else { USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_init_power_mgmt:" "fail to enable remote wakeup"); } } else { USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_init_power_mgmt: create_pm_compts failed"); } USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_init_power_mgmt: end"); }
/* * ds_reconnect */ static int uftdi_reconnect(ds_hdl_t hdl) { uftdi_state_t *uf = (uftdi_state_t *)hdl; USB_DPRINTF_L4(DPRINT_HOTPLUG, uf->uf_lh, "uftdi_reconnect"); return (uftdi_restore_device_state(uf)); }
/*ARGSUSED*/ int usb_set_device_pwrlvl3(dev_info_t *dip) { USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, "usb_set_device_pwrlvl3 : Not Yet Implemented"); return (USB_SUCCESS); }
static int uftdi_pwrlvl2(uftdi_state_t *uf) { USB_DPRINTF_L4(DPRINT_PM, uf->uf_lh, "uftdi_pwrlvl2"); /* issue USB D1 command to the device */ (void) usb_set_device_pwrlvl1(uf->uf_dip); return (USB_FAILURE); }
/* * usb device driver unregistration */ void usb_unregister_dev_driver(dev_info_t *dip) { USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, "usb_unregister_dev_driver: unregister the registered " "driver: dip =0x%p", (void *)dip); ASSERT(dip == usb_cap.dip); usb_cap.dip = NULL; usb_cap.usba_dev_driver_cb = NULL; }
/* * ehci_hcdi_pipe_bulk_xfer: */ int ehci_hcdi_pipe_bulk_xfer( usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp, usb_flags_t usb_flags) { ehci_state_t *ehcip = ehci_obtain_state( ph->p_usba_device->usb_root_hub_dip); ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; int rval, error = USB_SUCCESS; ehci_trans_wrapper_t *tw; USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, "ehci_hcdi_pipe_bulk_xfer: ph = 0x%p reqp = 0x%p flags = %x", (void *)ph, bulk_reqp, usb_flags); mutex_enter(&ehcip->ehci_int_mutex); rval = ehci_state_is_operational(ehcip); if (rval != USB_SUCCESS) { mutex_exit(&ehcip->ehci_int_mutex); return (rval); } /* * Check whether pipe is in halted state. */ if (pp->pp_state == EHCI_PIPE_STATE_ERROR) { USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, "ehci_hcdi_pipe_bulk_xfer:" "Pipe is in error state, need pipe reset to continue"); mutex_exit(&ehcip->ehci_int_mutex); return (USB_FAILURE); } /* Allocate a transfer wrapper */ if ((tw = ehci_allocate_bulk_resources(ehcip, pp, bulk_reqp, usb_flags)) == NULL) { error = USB_NO_RESOURCES; } else { /* Add the QTD into the Host Controller's bulk list */ ehci_insert_bulk_req(ehcip, ph, bulk_reqp, tw, usb_flags); } mutex_exit(&ehcip->ehci_int_mutex); return (error); }
/* USBA framework initializations */ void usba_usbai_initialization() { usbai_log_handle = usb_alloc_log_hdl(NULL, "usbai", &usbai_errlevel, &usbai_errmask, NULL, 0); USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, "usba_usbai_initialization"); mutex_init(&usba_print_mutex, NULL, MUTEX_DRIVER, NULL); mutex_init(&usbai_mutex, NULL, MUTEX_DRIVER, NULL); }
/* * ehci_hcdi_isoc_callback: * * Convenience wrapper around usba_hcdi_cb() other than root hub. */ void ehci_hcdi_isoc_callback( usba_pipe_handle_data_t *ph, ehci_isoc_xwrapper_t *itw, usb_cr_t completion_reason) { ehci_state_t *ehcip = ehci_obtain_state( ph->p_usba_device->usb_root_hub_dip); ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; usb_opaque_t curr_xfer_reqp; uint_t pipe_state = 0; USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, "ehci_hcdi_isoc_callback: ph = 0x%p, itw = 0x%p, cr = 0x%x", (void *)ph, itw, completion_reason); ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); /* Set the pipe state as per completion reason */ switch (completion_reason) { case USB_CR_OK: pipe_state = pp->pp_state; break; case USB_CR_NO_RESOURCES: case USB_CR_NOT_SUPPORTED: case USB_CR_PIPE_RESET: case USB_CR_STOPPED_POLLING: pipe_state = EHCI_PIPE_STATE_IDLE; break; case USB_CR_PIPE_CLOSING: break; } pp->pp_state = pipe_state; if (itw && itw->itw_curr_xfer_reqp) { curr_xfer_reqp = (usb_opaque_t)itw->itw_curr_xfer_reqp; itw->itw_curr_xfer_reqp = NULL; } else { ASSERT(pp->pp_client_periodic_in_reqp != NULL); curr_xfer_reqp = pp->pp_client_periodic_in_reqp; pp->pp_client_periodic_in_reqp = NULL; } ASSERT(curr_xfer_reqp != NULL); mutex_exit(&ehcip->ehci_int_mutex); usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason); mutex_enter(&ehcip->ehci_int_mutex); }
/* * ehci_isoc_pipe_cleanup * * Cleanup ehci isoc pipes. */ void ehci_isoc_pipe_cleanup( ehci_state_t *ehcip, usba_pipe_handle_data_t *ph) { ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; uint_t pipe_state = pp->pp_state; usb_cr_t completion_reason; USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph); ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); /* Stop all further processing */ ehci_mark_reclaim_isoc(ehcip, pp); /* * Wait for processing all completed transfers * and send result upstream/ */ ehci_wait_for_isoc_completion(ehcip, pp); /* Go ahead and remove all remaining itds if there are any */ ehci_remove_isoc_itds(ehcip, pp); switch (pipe_state) { case EHCI_PIPE_STATE_CLOSE: completion_reason = USB_CR_PIPE_CLOSING; break; case EHCI_PIPE_STATE_RESET: case EHCI_PIPE_STATE_STOP_POLLING: /* Set completion reason */ completion_reason = (pipe_state == EHCI_PIPE_STATE_RESET) ? USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING; /* Set pipe state to idle */ pp->pp_state = EHCI_PIPE_STATE_IDLE; break; } /* * Do the callback for the original client * periodic IN request. */ if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) { ehci_do_client_periodic_in_req_callback( ehcip, pp, completion_reason); } }
/* * wusb_df_destroy_power_mgmt: * Shut down and destroy power management and remote wakeup functionality. */ static void wusb_df_destroy_power_mgmt(wusb_df_state_t *wusb_dfp) { USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "destroy_power_mgmt enter"); ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex)); mutex_enter(&wusb_dfp->wusb_df_mutex); if (!wusb_dfp->wusb_df_pm) { mutex_exit(&wusb_dfp->wusb_df_mutex); return; } mutex_exit(&wusb_dfp->wusb_df_mutex); (void) wusb_df_pm_busy_component(wusb_dfp); mutex_enter(&wusb_dfp->wusb_df_mutex); if (wusb_dfp->wusb_df_dev_state != USB_DEV_DISCONNECTED) { if (wusb_dfp->wusb_df_pm->wusb_df_wakeup_enabled) { mutex_exit(&wusb_dfp->wusb_df_mutex); (void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_FULL_PWR); if (usb_handle_remote_wakeup(wusb_dfp->wusb_df_dip, USB_REMOTE_WAKEUP_DISABLE) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_destroy_power_mgmt: " "Error disabling rmt wakeup"); } mutex_enter(&wusb_dfp->wusb_df_mutex); } } mutex_exit(&wusb_dfp->wusb_df_mutex); /* * Since remote wakeup is disabled now, * no one can raise power * and get to device once power is lowered here. */ (void) pm_lower_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_PWR_OFF); wusb_df_pm_idle_component(wusb_dfp); mutex_enter(&wusb_dfp->wusb_df_mutex); kmem_free(wusb_dfp->wusb_df_pm, sizeof (wusb_df_power_t)); wusb_dfp->wusb_df_pm = NULL; mutex_exit(&wusb_dfp->wusb_df_mutex); }
/* * wusb_df_cpr_suspend: * Clean up device. * Wait for any IO to finish, then close pipes. * Quiesce device. */ static int wusb_df_cpr_suspend(dev_info_t *dip) { int instance = ddi_get_instance(dip); wusb_df_state_t *wusb_dfp = ddi_get_soft_state(wusb_df_statep, instance); USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, "suspend enter"); /* Serialize to prevent races with detach, open, device access. */ mutex_enter(&wusb_dfp->wusb_df_mutex); (void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG); mutex_exit(&wusb_dfp->wusb_df_mutex); wusb_df_pm_busy_component(wusb_dfp); mutex_enter(&wusb_dfp->wusb_df_mutex); /* Access device here to clean it up. */ wusb_dfp->wusb_df_dev_state = USB_DEV_SUSPENDED; /* * Save any state of device required by wusb_df_restore_device_state * for proper device "thawing" later. */ wusb_df_release_access(wusb_dfp); mutex_exit(&wusb_dfp->wusb_df_mutex); wusb_df_pm_idle_component(wusb_dfp); USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, "suspend: success"); return (USB_SUCCESS); }
/* * scsa2usb_handle_status_start: * Receive status data */ static int scsa2usb_handle_status_start(scsa2usb_state_t *scsa2usbp, usb_bulk_req_t *req) { int rval; USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle, "scsa2usb_handle_status_start: req = 0x%p", (void *)req); ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex)); /* setup up for receiving CSW */ #ifdef SCSA2USB_BULK_ONLY_TEST req->bulk_attributes = 0; #else req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK; #endif /* SCSA2USB_BULK_ONLY_TEST */ req->bulk_len = CSW_LEN; SCSA2USB_FREE_MSG(req->bulk_data); req->bulk_data = allocb_wait(req->bulk_len, BPRI_LO, STR_NOSIG, NULL); /* Issue the request */ mutex_exit(&scsa2usbp->scsa2usb_mutex); ASSERT(req->bulk_timeout); rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe, req, USB_FLAGS_SLEEP); mutex_enter(&scsa2usbp->scsa2usb_mutex); USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle, "scsa2usb_handle_status_start: END rval = 0x%x", rval); if (rval != USB_SUCCESS) { if (scsa2usbp->scsa2usb_pkt_state == SCSA2USB_PKT_PROCESS_CSW) { scsa2usb_bulk_only_reset_recovery(scsa2usbp); return (rval); } if (req->bulk_completion_reason == USB_CR_STALL) { (void) scsa2usb_clear_ept_stall(scsa2usbp, scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress, scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in"); } } return (rval); }