/* disable the USB port by clearing the EN bit in the USBMOD register */ static void usb_port_disable(struct fhci_hcd *fhci) { struct fhci_usb *usb = (struct fhci_usb *)fhci->usb_lld; enum fhci_port_status port_status; fhci_dbg(fhci, "-> %s\n", __func__); fhci_stop_sof_timer(fhci); flush_all_transmissions(usb); config_transceiver(fhci, FHCI_OP_POWER_OFF); fhci_usb_disable_interrupt((struct fhci_usb *)fhci->usb_lld); port_status = usb->port_status; usb->port_status = FHCI_PORT_DISABLED; /* Enable IDLE since we want to know if something comes along */ usb->saved_msk |= USB_E_IDLE_MASK; out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); /* check if during the disconnection process attached new device */ if (port_status == FHCI_PORT_WAITING) device_connected_interrupt(fhci); usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_ENABLE; usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE; fhci_usb_enable_interrupt((struct fhci_usb *)fhci->usb_lld); fhci_dbg(fhci, "<- %s\n", __func__); }
/* * Submitting a data frame to a specified endpoint of a USB device * The frame is put in the driver's transmit queue for this endpoint * * Arguments: * usb A pointer to the USB structure * pkt A pointer to the user frame structure * trans_type Transaction tyep - IN,OUT or SETUP * dest_addr Device address - 0~127 * dest_ep Endpoint number of the device - 0~16 * trans_mode Pipe type - ISO,Interrupt,bulk or control * dest_speed USB speed - Low speed or FULL speed * data_toggle Data sequence toggle - 0 or 1 */ u32 fhci_host_transaction(struct fhci_usb *usb, struct packet *pkt, enum fhci_ta_type trans_type, u8 dest_addr, u8 dest_ep, enum fhci_tf_mode trans_mode, enum fhci_speed dest_speed, u8 data_toggle) { struct endpoint *ep = usb->ep0; struct usb_td __iomem *td; u16 extra_data; u16 td_status; fhci_usb_disable_interrupt(usb); /* start from the next BD that should be filled */ td = ep->empty_td; td_status = in_be16(&td->status); if (td_status & TD_R && in_be16(&td->length)) { /* if the TD is not free */ fhci_usb_enable_interrupt(usb); return -1; } /* get the next TD in the ring */ ep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status); fhci_usb_enable_interrupt(usb); pkt->priv_data = td; out_be32(&td->buf_ptr, virt_to_phys(pkt->data)); /* sets up transaction parameters - addr,endp,dir,and type */ extra_data = (dest_ep << TD_ENDP_SHIFT) | dest_addr; switch (trans_type) { case FHCI_TA_IN: extra_data |= TD_TOK_IN; break; case FHCI_TA_OUT: extra_data |= TD_TOK_OUT; break; case FHCI_TA_SETUP: extra_data |= TD_TOK_SETUP; break; } if (trans_mode == FHCI_TF_ISO) extra_data |= TD_ISO; out_be16(&td->extra, extra_data); /* sets up the buffer descriptor */ td_status = ((td_status & TD_W) | TD_R | TD_L | TD_I | TD_CNF); if (!(pkt->info & PKT_NO_CRC)) td_status |= TD_TC; switch (trans_type) { case FHCI_TA_IN: if (data_toggle) pkt->info |= PKT_PID_DATA1; else pkt->info |= PKT_PID_DATA0; break; default: if (data_toggle) { td_status |= TD_PID_DATA1; pkt->info |= PKT_PID_DATA1; } else { td_status |= TD_PID_DATA0; pkt->info |= PKT_PID_DATA0; } break; } if ((dest_speed == FHCI_LOW_SPEED) && (usb->port_status == FHCI_PORT_FULL)) td_status |= TD_LSP; out_be16(&td->status, td_status); /* set up buffer length */ if (trans_type == FHCI_TA_IN) out_be16(&td->length, pkt->len + CRC_SIZE); else out_be16(&td->length, pkt->len); /* put the frame to the confirmation queue */ cq_put(&ep->conf_frame_Q, pkt); if (cq_howmany(&ep->conf_frame_Q) == 1) out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO); return 0; }