コード例 #1
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* Dispatch an incoming Setup packet according to its type */
static void handle_setup(enum table_case tc)
{
	struct usb_setup_packet *req = cur_out_desc->addr;
	int data_phase_in = req->bmRequestType & USB_DIR_IN;
	int data_phase_out = !data_phase_in && req->wLength;
	int bytes = -1;				/* default is to stall */

	print_later("R: %02x %02x %04x %04x %04x",
		    req->bmRequestType, req->bRequest,
		    req->wValue, req->wIndex, req->wLength);

	if (0 == (req->bmRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))) {
		/* Standard Device requests */
		if (data_phase_in)
			bytes = handle_setup_with_in_stage(tc, req);
		else if (data_phase_out)
			bytes = handle_setup_with_out_stage(tc, req);
		else
			bytes = handle_setup_with_no_data_stage(tc, req);
	} else if (USB_RECIP_INTERFACE ==
		   (req->bmRequestType & USB_RECIP_MASK)) {
		/* Interface-specific requests */
		uint8_t iface = req->wIndex & 0xff;

		print_later("iface %d request (vs %d)",
			    iface, USB_IFACE_COUNT, 0, 0, 0);
		if (iface < USB_IFACE_COUNT) {
			bytes = usb_iface_request[iface](req);
			print_later("  iface returned %d", bytes, 0, 0, 0, 0);
		}
	} else {
		/* Something we need to add support for? */
		report_error(-1);
	}

	print_later("data_phase_in %d data_phase_out %d bytes %d",
		    !!data_phase_in, !!data_phase_out, bytes, 0, 0);

	/* We say "no" to unsupported and intentionally unhandled requests by
	 * stalling the Data and/or Status stage. */
	if (bytes < 0) {
		/* Stall both IN and OUT. SETUP will come through anyway. */
		stall_both_fifos();
	} else {
		if (data_phase_in)
			expect_data_phase_in(tc);
		else if (data_phase_out)
			expect_data_phase_out(tc);
		else
			expect_status_phase_in(tc);
	}
}
コード例 #2
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
static void expect_data_phase_out(enum table_case tc)
{
	print_later("expect_data_phase_out(%c)", "0ABCDE67"[tc], 0, 0, 0, 0);
	/* TODO: This is not yet supported */
	report_error(tc);
	expect_setup_packet();
}
コード例 #3
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* Now put those constants into the correct registers */
static void setup_data_fifos(void)
{
	int i;

	print_later("setup_data_fifos()", 0, 0, 0, 0, 0);

	/* Programmer's Guide, p31 */
	GR_USB_GRXFSIZ = RXFIFO_SIZE;			      /* RXFIFO */
	GR_USB_GNPTXFSIZ = (TXFIFO_SIZE << 16) | RXFIFO_SIZE; /* TXFIFO 0 */

	/* TXFIFO 1..15 */
	for (i = 1; i < MAX_NORMAL_EPS; i++)
		GR_USB_DIEPTXF(i) = ((TXFIFO_SIZE << 16) |
				     (RXFIFO_SIZE + i * TXFIFO_SIZE));

	/*
	 * TODO: The Programmer's Guide is confusing about when or whether to
	 * flush the FIFOs. Section 2.1.1.2 (p31) just says to flush. Section
	 * 2.2.2 (p55) says to stop all the FIFOs first, then flush. Section
	 * 7.5.4 (p162) says that flushing the RXFIFO at reset is not
	 * recommended at all.
	 *
	 * I'm also unclear on whether or not the individual EPs are expected
	 * to be disabled already (DIEPCTLn/DOEPCTLn.EPENA == 0), and if so,
	 * whether by firmware or hardware.
	 */

	/* Flush all FIFOs according to Section 2.1.1.2 */
	GR_USB_GRSTCTL = GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH
		| GRSTCTL_RXFFLSH;
	while (GR_USB_GRSTCTL & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH))
		;				/* TODO: timeout 100ms */
}
コード例 #4
0
ファイル: usb.c プロジェクト: littlebabay/chrome-ec
static void usb_resetdet(void)
{
	/* TODO: Same as normal reset, right? I think we only get this if we're
	 * suspended (sleeping) and the host resets us. Try it and see. */
	print_later("usb_resetdet()", 0, 0, 0, 0, 0);
	usb_reset();
}
コード例 #5
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
void usb_disconnect(void)
{
	print_later("usb_disconnect()", 0, 0, 0, 0, 0);
	GR_USB_DCTL |= DCTL_SFTDISCON;

	device_state = DS_DEFAULT;
	configuration_value = 0;
}
コード例 #6
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* Handle a Setup that comes with additional data for us. */
static int handle_setup_with_out_stage(enum table_case tc,
				       struct usb_setup_packet *req)
{
	print_later("handle_setup_with_out_stage(%c)", "0ABCDE67"[tc],
		    0, 0, 0, 0);

	/* TODO: We don't support any of these. We should. */
	return -1;
}
コード例 #7
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
static void usb_init_endpoints(void)
{
	int ep;

	print_later("usb_init_endpoints()", 0, 0, 0, 0, 0);

	/* Prepare to receive packets on EP0 */
	initialize_dma_buffers();
	expect_setup_packet();

	/* Reset the other endpoints */
	for (ep = 1; ep < USB_EP_COUNT; ep++)
		usb_ep_reset[ep]();
}
コード例 #8
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
static void usb_reset(void)
{
	CPRINTS("%s, status %x", __func__, GR_USB_GINTSTS);
	print_later("usb_reset()", 0, 0, 0, 0, 0);

	/* Clear our internal state */
	device_state = DS_DEFAULT;
	configuration_value = 0;

	/* Clear the device address */
	GWRITE_FIELD(USB, DCFG, DEVADDR, 0);

	/* Reinitialize all the endpoints */
	usb_init_endpoints();
}
コード例 #9
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* The next packet from the host should be a Setup packet. Get ready for it. */
static void expect_setup_packet(void)
{
	print_later("expect_setup_packet()", 0, 0, 0, 0, 0);

	what_am_i_doing = WAITING_FOR_SETUP_PACKET;

	next_out_desc->flags =
		DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE)
		| DOEPDMA_IOC | DOEPDMA_LAST;

	/* We don't care about IN packets right now, only OUT. */
	GR_USB_DAINTMSK |= DAINT_OUTEP(0);
	GR_USB_DAINTMSK &= ~DAINT_INEP(0);

	/* Let it run. We might need CNAK if we just got an OUT for status */
	GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
}
コード例 #10
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* We're complaining about something by stalling both IN and OUT packets,
 * but a SETUP packet will get through anyway, so prepare for it. */
static void stall_both_fifos(void)
{
	print_later("stall_both_fifos()", 0, 0, 0, 0, 0);

	what_am_i_doing = WAITING_FOR_SETUP_PACKET;

	next_out_desc->flags =
		DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE)
		| DOEPDMA_IOC | DOEPDMA_LAST;

	/* We don't care about IN packets right now, only OUT. */
	GR_USB_DAINTMSK |= DAINT_OUTEP(0);
	GR_USB_DAINTMSK &= ~DAINT_INEP(0);

	/* Stall both IN and OUT. The hardware will reset them when the next
	 * SETUP comes along. */
	GR_USB_DOEPCTL(0) = DXEPCTL_STALL | DXEPCTL_EPENA;
	flush_in_fifo();
	GR_USB_DIEPCTL(0) = DXEPCTL_STALL | DXEPCTL_EPENA;
}
コード例 #11
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* No Data phase, just Status phase (which is IN, since Setup is OUT) */
static void expect_status_phase_in(enum table_case tc)
{
	print_later("expect_status_phase_in(%c)", "0ABCDE67"[tc], 0, 0, 0, 0);

	what_am_i_doing = NO_DATA_STAGE;

	/* Expect a zero-length IN for the Status phase */
	(void) load_in_fifo(0, 0);

	/* We apparently have to do this every time we transmit anything */
	flush_in_fifo();

	/* I don't think we have to do this every time, but the Programmer's
	 * Guide says to, so...	*/
	GR_USB_DIEPDMA(0) = (uint32_t)(cur_in_desc);

	/* Blindly following instructions here, too. */
	if (tc == TABLE_CASE_C)
		GR_USB_DIEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
	else
		GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;

	/* The Programmer's Guide instructions for the Normal Two-Stage Control
	 * Transfer leave this next bit out, so we only need it if we intend to
	 * process an Exceptional Two-Stage Control Transfer. Because obviously
	 * we always know in advance what the host is going to do. Idiots. */

	/* Be prepared to get a new Setup packet during the Status phase */
	next_out_desc->flags =
		DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE)
		| DOEPDMA_IOC | DOEPDMA_LAST;

	/* We've already set GR_USB_DOEPDMA(0), so just enable it. */
	if (tc == TABLE_CASE_C)
		GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
	else
		GR_USB_DOEPCTL(0) = DXEPCTL_EPENA;

	/* Get an interrupt when either IN or OUT arrives */
	GR_USB_DAINTMSK |= (DAINT_OUTEP(0) | DAINT_INEP(0));
}
コード例 #12
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* Reset all this to a good starting state. */
static void initialize_dma_buffers(void)
{
	int i;

	print_later("initialize_dma_buffers()", 0, 0, 0, 0, 0);

	for (i = 0; i < NUM_OUT_BUFFERS; i++) {
		ep0_out_desc[i].addr = ep0_out_buf[i];
		ep0_out_desc[i].flags = DOEPDMA_BS_HOST_BSY;
	}
	next_out_idx = 0;
	next_out_desc = ep0_out_desc + next_out_idx;
	GR_USB_DOEPDMA(0) = (uint32_t)next_out_desc;
	/* cur_out_* will be updated when we get the first RX packet */

	for (i = 0; i < NUM_IN_PACKETS_AT_ONCE; i++) {
		ep0_in_desc[i].addr = ep0_in_buf + i * USB_MAX_PACKET_SIZE;
		ep0_in_desc[i].flags = DIEPDMA_BS_HOST_BSY;
	}
	cur_in_desc = ep0_in_desc;
	GR_USB_DIEPDMA(0) = (uint32_t)(cur_in_desc);
};
コード例 #13
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* The TX FIFO buffer is loaded. Start the Data phase. */
static void expect_data_phase_in(enum table_case tc)
{
	print_later("expect_data_phase_in(%c)", "0ABCDE67"[tc], 0, 0, 0, 0);

	what_am_i_doing = DATA_STAGE_IN;

	/* We apparently have to do this every time we transmit anything */
	flush_in_fifo();

	/* I don't think we have to do this every time, but the Programmer's
	 * Guide says to, so...	*/
	GR_USB_DIEPDMA(0) = (uint32_t)(cur_in_desc);

	/* Blindly following instructions here, too. */
	if (tc == TABLE_CASE_C)
		GR_USB_DIEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
	else
		GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;

	/*
	 * When the IN is done, we expect a zero-length OUT for the status
	 * phase but it could be an early SETUP instead. We'll have to deal
	 * with either one when it arrives.
	 */
	next_out_desc->flags =
		DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE)
		| DOEPDMA_IOC | DOEPDMA_LAST;

	/* And here's this jimmy rustler again... */
	if (tc == TABLE_CASE_C)
		GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
	else
		GR_USB_DOEPCTL(0) = DXEPCTL_EPENA;

	/* Get an interrupt when either IN or OUT arrives */
	GR_USB_DAINTMSK |= (DAINT_OUTEP(0) | DAINT_INEP(0));

}
コード例 #14
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* This handles both IN and OUT interrupts for EP0 */
static void ep0_interrupt(uint32_t intr_on_out, uint32_t intr_on_in)
{
	uint32_t doepint, diepint;
	enum table_case tc;
	int sr;

	/* Determine the interrupt cause and clear the bits quickly, but only
	 * if they really apply. I don't think they're trustworthy if we didn't
	 * actually get an interrupt. */
	doepint = GR_USB_DOEPINT(0);
	if (intr_on_out)
		GR_USB_DOEPINT(0) = doepint;
	diepint = GR_USB_DIEPINT(0);
	if (intr_on_in)
		GR_USB_DIEPINT(0) = diepint;

	print_later("doepint%c 0x%08x diepint%c 0x%08x what %d",
		    intr_on_out ? '!' : '_', doepint,
		    intr_on_in ? '!' : '_', diepint,
		    what_am_i_doing);

	/* Update current and pending RX FIFO buffers */
	if (intr_on_out && (doepint & DOEPINT_XFERCOMPL))
		got_RX_packet();

	/* Decode the situation according to Table 10-7 */
	tc = decode_table_10_7(doepint);
	sr = cur_out_desc->flags & DOEPDMA_SR;

	print_later("cur_out_idx %d flags 0x%08x case=%c SR=%d",
		    cur_out_idx, cur_out_desc->flags,
		    "0ABCDE67"[tc], !!sr, 0);

	switch (what_am_i_doing) {
	case WAITING_FOR_SETUP_PACKET:
		if (tc == TABLE_CASE_A || tc == TABLE_CASE_C) {
			if (sr) {
				handle_setup(tc);
			} else {
				report_error(tc);
				print_later("next_out_idx %d flags 0x%08x",
					    next_out_idx, next_out_desc->flags,
					    0, 0, 0);
				expect_setup_packet();
			}
		}
		/* This only happens if we're stalling, so keep doing it. */
		if (tc == TABLE_CASE_B) {
			print_later("Still waiting for Setup...",
				    0, 0, 0, 0, 0);
			stall_both_fifos();
		}
		break;

	case DATA_STAGE_IN:
		if (intr_on_in && (diepint & DIEPINT_XFERCOMPL)) {
			print_later("IN is complete? Maybe? How do we know?",
				    0, 0, 0, 0, 0);
			/* I don't *think* we need to do this, unless we need
			 * to transfer more data. Customer support agrees and
			 * it shouldn't matter if the host is well-behaved, but
			 * it seems like we had issues without it.
			 * TODO: Test this case until we know for sure. */
			GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;

			/*
			 * The Programmer's Guide says (p291) to stall any
			 * further INs, but that's stupid because it'll destroy
			 * the packet we just transferred to SPRAM, so don't do
			 * that (we tried it anyway, and Bad Things happened).
			 * Also don't stop here, but keep looking at stuff.
			 */
		}

		/* But we should ignore the OUT endpoint if we didn't actually
		 * get an OUT interrupt. */
		if (!intr_on_out)
			break;

		if (tc == TABLE_CASE_B) {
			print_later("IN has been detected...", 0, 0, 0, 0, 0);
			/* The first IN packet has been seen. Keep going. */
			GR_USB_DIEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
			GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
			break;
		}
		if (tc == TABLE_CASE_A) {
			if (!sr) {
				/* We've handled the Status phase. All done. */
				print_later("Status phase complete",
					    0, 0, 0, 0, 0);
				expect_setup_packet();
				break;
			}
			/* We expected an OUT, but got a Setup. Deal with it. */
			print_later("Early Setup", 0, 0, 0, 0, 0);
			handle_setup(tc);
			break;
		}
		/* From the Exceptional Control Read Transfer section ... */
		if (tc == TABLE_CASE_C) {
			if (sr) {
				print_later("Early Setup w/Data packet seen",
					    0, 0, 0, 0, 0);
				handle_setup(tc);
				break;
			}
			print_later("Status phase complete. I think...",
				    0, 0, 0, 0, 0);
			expect_setup_packet();
			break;
		}

		/* Anything else should be ignorable. Right? */
		break;

	case NO_DATA_STAGE:
		if (intr_on_in && (diepint & DIEPINT_XFERCOMPL)) {
			print_later("IN descriptor processed", 0, 0, 0, 0, 0);
			/* Let the IN proceed */
			GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;
		}

		/* Done unless we got an OUT interrupt */
		if (!intr_on_out)
			break;

		if (tc == TABLE_CASE_B) {
			print_later("IN has been detected...", 0, 0, 0, 0, 0);
			/* Let the IN proceed */
			GR_USB_DIEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
			/* Reenable the previously prepared OUT descriptor. */
			GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
			break;
		}

		if (tc == TABLE_CASE_A || tc == TABLE_CASE_C) {
			if (sr) {
				/* We expected an IN, but got a Setup. */
				print_later("Early Setup", 0, 0, 0, 0, 0);
				handle_setup(tc);
				break;
			}
		}

		/* Anything else means get ready for a Setup packet */
		print_later("Status phase complete. Maybe.",
			    0, 0, 0, 0, 0);
		expect_setup_packet();
		break;
	}
}
コード例 #15
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
void usb_interrupt(void)
{
	uint32_t status = GR_USB_GINTSTS;
	uint32_t oepint = status & GINTSTS(OEPINT);
	uint32_t iepint = status & GINTSTS(IEPINT);

	int ep;

	print_later("interrupt: GINTSTS 0x%08x", status, 0, 0, 0, 0);

	/* We can suspend if the host stops talking to us. But if anything else
	 * comes along (even ERLYSUSP), we should NOT suspend. */
	if (status & GINTSTS(USBSUSP)) {
		print_later("usb_suspend()", 0, 0, 0, 0, 0);
		enable_sleep(SLEEP_MASK_USB_DEVICE);
	} else {
		disable_sleep(SLEEP_MASK_USB_DEVICE);
	}

#ifdef DEBUG_ME
	if (status & GINTSTS(ERLYSUSP))
		print_later("usb_early_suspend()", 0, 0, 0, 0, 0);

	if (status & GINTSTS(WKUPINT))
		print_later("usb_wakeup()", 0, 0, 0, 0, 0);

	if (status & GINTSTS(ENUMDONE))
		print_later("usb_enumdone()", 0, 0, 0, 0, 0);
#endif

	if (status & (GINTSTS(RESETDET) | GINTSTS(USBRST)))
		usb_reset();

	/* Initialize the SOF clock calibrator only on the first SOF */
	if (GR_USB_GINTMSK & GINTMSK(SOF) && status & GINTSTS(SOF)) {
		init_sof_clock();
		GR_USB_GINTMSK &= ~GINTMSK(SOF);
	}

	/* Endpoint interrupts */
	if (oepint || iepint) {
		/* Note: It seems that the DAINT bits are only trustworthy for
		 * identifying interrupts when selected by the corresponding
		 * OEPINT and IEPINT bits from GINTSTS. */
		uint32_t daint = GR_USB_DAINT;

		print_later("  oepint%c iepint%c daint 0x%08x",
			    oepint ? '!' : '_', iepint ? '!' : '_',
			    daint, 0, 0);

		/* EP0 has a combined IN/OUT handler. Only call it once, but
		 * let it know which direction(s) had an interrupt. */
		if (daint & (DAINT_OUTEP(0) | DAINT_INEP(0))) {
			uint32_t intr_on_out = (oepint &&
						(daint & DAINT_OUTEP(0)));
			uint32_t intr_on_in = (iepint &&
					       (daint & DAINT_INEP(0)));
			ep0_interrupt(intr_on_out, intr_on_in);
		}

		/* Invoke the unidirectional IN and OUT functions for the other
		 * endpoints. Each handler must clear their own bits in
		 * DIEPINTn/DOEPINTn. */
		for (ep = 1; ep < USB_EP_COUNT; ep++) {
			if (oepint && (daint & DAINT_OUTEP(ep)))
				usb_ep_rx[ep]();
			if (iepint && (daint & DAINT_INEP(ep)))
				usb_ep_tx[ep]();
		}
	}

	if (status & GINTSTS(GOUTNAKEFF))
		GR_USB_DCTL |= DCTL_CGOUTNAK;

	if (status & GINTSTS(GINNAKEFF))
		GR_USB_DCTL |= DCTL_CGNPINNAK;

	GR_USB_GINTSTS = status;

	print_later("end of interrupt", 0, 0, 0, 0, 0);
}
コード例 #16
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* Some Setup packets don't have a data stage at all. */
static int handle_setup_with_no_data_stage(enum table_case tc,
					   struct usb_setup_packet *req)
{
	uint8_t set_addr;

	print_later("handle_setup_with_no_data_stage(%c)", "0ABCDE67"[tc],
		    0, 0, 0, 0);

	switch (req->bRequest) {
	case USB_REQ_SET_ADDRESS:
		/*
		 * Set the address after the IN packet handshake.
		 *
		 * From the USB 2.0 spec, section 9.4.6:
		 *
		 * As noted elsewhere, requests actually may result in
		 * up to three stages. In the first stage, the Setup
		 * packet is sent to the device. In the optional second
		 * stage, data is transferred between the host and the
		 * device. In the final stage, status is transferred
		 * between the host and the device. The direction of
		 * data and status transfer depends on whether the host
		 * is sending data to the device or the device is
		 * sending data to the host. The Status stage transfer
		 * is always in the opposite direction of the Data
		 * stage. If there is no Data stage, the Status stage
		 * is from the device to the host.
		 *
		 * Stages after the initial Setup packet assume the
		 * same device address as the Setup packet. The USB
		 * device does not change its device address until
		 * after the Status stage of this request is completed
		 * successfully. Note that this is a difference between
		 * this request and all other requests. For all other
		 * requests, the operation indicated must be completed
		 * before the Status stage
		 */
		set_addr = req->wValue & 0xff;
		/*
		 * NOTE: Now that we've said that, we don't do it. The
		 * hardware for this SoC knows that an IN packet will
		 * be following the SET ADDRESS, so it waits until it
		 * sees that happen before the address change takes
		 * effect. If we wait until after the IN packet to
		 * change the register, the hardware gets confused and
		 * doesn't respond to anything.
		 */
		GWRITE_FIELD(USB, DCFG, DEVADDR, set_addr);
		CPRINTS("SETAD 0x%02x (%d)", set_addr, set_addr);
		print_later("SETAD 0x%02x (%d)", set_addr, set_addr, 0, 0, 0);
		device_state = DS_ADDRESS;
		processed_update_counter = 1;
		break;

	case USB_REQ_SET_CONFIGURATION:
		print_later("SETCFG 0x%x", req->wValue, 0, 0, 0, 0);
		switch (req->wValue) {
		case 0:
			configuration_value = req->wValue;
			device_state = DS_ADDRESS;
			break;
		case 1:	    /* Caution: Only one config descriptor TODAY */
			/* TODO: All endpoints set to DATA0 toggle state */
			configuration_value = req->wValue;
			device_state = DS_CONFIGURED;
			break;
		default:
			/* Nope. That's a paddlin. */
			return -1;
		}
		break;

	case USB_REQ_CLEAR_FEATURE:
	case USB_REQ_SET_FEATURE:
		/* TODO: Handle DEVICE_REMOTE_WAKEUP, ENDPOINT_HALT? */
		print_later("SET_FEATURE/CLEAR_FEATURE. Whatever...",
			    0, 0, 0, 0, 0);
		break;

	default:
		/* Anything else is unsupported */
		return -1;
	}

	/* No data to transfer, go straight to the Status phase. */
	return 0;
}
コード例 #17
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
void usb_connect(void)
{
	print_later("usb_connect()", 0, 0, 0, 0, 0);
	GR_USB_DCTL &= ~DCTL_SFTDISCON;
}
コード例 #18
0
ファイル: usb.c プロジェクト: coreboot/chrome-ec
/* Handle a Setup packet that expects us to send back data in reply. Return the
 * length of the data we're returning, or negative to indicate an error. */
static int handle_setup_with_in_stage(enum table_case tc,
				      struct usb_setup_packet *req)
{
	const void *data = 0;
	uint32_t len = 0;
	int ugly_hack = 0;
	static const uint16_t zero;		/* == 0 */

	print_later("handle_setup_with_in_stage(%c)", "0ABCDE67"[tc],
		    0, 0, 0, 0);

	switch (req->bRequest) {
	case USB_REQ_GET_DESCRIPTOR: {
		uint8_t type = req->wValue >> 8;
		uint8_t idx = req->wValue & 0xff;

		switch (type) {
		case USB_DT_DEVICE:
			data = &dev_desc;
			len = sizeof(dev_desc);
			break;
		case USB_DT_CONFIGURATION:
			data = __usb_desc;
			len = USB_DESC_SIZE;
			ugly_hack = 1;		/* see below */
			break;
#ifdef CONFIG_USB_BOS
		case USB_DT_BOS:
			data = bos_ctx.descp;
			len = bos_ctx.size;
			break;
#endif
		case USB_DT_STRING:
			if (idx >= USB_STR_COUNT)
				return -1;
#if USE_SERIAL_NUMBER
			if (idx == USB_STR_SERIALNO &&
			    ccd_get_mode() == CCD_MODE_ENABLED)
				data = usb_serialno_desc;
			else
#endif
				data = usb_strings[idx];
			len = *(uint8_t *)data;
			break;
		case USB_DT_DEVICE_QUALIFIER:
			/* We're not high speed */
			return -1;
		default:
			report_error(type);
			return -1;
		}
		break;
	}
	case USB_REQ_GET_STATUS: {
		/* TODO: Device Status: Remote Wakeup? Self Powered? */
		data = &zero;
		len = sizeof(zero);
		break;
	}
	case USB_REQ_GET_CONFIGURATION:
		data = &configuration_value;
		len = sizeof(configuration_value);
		break;

	case USB_REQ_SYNCH_FRAME:
		/* Unimplemented */
		return -1;

	default:
		report_error(req->bRequest);
		return -1;
	}

	/* Don't send back more than we were asked for. */
	len = MIN(req->wLength, len);

	/* Prepare the TX FIFO. If we haven't preallocated enough room in the
	 * TX FIFO for the largest reply, we'll have to stall. This is a bug in
	 * our code, but detecting it easily at compile time is related to the
	 * ugly_hack directly below. */
	if (load_in_fifo(data, len) < 0)
		return -1;

	if (ugly_hack) {
		/*
		 * TODO: Somebody figure out how to fix this, please.
		 *
		 * The USB configuration descriptor request is unique in that
		 * it not only returns the configuration descriptor, but also
		 * all the interface descriptors and all their endpoint
		 * descriptors as one enormous blob. We've set up some macros
		 * so we can declare and implement separate interfaces in
		 * separate files just by compiling them, and all the relevant
		 * descriptors are sorted and bundled up by the linker. But the
		 * total length of the entire blob needs to appear in the first
		 * configuration descriptor struct and because we don't know
		 * that value until after linking, it can't be initialized as a
		 * constant. So we have to compute it at run-time and shove it
		 * in here, which also means that we have to copy the whole
		 * blob into our TX FIFO buffer so that it's mutable. Otherwise
		 * we could just point at it (or pretty much any other constant
		 * struct that we wanted to send to the host). Bah.
		 */
		struct usb_config_descriptor *cfg =
			(struct usb_config_descriptor *)ep0_in_buf;
		/* set the real descriptor size */
		cfg->wTotalLength = USB_DESC_SIZE;
	}

	return len;
}
コード例 #19
0
ファイル: usb.c プロジェクト: littlebabay/chrome-ec
void usb_connect(void)
{
	CPRINTS("%s", __func__);
	print_later("usb_connect()", 0, 0, 0, 0, 0);
	GR_USB_DCTL &= ~DCTL_SFTDISCON;
}