コード例 #1
0
int musb_hub_control(
	struct usb_hcd	*hcd,
	u16		typeReq,
	u16		wValue,
	u16		wIndex,
	char		*buf,
	u16		wLength)
{
	struct musb	*musb = hcd_to_musb(hcd);
	u32		temp;
	int		retval = 0;
	unsigned long	flags;

	spin_lock_irqsave(&musb->lock, flags);

	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
		spin_unlock_irqrestore(&musb->lock, flags);
		return -ESHUTDOWN;
	}

	/* hub features:  always zero, setting is a NOP
	 * port features: reported, sometimes updated when host is active
	 * no indicators
	 */
	switch (typeReq) {
	case ClearHubFeature:
	case SetHubFeature:
		switch (wValue) {
		case C_HUB_OVER_CURRENT:
		case C_HUB_LOCAL_POWER:
			break;
		default:
			goto error;
		}
		break;
	case ClearPortFeature:
		if ((wIndex & 0xff) != 1)
			goto error;

		switch (wValue) {
		case USB_PORT_FEAT_ENABLE:
			break;
		case USB_PORT_FEAT_SUSPEND:
			musb_port_suspend(musb, false);
			break;
		case USB_PORT_FEAT_POWER:
			if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
				musb_set_vbus(musb, 0);
			break;
		case USB_PORT_FEAT_C_CONNECTION:
		case USB_PORT_FEAT_C_ENABLE:
		case USB_PORT_FEAT_C_OVER_CURRENT:
		case USB_PORT_FEAT_C_RESET:
		case USB_PORT_FEAT_C_SUSPEND:
			break;
		default:
			goto error;
		}
		DBG(5, "clear feature %d\n", wValue);
		musb->port1_status &= ~(1 << wValue);
		break;
	case GetHubDescriptor:
		{
		struct usb_hub_descriptor *desc = (void *)buf;

		desc->bDescLength = 9;
		desc->bDescriptorType = 0x29;
		desc->bNbrPorts = 1;
		desc->wHubCharacteristics = cpu_to_le16(
				  0x0001	/* per-port power switching */
				| 0x0010	/* no overcurrent reporting */
				);
		desc->bPwrOn2PwrGood = 5;	/* msec/2 */
		desc->bHubContrCurrent = 0;

		/* workaround bogus struct definition */
		desc->DeviceRemovable[0] = 0x02;	/* port 1 */
		desc->DeviceRemovable[1] = 0xff;
		}
		break;
	case GetHubStatus:
		temp = 0;
		*(__le32 *) buf = cpu_to_le32(temp);
		break;
	case GetPortStatus:
		if (wIndex != 1)
			goto error;

		/* finish RESET signaling? */
		if ((musb->port1_status & USB_PORT_STAT_RESET)
				&& time_after_eq(jiffies, musb->rh_timer))
			musb_port_reset(musb, false);

		/* finish RESUME signaling? */
		if ((musb->port1_status & MUSB_PORT_STAT_RESUME)
				&& time_after_eq(jiffies, musb->rh_timer)) {
			u8		power;

			power = musb_readb(musb->mregs, MUSB_POWER);
			power &= ~MUSB_POWER_RESUME;
			DBG(4, "root port resume stopped, power %02x\n",
					power);
			musb_writeb(musb->mregs, MUSB_POWER, power);

			/* ISSUE:  DaVinci (RTL 1.300) disconnects after
			 * resume of high speed peripherals (but not full
			 * speed ones).
			 */

			musb->is_active = 1;
			musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
					| MUSB_PORT_STAT_RESUME);
			musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
			usb_hcd_poll_rh_status(musb_to_hcd(musb));
			/* NOTE: it might really be A_WAIT_BCON ... */
			musb->xceiv->state = OTG_STATE_A_HOST;
		}

		put_unaligned(cpu_to_le32(musb->port1_status
					& ~MUSB_PORT_STAT_RESUME),
				(__le32 *) buf);

		/* port change status is more interesting */
		DBG(get_unaligned((u16 *)(buf+2)) ? 2 : 5, "port status %08x\n",
				musb->port1_status);
		break;
	case SetPortFeature:
		if ((wIndex & 0xff) != 1)
			goto error;

		switch (wValue) {
		case USB_PORT_FEAT_POWER:
			/* NOTE: this controller has a strange state machine
			 * that involves "requesting sessions" according to
			 * magic side effects from incompletely-described
			 * rules about startup...
			 *
			 * This call is what really starts the host mode; be
			 * very careful about side effects if you reorder any
			 * initialization logic, e.g. for OTG, or change any
			 * logic relating to VBUS power-up.
			 */
			if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
				musb_start(musb);
			break;
		case USB_PORT_FEAT_RESET:
			musb_port_reset(musb, true);
			break;
		case USB_PORT_FEAT_SUSPEND:
			musb_port_suspend(musb, true);
			break;
		case USB_PORT_FEAT_TEST:
			wIndex >>= 8;
			switch (wIndex) {
			case 1:
				pr_debug("TEST_J\n");
				temp = MUSB_TEST_J;
				break;
			case 2:
				pr_debug("TEST_K\n");
				temp = MUSB_TEST_K;
				break;
			case 3:
				pr_debug("TEST_SE0_NAK\n");
				temp = MUSB_TEST_SE0_NAK;
				break;
			case 4:
				pr_debug("TEST_PACKET\n");
				temp = MUSB_TEST_PACKET;
				musb_load_testpacket(musb);
				break;
			case 5:
				pr_debug("TEST_FORCE_ENABLE\n");
				temp = MUSB_TEST_FORCE_HOST
					| MUSB_TEST_FORCE_HS;

				musb_writeb(musb->mregs, MUSB_DEVCTL,
						MUSB_DEVCTL_SESSION);
				break;
			case 6:
				pr_debug("TEST_FIFO_ACCESS\n");
				temp = MUSB_TEST_FIFO_ACCESS;
				break;
			default:
				goto error;
			}
			musb_writeb(musb->mregs, MUSB_TESTMODE, temp);
			break;
		default:
			goto error;
		}
		DBG(5, "set feature %d\n", wValue);
		musb->port1_status |= 1 << wValue;
		break;

	default:
error:
		/* "protocol stall" on error */
		retval = -EPIPE;
	}
	spin_unlock_irqrestore(&musb->lock, flags);
	return retval;
}
コード例 #2
0
ファイル: musb_virthub.c プロジェクト: jgroen/rtt_tests
int musb_hub_control(
	struct usb_hcd	*hcd,
	u16		typeReq,
	u16		wValue,
	u16		wIndex,
	char		*buf,
	u16		wLength)
{
	struct musb	*musb = hcd_to_musb(hcd);
	u32		temp;
	int		retval = 0;
	unsigned long	flags;

	spin_lock_irqsave(&musb->lock, flags);

	if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) {
		spin_unlock_irqrestore(&musb->lock, flags);
		return -ESHUTDOWN;
	}

	/* hub features:  always zero, setting is a NOP
	 * port features: reported, sometimes updated when host is active
	 * no indicators
	 */
	switch (typeReq) {
	case ClearHubFeature:
	case SetHubFeature:
		switch (wValue) {
		case C_HUB_OVER_CURRENT:
		case C_HUB_LOCAL_POWER:
			break;
		default:
			goto error;
		}
		break;
	case ClearPortFeature:
		if ((wIndex & 0xff) != 1)
			goto error;

		switch (wValue) {
		case USB_PORT_FEAT_ENABLE:
			break;
		case USB_PORT_FEAT_SUSPEND:
			musb_port_suspend(musb, false);
			break;
		case USB_PORT_FEAT_POWER:
			if (!hcd->self.is_b_host)
				musb_platform_set_vbus(musb, 0);
			break;
		case USB_PORT_FEAT_C_CONNECTION:
		case USB_PORT_FEAT_C_ENABLE:
		case USB_PORT_FEAT_C_OVER_CURRENT:
		case USB_PORT_FEAT_C_RESET:
		case USB_PORT_FEAT_C_SUSPEND:
			break;
		default:
			goto error;
		}
		dev_dbg(musb->controller, "clear feature %d\n", wValue);
		musb->port1_status &= ~(1 << wValue);
		break;
	case GetHubDescriptor:
		{
		struct usb_hub_descriptor *desc = (void *)buf;

		desc->bDescLength = 9;
		desc->bDescriptorType = 0x29;
		desc->bNbrPorts = 1;
		desc->wHubCharacteristics = cpu_to_le16(
				  0x0001	/* per-port power switching */
				| 0x0010	/* no overcurrent reporting */
				);
		desc->bPwrOn2PwrGood = 5;	/* msec/2 */
		desc->bHubContrCurrent = 0;

		/* workaround bogus struct definition */
		desc->u.hs.DeviceRemovable[0] = 0x02;	/* port 1 */
		desc->u.hs.DeviceRemovable[1] = 0xff;
		}
		break;
	case GetHubStatus:
		temp = 0;
		*(__le32 *) buf = cpu_to_le32(temp);
		break;
	case GetPortStatus:
		if (wIndex != 1)
			goto error;

		put_unaligned(cpu_to_le32(musb->port1_status
					& ~MUSB_PORT_STAT_RESUME),
				(__le32 *) buf);

		/* port change status is more interesting */
		dev_dbg(musb->controller, "port status %08x\n",
				musb->port1_status);
		break;
	case SetPortFeature:
		if ((wIndex & 0xff) != 1)
			goto error;

		switch (wValue) {
		case USB_PORT_FEAT_POWER:
			/* NOTE: this controller has a strange state machine
			 * that involves "requesting sessions" according to
			 * magic side effects from incompletely-described
			 * rules about startup...
			 *
			 * This call is what really starts the host mode; be
			 * very careful about side effects if you reorder any
			 * initialization logic, e.g. for OTG, or change any
			 * logic relating to VBUS power-up.
			 */
			if (!hcd->self.is_b_host && musb_has_gadget(musb))
				musb_start(musb);
			break;
		case USB_PORT_FEAT_RESET:
			musb_port_reset(musb, true);
			break;
		case USB_PORT_FEAT_SUSPEND:
			musb_port_suspend(musb, true);
			break;
		case USB_PORT_FEAT_TEST:
			if (unlikely(is_host_active(musb)))
				goto error;

			wIndex >>= 8;
			switch (wIndex) {
			case 1:
				pr_debug("TEST_J\n");
				temp = MUSB_TEST_J;
				break;
			case 2:
				pr_debug("TEST_K\n");
				temp = MUSB_TEST_K;
				break;
			case 3:
				pr_debug("TEST_SE0_NAK\n");
				temp = MUSB_TEST_SE0_NAK;
				break;
			case 4:
				pr_debug("TEST_PACKET\n");
				temp = MUSB_TEST_PACKET;
				musb_load_testpacket(musb);
				break;
			case 5:
				pr_debug("TEST_FORCE_ENABLE\n");
				temp = MUSB_TEST_FORCE_HOST
					| MUSB_TEST_FORCE_HS;

				musb_writeb(musb->mregs, MUSB_DEVCTL,
						MUSB_DEVCTL_SESSION);
				break;
			case 6:
				pr_debug("TEST_FIFO_ACCESS\n");
				temp = MUSB_TEST_FIFO_ACCESS;
				break;
			default:
				goto error;
			}
			musb_writeb(musb->mregs, MUSB_TESTMODE, temp);
			break;
		default:
			goto error;
		}
		dev_dbg(musb->controller, "set feature %d\n", wValue);
		musb->port1_status |= 1 << wValue;
		break;

	default:
error:
		/* "protocol stall" on error */
		retval = -EPIPE;
	}
	spin_unlock_irqrestore(&musb->lock, flags);
	return retval;
}
コード例 #3
0
/*
 * root hub control
 */
static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
                              void *buffer, int transfer_len,
                              struct devrequest *cmd)
{
    int leni = transfer_len;
    int len = 0;
    int stat = 0;
    u32 datab[4];
    const u8 *data_buf = (u8 *) datab;
    u16 bmRType_bReq;
    u16 wValue;
    u16 wIndex;
    u16 wLength;
    u16 int_usb;

    if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
        debug("Root-Hub submit IRQ: NOT implemented\n");
        return 0;
    }

    bmRType_bReq = cmd->requesttype | (cmd->request << 8);
    wValue = swap_16(cmd->value);
    wIndex = swap_16(cmd->index);
    wLength = swap_16(cmd->length);

    debug("--- HUB ----------------------------------------\n");
    debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n",
          bmRType_bReq, wValue, wIndex, wLength);
    debug("------------------------------------------------\n");

    switch (bmRType_bReq) {
    case RH_GET_STATUS:
        debug("RH_GET_STATUS\n");

        *(__u16 *) data_buf = swap_16(1);
        len = 2;
        break;

    case RH_GET_STATUS | RH_INTERFACE:
        debug("RH_GET_STATUS | RH_INTERFACE\n");

        *(__u16 *) data_buf = swap_16(0);
        len = 2;
        break;

    case RH_GET_STATUS | RH_ENDPOINT:
        debug("RH_GET_STATUS | RH_ENDPOINT\n");

        *(__u16 *) data_buf = swap_16(0);
        len = 2;
        break;

    case RH_GET_STATUS | RH_CLASS:
        debug("RH_GET_STATUS | RH_CLASS\n");

        *(__u32 *) data_buf = swap_32(0);
        len = 4;
        break;

    case RH_GET_STATUS | RH_OTHER | RH_CLASS:
        debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n");

        int_usb = readw(&musbr->intrusb);
        if (int_usb & MUSB_INTR_CONNECT) {
            port_status |= USB_PORT_STAT_CONNECTION
                           | (USB_PORT_STAT_C_CONNECTION << 16);
            port_status |= USB_PORT_STAT_HIGH_SPEED
                           | USB_PORT_STAT_ENABLE;
        }

        if (port_status & USB_PORT_STAT_RESET)
            musb_port_reset(0);

        *(__u32 *) data_buf = swap_32(port_status);
        len = 4;
        break;

    case RH_CLEAR_FEATURE | RH_ENDPOINT:
        debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n");

        switch (wValue) {
        case RH_ENDPOINT_STALL:
            debug("C_HUB_ENDPOINT_STALL\n");
            len = 0;
            break;
        }
        port_status &= ~(1 << wValue);
        break;

    case RH_CLEAR_FEATURE | RH_CLASS:
        debug("RH_CLEAR_FEATURE | RH_CLASS\n");

        switch (wValue) {
        case RH_C_HUB_LOCAL_POWER:
            debug("C_HUB_LOCAL_POWER\n");
            len = 0;
            break;

        case RH_C_HUB_OVER_CURRENT:
            debug("C_HUB_OVER_CURRENT\n");
            len = 0;
            break;
        }
        port_status &= ~(1 << wValue);
        break;

    case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
        debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n");

        switch (wValue) {
        case RH_PORT_ENABLE:
            len = 0;
            break;

        case RH_PORT_SUSPEND:
            len = 0;
            break;

        case RH_PORT_POWER:
            len = 0;
            break;

        case RH_C_PORT_CONNECTION:
            len = 0;
            break;

        case RH_C_PORT_ENABLE:
            len = 0;
            break;

        case RH_C_PORT_SUSPEND:
            len = 0;
            break;

        case RH_C_PORT_OVER_CURRENT:
            len = 0;
            break;

        case RH_C_PORT_RESET:
            len = 0;
            break;

        default:
            debug("invalid wValue\n");
            stat = USB_ST_STALLED;
        }

        port_status &= ~(1 << wValue);
        break;

    case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
        debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n");

        switch (wValue) {
        case RH_PORT_SUSPEND:
            len = 0;
            break;

        case RH_PORT_RESET:
            musb_port_reset(1);
            len = 0;
            break;

        case RH_PORT_POWER:
            len = 0;
            break;

        case RH_PORT_ENABLE:
            len = 0;
            break;

        default:
            debug("invalid wValue\n");
            stat = USB_ST_STALLED;
        }

        port_status |= 1 << wValue;
        break;

    case RH_SET_ADDRESS:
        debug("RH_SET_ADDRESS\n");

        rh_devnum = wValue;
        len = 0;
        break;

    case RH_GET_DESCRIPTOR:
        debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength);

        switch (wValue) {
        case (USB_DT_DEVICE << 8):	/* device descriptor */
            len = min_t(unsigned int,
                        leni, min_t(unsigned int,
                                    sizeof(root_hub_dev_des),
                                    wLength));
            data_buf = root_hub_dev_des;
            break;

        case (USB_DT_CONFIG << 8):	/* configuration descriptor */
            len = min_t(unsigned int,
                        leni, min_t(unsigned int,
                                    sizeof(root_hub_config_des),
                                    wLength));
            data_buf = root_hub_config_des;
            break;

        case ((USB_DT_STRING << 8) | 0x00):	/* string 0 descriptors */
            len = min_t(unsigned int,
                        leni, min_t(unsigned int,
                                    sizeof(root_hub_str_index0),
                                    wLength));
            data_buf = root_hub_str_index0;
            break;

        case ((USB_DT_STRING << 8) | 0x01):	/* string 1 descriptors */
            len = min_t(unsigned int,
                        leni, min_t(unsigned int,
                                    sizeof(root_hub_str_index1),
                                    wLength));
            data_buf = root_hub_str_index1;
            break;

        default:
            debug("invalid wValue\n");
            stat = USB_ST_STALLED;
        }

        break;

    case RH_GET_DESCRIPTOR | RH_CLASS: {
        u8 *_data_buf = (u8 *) datab;
        debug("RH_GET_DESCRIPTOR | RH_CLASS\n");

        _data_buf[0] = 0x09;	/* min length; */
        _data_buf[1] = 0x29;
        _data_buf[2] = 0x1;	/* 1 port */
        _data_buf[3] = 0x01;	/* per-port power switching */
        _data_buf[3] |= 0x10;	/* no overcurrent reporting */

        /* Corresponds to data_buf[4-7] */
        _data_buf[4] = 0;
        _data_buf[5] = 5;
        _data_buf[6] = 0;
        _data_buf[7] = 0x02;
        _data_buf[8] = 0xff;

        len = min_t(unsigned int, leni,
                    min_t(unsigned int, data_buf[0], wLength));
        break;
    }

    case RH_GET_CONFIGURATION:
        debug("RH_GET_CONFIGURATION\n");

        *(__u8 *) data_buf = 0x01;
        len = 1;
        break;

    case RH_SET_CONFIGURATION:
        debug("RH_SET_CONFIGURATION\n");

        len = 0;
        break;

    default:
        debug("*** *** *** unsupported root hub command *** *** ***\n");
        stat = USB_ST_STALLED;
    }

    len = min_t(int, len, leni);
    if (buffer != data_buf)
        memcpy(buffer, data_buf, len);

    dev->act_len = len;
    dev->status = stat;
    debug("dev act_len %d, status %d\n", dev->act_len, dev->status);

    return stat;
}