Пример #1
0
/* 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__);
}
Пример #2
0
/*
 * 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;
}