Esempio n. 1
0
/* disable root hub */
static void
uhci_rh_disable_port (usbdev_t *dev, int port)
{
	hci_t *controller = dev->controller;
	if (port == 1)
		port = PORTSC1;
	else if (port == 2)
		port = PORTSC2;
	else {
		usb_debug("Invalid port %d\n", port);
		return;
	}
	uhci_reg_write16(controller, port,
			 uhci_reg_read16(controller, port) & ~4);
	u16 value;
	/* wait for controller to disable port */
	/* TOTEST: how long to wait? 100ms for now */
	int timeout = 200; /* time out after 200 * 500us == 100ms */
	do {
		value = uhci_reg_read16 (controller, port);
		udelay(500); timeout--;
	} while (((value & (1 << 2)) != 0) && timeout);
	if (!timeout)
		usb_debug("Warning: uhci_rh: port disabling timed out.\n");
}
Esempio n. 2
0
static int
dwc2_rh_reset_port(usbdev_t *const dev, const int port)
{
	hprt_t hprt;
	dwc_ctrl_t *const dwc2 = DWC2_INST(dev->controller);

	hprt.d32 = readl(dwc2->hprt0);
	hprt.d32 &= HPRT_W1C_MASK;
	hprt.prtrst = 1;
	writel(hprt.d32, dwc2->hprt0);

	/* Wait a bit while reset is active. */
	mdelay(50);

	/* Deassert reset. */
	hprt.prtrst = 0;
	writel(hprt.d32, dwc2->hprt0);

	/*
	 * If reset and speed enum success the DWC2 core will set enable bit
	 * after port reset bit is deasserted
	 */
	mdelay(1);
	hprt.d32 = readl(dwc2->hprt0);
	usb_debug("%s reset port ok, hprt = 0x%08x\n", __func__, hprt.d32);

	if (!hprt.prtena) {
		usb_debug("%s enable port fail! hprt = 0x%08x\n",
			  __func__, hprt.d32);
		return -1;
	}

	return 0;
}
Esempio n. 3
0
static int
xhci_wait_ready(xhci_t *const xhci)
{
	xhci_debug("Waiting for controller to be ready... ");
	if (!xhci_handshake(&xhci->opreg->usbsts, USBSTS_CNR, 0, 100000L)) {
		usb_debug("timeout!\n");
		return -1;
	}
	usb_debug("ok.\n");
	return 0;
}
Esempio n. 4
0
static void
xhci_reset(hci_t *const controller)
{
	xhci_t *const xhci = XHCI_INST(controller);

	xhci_stop(controller);

	xhci->opreg->usbcmd |= USBCMD_HCRST;
	xhci_debug("Resetting controller... ");
	if (!xhci_handshake(&xhci->opreg->usbcmd, USBCMD_HCRST, 0, 1000000L))
		usb_debug("timeout!\n");
	else
		usb_debug("ok.\n");
}
Esempio n. 5
0
static void
ehci_rh_scanport (usbdev_t *dev, int port)
{
	if (RH_INST(dev)->devices[port]!=-1) {
		usb_debug("Unregister device at port %x\n", port+1);
		usb_detach_device(dev->controller, RH_INST(dev)->devices[port]);
		RH_INST(dev)->devices[port]=-1;
	}
	/* device connected, handle */
	if (RH_INST(dev)->ports[port] & P_CURR_CONN_STATUS) {
		mdelay(100); // usb20 spec 9.1.2
		if ((RH_INST(dev)->ports[port] & P_LINE_STATUS) == P_LINE_STATUS_LOWSPEED) {
			ehci_rh_hand_over_port(dev, port);
			return;
		}

		/* Deassert enable, assert reset.  These must change
		 * atomically.
		 */
		RH_INST(dev)->ports[port] = (RH_INST(dev)->ports[port] & ~P_PORT_ENABLE) | P_PORT_RESET;

		/* Wait a bit while reset is active. */
		mdelay(50); // usb20 spec 7.1.7.5 (TDRSTR)

		/* Deassert reset. */
		RH_INST(dev)->ports[port] &= ~P_PORT_RESET;

		/* Wait max. 2ms (ehci spec 2.3.9) for flag change to finish. */
		int timeout = 20; /* time out after 20 * 100us == 2ms */
		while ((RH_INST(dev)->ports[port] & P_PORT_RESET) && timeout--)
			udelay(100);
		if (RH_INST(dev)->ports[port] & P_PORT_RESET) {
			usb_debug("Error: ehci_rh: port reset timed out.\n");
			return;
		}

		/* If the host controller enabled the port, it's a high-speed
		 * device, otherwise it's full-speed.
		 */
		if (!(RH_INST(dev)->ports[port] & P_PORT_ENABLE)) {
			ehci_rh_hand_over_port(dev, port);
			return;
		}
		usb_debug("port %x hosts a USB2 device\n", port+1);
		RH_INST(dev)->devices[port] = usb_attach_device(dev->controller, dev->address, port, 2);
	}
	/* RW/C register, so clear it by writing 1 */
	RH_INST(dev)->ports[port] |= P_CONN_STATUS_CHANGE;
}
Esempio n. 6
0
/* read one intr-packet from queue, if available. extend the queue for new input.
   return NULL if nothing new available.
   Recommended use: while (data=poll_intr_queue(q)) process(data);
 */
static u8*
uhci_poll_intr_queue (void *q_)
{
	intr_q *q = (intr_q*)q_;
	if ((q->tds[q->lastread].ctrlsts & TD_STATUS_ACTIVE) == 0) {
		int current = q->lastread;
		int previous;
		if (q->lastread == 0) {
			previous = q->total - 1;
		} else {
			previous = q->lastread - 1;
		}
		q->tds[previous].ctrlsts &= ~TD_STATUS_MASK;
		q->tds[previous].ptr = 0 | TD_TERMINATE;
		if (q->last_td != &q->tds[previous]) {
			q->last_td->ptr = virt_to_phys(&q->tds[previous]) & ~TD_TERMINATE;
			q->last_td = &q->tds[previous];
		}
		q->tds[previous].ctrlsts |= TD_STATUS_ACTIVE;
		q->lastread = (q->lastread + 1) % q->total;
		if (!(q->tds[current].ctrlsts & TD_STATUS_MASK))
			return &q->data[current*q->reqsize];
	}
	/* reset queue if we fully processed it after underrun */
	else if (q->qh->elementlinkptr & FLISTP_TERMINATE) {
		usb_debug("resetting underrun uhci interrupt queue.\n");
		q->qh->elementlinkptr = virt_to_phys(q->tds + q->lastread);
	}
	return NULL;
}
Esempio n. 7
0
static void usb_handle_get_desc(struct usb_setup_req *req)
{
	switch (req->wValue) {
	case USB_DESC_VALUE(USB_DESC_DEVICE, 0):
		usb_send_desc(_dev00, min(sizeof(_dev00),req->wLength));
		break;

	case USB_DESC_VALUE(USB_DESC_CONFIG, 0):
		usb_send_desc(_cfg00, min(sizeof(_cfg00),req->wLength));
		break;

	case USB_DESC_VALUE(USB_DESC_STRING, 0):
		usb_send_desc(lang_id, min(sizeof(lang_id),req->wLength));
		break;

	case USB_DESC_VALUE(USB_DESC_STRING, 1):
		usb_send_desc(mfg_string, min(sizeof(mfg_string),req->wLength));
		break;

	case USB_DESC_VALUE(USB_DESC_STRING, 2):
		usb_send_desc(prod_string, min(sizeof(prod_string),req->wLength));
		break;

	default:
		usb_debug("unknown desc: %h\n", req->wValue);

		usb_nak(&usb_ep_data[0]);
		break;
	}
}
Esempio n. 8
0
static int get_mps(dwc2_ep_t *ep)
{
	dwc2_ep_reg_t *ep_reg = ep->ep_regs;
	depctl_t depctl;
	uint16_t mps = 0;

	depctl.d32 = readl(&ep_reg->depctl);
	if (ep->ep_num == 0) {
		switch (depctl.mps) {
		case D0EPCTL_MPS_64:
			mps = 64;
			break;
		case D0EPCTL_MPS_32:
			mps = 32;
			break;
		case D0EPCTL_MPS_16:
			mps = 16;
			break;
		case D0EPCTL_MPS_8:
			mps = 8;
			break;
		default:
			usb_debug("get mps error\n");
		}
	} else {
		mps = depctl.mps;
	}

	return mps;
}
Esempio n. 9
0
void
dwc2_rh_init(usbdev_t *dev)
{
	dwc_ctrl_t *const dwc2 = DWC2_INST(dev->controller);

	/* we can set them here because a root hub _really_ shouldn't
	   appear elsewhere */
	dev->address = 0;
	dev->hub = -1;
	dev->port = -1;

	generic_hub_init(dev, 1, &dwc2_rh_ops);
	usb_debug("dwc2_rh_init HPRT 0x%08x p = %p\n ",
		  readl(dwc2->hprt0), dwc2->hprt0);
	usb_debug("DWC2: root hub init done\n");
}
Esempio n. 10
0
static void
uhci_rh_scanport (usbdev_t *dev, int port)
{
	int portsc, offset;
	if (port == 1) {
		portsc = PORTSC1;
		offset = 0;
	} else if (port == 2) {
		portsc = PORTSC2;
		offset = 1;
	} else {
		usb_debug("Invalid port %d\n", port);
		return;
	}
	int devno = RH_INST (dev)->port[offset];
	if ((dev->controller->devices[devno] != 0) && (devno != -1)) {
		usb_detach_device(dev->controller, devno);
		RH_INST (dev)->port[offset] = -1;
	}
	uhci_reg_write16(dev->controller, portsc,
			 uhci_reg_read16(dev->controller, portsc) | (1 << 3) | (1 << 2));	// clear port state change, enable port

	mdelay(100); // wait for signal to stabilize

	if ((uhci_reg_read16 (dev->controller, portsc) & 1) != 0) {
		// device attached

		uhci_rh_disable_port (dev, port);
		uhci_rh_enable_port (dev, port);

		int speed = ((uhci_reg_read16 (dev->controller, portsc) >> 8) & 1);

		RH_INST (dev)->port[offset] = usb_attach_device(dev->controller, dev->address, portsc, speed);
	}
Esempio n. 11
0
/* finalize == 1: if data is of packet aligned size, add a zero length packet */
static int
uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
{
	int maxpsize = ep->maxpacketsize;
	if (maxpsize == 0)
		fatal("MaxPacketSize == 0!!!");
	int numpackets = (size + maxpsize - 1) / maxpsize;
	if (finalize && ((size % maxpsize) == 0)) {
		numpackets++;
	}
	if (numpackets == 0)
		return 0;
	td_t *tds = create_schedule (numpackets);
	int i = 0, toggle = ep->toggle;
	while ((size > 0) || ((size == 0) && (finalize != 0))) {
		fill_schedule (&tds[i], ep, min (size, maxpsize), data,
			       &toggle);
		i++;
		data += maxpsize;
		size -= maxpsize;
	}
	if (run_schedule (ep->dev, tds) == 1) {
		usb_debug("Stalled. Trying to clean up.\n");
		clear_stall (ep);
		free (tds);
		return 1;
	}
	ep->toggle = toggle;
	free (tds);
	return 0;
}
Esempio n. 12
0
void
xhci_dump_transfer_trb(const trb_t *const cur)
{
	xhci_debug("Transfer TRB (@%p):\n", cur);
	usb_debug(" PTR_L\t0x%08"PRIx32"\n", cur->ptr_low);
	usb_debug(" PTR_H\t0x%08"PRIx32"\n", cur->ptr_high);
	usb_debug(" STATUS\t0x%08"PRIx32"\n", cur->status);
	usb_debug(" CNTRL\t0x%08"PRIx32"\n", cur->control);
	TRB_DUMP(TL,	cur);
	TRB_DUMP(TDS,	cur);
	TRB_DUMP(C,	cur);
	TRB_DUMP(ISP,	cur);
	TRB_DUMP(CH,	cur);
	TRB_DUMP(IOC,	cur);
	TRB_DUMP(IDT,	cur);
	TRB_DUMP(TT,	cur);
	TRB_DUMP(DIR,	cur);
}
Esempio n. 13
0
static void usb_send_desc(const void *desc, int len)
{
	if (usb_ep_data[0].in_size < len) {
		usb_debug("descriptor size (%x) larger than in buffer (%x)\n",
		       len, usb_ep_data[0].in_size);
		usb_nak(&usb_ep_data[0]);
		return;
	}
	usb_ep_write(&usb_ep_data[0], desc, len);
}
Esempio n. 14
0
void
xhci_dump_epctx(const epctx_t *const ec)
{
	xhci_debug("Endpoint Context (@%p):\n", ec);
	usb_debug(" FIELD1\t0x%08"PRIx32"\n", ec->f1);
	usb_debug(" FIELD2\t0x%08"PRIx32"\n", ec->f2);
	usb_debug(" TRDQ_L\t0x%08"PRIx32"\n", ec->tr_dq_low);
	usb_debug(" TRDQ_H\t0x%08"PRIx32"\n", ec->tr_dq_high);
	usb_debug(" FIELD5\t0x%08"PRIx32"\n", ec->f5);
	EC_DUMP(STATE,  ec);
	EC_DUMP(INTVAL, ec);
	EC_DUMP(CERR,   ec);
	EC_DUMP(TYPE,   ec);
	EC_DUMP(MBS,    ec);
	EC_DUMP(MPS,    ec);
	EC_DUMP(DCS,    ec);
	EC_DUMP(AVRTRB, ec);
	EC_DUMP(MXESIT, ec);
}
Esempio n. 15
0
/* dump uhci */
static void
uhci_dump (hci_t *controller)
{
	usb_debug ("dump:\nUSBCMD: %x\n", uhci_reg_read16 (controller, USBCMD));
	usb_debug ("USBSTS: %x\n", uhci_reg_read16 (controller, USBSTS));
	usb_debug ("USBINTR: %x\n", uhci_reg_read16 (controller, USBINTR));
	usb_debug ("FRNUM: %x\n", uhci_reg_read16 (controller, FRNUM));
	usb_debug ("FLBASEADD: %x\n", uhci_reg_read32 (controller, FLBASEADD));
	usb_debug ("SOFMOD: %x\n", uhci_reg_read8 (controller, SOFMOD));
	usb_debug ("PORTSC1: %x\n", uhci_reg_read16 (controller, PORTSC1));
	usb_debug ("PORTSC2: %x\n", uhci_reg_read16 (controller, PORTSC2));
}
Esempio n. 16
0
int usb_debug_printf( const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    char buf[60];

    int ret = vsnprintf(buf, sizeof(buf), fmt, ap);
	usb_debug(buf);

    return ret;	
}
Esempio n. 17
0
void
xhci_dump_slotctx(const slotctx_t *const sc)
{
	xhci_debug("Slot Context (@%p):\n", sc);
	usb_debug(" FIELD1\t0x%08"PRIx32"\n", sc->f1);
	usb_debug(" FIELD2\t0x%08"PRIx32"\n", sc->f2);
	usb_debug(" FIELD3\t0x%08"PRIx32"\n", sc->f3);
	usb_debug(" FIELD4\t0x%08"PRIx32"\n", sc->f4);
	SC_DUMP(ROUTE,  sc);
	SC_DUMP(SPEED1, sc);
	SC_DUMP(MTT,    sc);
	SC_DUMP(HUB,    sc);
	SC_DUMP(CTXENT, sc);
	SC_DUMP(RHPORT, sc);
	SC_DUMP(NPORTS, sc);
	SC_DUMP(TTID,   sc);
	SC_DUMP(TTPORT, sc);
	SC_DUMP(TTT,    sc);
	SC_DUMP(UADDR,  sc);
	SC_DUMP(STATE,  sc);
}
Esempio n. 18
0
u32 usb_quirk_check(u16 vendor, u16 device)
{
	int i;
	for (i = 0; i < ARRAY_SIZE(usb_quirks); i++) {
		if ((usb_quirks[i].vendor == vendor) &&
				(usb_quirks[i].device == device)) {
			usb_debug("USB quirks enabled: %08x\n",
					usb_quirks[i].quirks);
			return usb_quirks[i].quirks;
		}
	}

	return USB_QUIRK_NONE;
}
Esempio n. 19
0
static void usb_handle_setup_req(struct usb_setup_req *req)
{
	switch (req->bRequest) {
	case USB_REQ_GET_DESCRIPTOR:
		usb_handle_get_desc(req);
		break;
	case USB_REQ_SET_ADDRESS:
		clr_set_reg(USB_DEVCMDSTAT, USB_DEVCMDSTAT_DEV_ADDR(~0),
			    USB_DEVCMDSTAT_DEV_ADDR(req->wValue));
		usb_send_zlp(&usb_ep_data[0]);
		break;
	case USB_REQ_GET_CONFIGURATION: {
                u8 config = usb_state == USB_STATE_ONLINE;
                usb_debug("get_config(%d)\n", config);
                usb_ep_write(&usb_ep_data[0], &config, 1);
                break;
        }

	case USB_REQ_SET_CONFIGURATION:
		usb_handle_set_config(req->wValue);
		break;

	default:
		usb_debug("unknown setup req:\n");
		usb_debug("  bmRequestType: %b\n", req->bmRequestType);
		usb_debug("     dir: %b\n", req->t.dir);
		usb_debug("     type: %b\n", req->t.type);
		usb_debug("     rcpt: %b\n", req->t.rcpt);
		usb_debug("  bRequest:      %b\n", req->bRequest);
		usb_debug("  wValue:        %h\n", req->wValue);
		usb_debug("  wIndex:        %h\n", req->wIndex);
		usb_debug("  wLength:       %h\n", req->wLength);

		usb_nak(&usb_ep_data[0]);
		break;
	}
}
Esempio n. 20
0
static void
uhci_rh_enable_port (usbdev_t *dev, int port)
{
	u16 value;
	hci_t *controller = dev->controller;
	if (port == 1)
		port = PORTSC1;
	else if (port == 2)
		port = PORTSC2;
	else {
		usb_debug("Invalid port %d\n", port);
		return;
	}

	uhci_reg_write16(controller, port,
			 uhci_reg_read16(controller, port) & ~(1 << 12));	/* wakeup */

	uhci_reg_write16(controller, port,
			 uhci_reg_read16(controller, port) | 1 << 9);	/* reset */
	mdelay (30);		// >10ms
	uhci_reg_write16(controller, port,
			 uhci_reg_read16(controller, port) & ~(1 << 9));
	mdelay (1);		// >5.3us per spec, <3ms because some devices make trouble

	uhci_reg_write16(controller, port,
			 uhci_reg_read16(controller, port) | 1 << 2);	/* enable */
	/* wait for controller to enable port */
	/* TOTEST: how long to wait? 100ms for now */
	int timeout = 200; /* time out after 200 * 500us == 100ms */
	do {
		value = uhci_reg_read16 (controller, port);
		udelay(500); timeout--;
	} while (((value & (1 << 2)) == 0) && (value & 0x01) && timeout);
	if (!timeout)
		usb_debug("Warning: uhci_rh: port enabling timed out.\n");
}
Esempio n. 21
0
void
ehci_rh_init (usbdev_t *dev)
{
	int i;
	dev->destroy = ehci_rh_destroy;
	dev->poll = ehci_rh_poll;

	dev->data = malloc(sizeof(rh_inst_t));

	RH_INST(dev)->n_ports = EHCI_INST(dev->controller)->capabilities->hcsparams & HCS_NPORTS_MASK;
	RH_INST(dev)->ports = EHCI_INST(dev->controller)->operation->portsc;

	usb_debug("root hub has %x ports\n", RH_INST(dev)->n_ports);

	/* If the host controller has port power control, enable power on
	 * all ports and wait 20ms.
	 */
	if (EHCI_INST(dev->controller)->capabilities->hcsparams
			& HCS_PORT_POWER_CONTROL) {
		usb_debug("host controller has port power control, "
				"giving power to all ports.\n");
		for (i=0; i < RH_INST(dev)->n_ports; i++)
			RH_INST(dev)->ports[i] |= P_PP;
	}
	mdelay(20); // ehci spec 2.3.9

	RH_INST(dev)->devices = malloc(RH_INST(dev)->n_ports * sizeof(int));
	for (i=0; i < RH_INST(dev)->n_ports; i++) {
		RH_INST(dev)->devices[i] = -1;
		ehci_rh_scanport(dev, i);
	}

	dev->address = 0;
	dev->hub = -1;
	dev->port = -1;
}
Esempio n. 22
0
static void
ehci_rh_hand_over_port (usbdev_t *dev, int port)
{
	usb_debug("giving up port %x, it's USB1\n", port+1);

	/* Clear ConnectStatusChange before evaluation */
	/* RW/C register, so clear it by writing 1 */
	RH_INST(dev)->ports[port] |= P_CONN_STATUS_CHANGE;

	/* Lowspeed device. Hand over to companion */
	RH_INST(dev)->ports[port] |= P_PORT_OWNER;

	/* TOTEST: how long to wait? trying 100ms for now */
	int timeout = 10; /* timeout after 10 * 10ms == 100ms */
	while (!(RH_INST(dev)->ports[port] & P_CONN_STATUS_CHANGE) && timeout--)
		mdelay(10);
	if (!(RH_INST(dev)->ports[port] & P_CONN_STATUS_CHANGE)) {
		usb_debug("Warning: Handing port over to companion timed out.\n");
	}

	/* RW/C register, so clear it by writing 1 */
	RH_INST(dev)->ports[port] |= P_CONN_STATUS_CHANGE;
	return;
}
Esempio n. 23
0
static void usb_handle_set_config(unsigned config)
{
        usb_debug("set_config(%d)\n", config);
	if (config != 1) {
		usb_nak(&usb_ep_data[0]);
		return;
	}
	usb_config_ep(&usb_ep_data[1]);
//	clr_set_reg(USB_DEVCMDSTAT, 0, USB_DEVCMDSTAT_INTONNAK_AI);

	usb_send_zlp(&usb_ep_data[0]);
	usb_state = USB_STATE_ONLINE;
	if (usb_online_cb)
		usb_online_cb(1);
        printx("state = %d\n", usb_state);
}
Esempio n. 24
0
static void
uhci_reset (hci_t *controller)
{
	/* reset */
	uhci_reg_write16 (controller, USBCMD, 4); /* Global Reset */
	mdelay (50); /* uhci spec 2.1.1: at least 10ms */
	uhci_reg_write16 (controller, USBCMD, 0);
	mdelay (10);
	uhci_reg_write16 (controller, USBCMD, 2); /* Host Controller Reset */
	/* wait for controller to finish reset */
	/* TOTEST: how long to wait? 100ms for now */
	int timeout = 200; /* time out after 200 * 500us == 100ms */
	while (((uhci_reg_read16 (controller, USBCMD) & 2) != 0) && timeout--)
		udelay (500);
	if (timeout < 0)
		usb_debug ("Warning: uhci: host controller reset timed out.\n");
}
Esempio n. 25
0
static void td_dump(td_t *td)
{
	usb_debug("+---------------------------------------------------+\n");
	if ((td->token & TD_PID_MASK) == UHCI_SETUP)
		usb_debug("|..[SETUP]..........................................|\n");
	else if ((td->token & TD_PID_MASK) == UHCI_IN)
		usb_debug("|..[IN].............................................|\n");
	else if ((td->token & TD_PID_MASK) == UHCI_OUT)
		usb_debug("|..[OUT]............................................|\n");
	else
		usb_debug("|..[]...............................................|\n");
	usb_debug("|:|============ UHCI TD at [0x%08lx] ==========|:|\n", virt_to_phys(td));
	usb_debug("|:+-----------------------------------------------+:|\n");
	usb_debug("|:| Next  TD/QH     [0x%08lx]                  |:|\n", td->ptr & ~0xFUL);
	usb_debug("|:+-----------------------------------------------+:|\n");
	usb_debug("|:| Depth/Breath [%lx]  | QH/TD [%lx] | TERMINATE [%lx] |:|\n",
	(td->ptr & (1UL << 2)) >> 2, (td->ptr & (1UL << 1)) >> 1, td->ptr & 1UL);
	usb_debug("|:+-----------------------------------------------+:|\n");
	usb_debug("|:|   T   | Maximum Length               | [%04lx] |:|\n", (td->token & (0x7FFUL << 21)) >> 21);
	usb_debug("|:|   O   | PID CODE                     | [%04lx] |:|\n", td->token & 0xFF);
	usb_debug("|:|   K   | Endpoint                     | [%04lx] |:|\n", (td->token & TD_EP_MASK) >> TD_EP_SHIFT);
	usb_debug("|:|   E   | Device Address               | [%04lx] |:|\n", (td->token & (0x7FUL << 8)) >> 8);
	usb_debug("|:|   N   | Data Toggle                  |    [%lx] |:|\n", (td->token & (1UL << 19)) >> 19);
	usb_debug("|:+-----------------------------------------------+:|\n");
	usb_debug("|:|   C   | Short Packet Detector        |    [%lx] |:|\n", (td->ctrlsts & (1UL << 29)) >> 29);
	usb_debug("|:|   O   | Error Counter                |    [%lx] |:|\n",
		(td->ctrlsts & (3UL << TD_COUNTER_SHIFT)) >> TD_COUNTER_SHIFT);
	usb_debug("|:|   N   | Low Speed Device             |    [%lx] |:|\n", (td->ctrlsts & (1UL << 26)) >> 26);
	usb_debug("|:|   T   | Isochronous Select           |    [%lx] |:|\n", (td->ctrlsts & (1UL << 25)) >> 25);
	usb_debug("|:|   R   | Interrupt on Complete (IOC)  |    [%lx] |:|\n", (td->ctrlsts & (1UL << 24)) >> 24);
	usb_debug("|:+   O   ----------------------------------------+:|\n");
	usb_debug("|:|   L   | Active                       |    [%lx] |:|\n", (td->ctrlsts & (1UL << 23)) >> 23);
	usb_debug("|:|   &   | Stalled                      |    [%lx] |:|\n", (td->ctrlsts & (1UL << 22)) >> 22);
	usb_debug("|:|   S   | Data Buffer Error            |    [%lx] |:|\n", (td->ctrlsts & (1UL << 21)) >> 21);
	usb_debug("|:|   T   | Bubble Detected              |    [%lx] |:|\n", (td->ctrlsts & (1UL << 20)) >> 20);
	usb_debug("|:|   A   | NAK Received                 |    [%lx] |:|\n", (td->ctrlsts & (1UL << 19)) >> 19);
	usb_debug("|:|   T   | CRC/Timeout Error            |    [%lx] |:|\n", (td->ctrlsts & (1UL << 18)) >> 18);
	usb_debug("|:|   U   | Bitstuff Error               |    [%lx] |:|\n", (td->ctrlsts & (1UL << 17)) >> 17);
	usb_debug("|:|   S   ----------------------------------------|:|\n");
	usb_debug("|:|       | Actual Length                | [%04lx] |:|\n", td->ctrlsts & 0x7FFUL);
	usb_debug("|:+-----------------------------------------------+:|\n");
	usb_debug("|:| Buffer pointer  [0x%08lx]                  |:|\n", td->bufptr);
	usb_debug("|:|-----------------------------------------------|:|\n");
	usb_debug("|...................................................|\n");
	usb_debug("+---------------------------------------------------+\n");
}
Esempio n. 26
0
/* create and hook-up an intr queue into device schedule */
static void*
uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming)
{
	u8 *data = malloc(reqsize*reqcount);
	td_t *tds = memalign(16, sizeof(td_t) * reqcount);
	qh_t *qh = memalign(16, sizeof(qh_t));

	if (!data || !tds || !qh)
		fatal("Not enough memory to create USB intr queue prerequisites.\n");

	qh->elementlinkptr = virt_to_phys(tds);

	intr_q *q = malloc(sizeof(intr_q));
	if (!q)
		fatal("Not enough memory to create USB intr queue.\n");
	q->qh = qh;
	q->tds = tds;
	q->data = data;
	q->lastread = 0;
	q->total = reqcount;
	q->reqsize = reqsize;
	q->last_td = &tds[reqcount - 1];

	memset (tds, 0, sizeof (td_t) * reqcount);
	int i;
	for (i = 0; i < reqcount; i++) {
		tds[i].ptr = virt_to_phys (&tds[i + 1]);

		switch (ep->direction) {
			case IN: tds[i].token = UHCI_IN; break;
			case OUT: tds[i].token = UHCI_OUT; break;
			case SETUP: tds[i].token = UHCI_SETUP; break;
		}
		tds[i].token |= ep->dev->address << TD_DEVADDR_SHIFT |
			(ep->endpoint & 0xf) << TD_EP_SHIFT |
			maxlen (reqsize) << TD_MAXLEN_SHIFT |
			(ep->toggle & 1) << TD_TOGGLE_SHIFT;
		tds[i].bufptr = virt_to_phys (data);
		tds[i].ctrlsts = (0 << TD_COUNTER_SHIFT) |
			(ep->dev->speed?TD_LOWSPEED:0) |
			TD_STATUS_ACTIVE;
		ep->toggle ^= 1;
		data += reqsize;
	}
	tds[reqcount - 1].ptr = 0 | TD_TERMINATE;

	/* insert QH into framelist */
	uhci_t *const uhcic = UHCI_INST(ep->dev->controller);
	const u32 def_ptr = virt_to_phys(uhcic->qh_prei) | FLISTP_QH;
	int nothing_placed = 1;
	qh->headlinkptr = def_ptr;
	for (i = 0; i < 1024; i += reqtiming) {
		/* advance to the next free position */
		while ((i < 1024) && (uhcic->framelistptr[i] != def_ptr)) ++i;
		if (i < 1024) {
			uhcic->framelistptr[i] = virt_to_phys(qh) | FLISTP_QH;
			nothing_placed = 0;
		}
	}
	if (nothing_placed) {
		usb_debug("Error: Failed to place UHCI interrupt queue "
			      "head into framelist: no space left\n");
		uhci_destroy_intr_queue(ep, q);
		return NULL;
	}

	return q;
}
Esempio n. 27
0
static int
uhci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen,
	      unsigned char *data)
{
	int endp = 0;		/* this is control: always 0 */
	int mlen = dev->endpoints[0].maxpacketsize;
	int count = (2 + (dalen + mlen - 1) / mlen);
	unsigned short req = ((unsigned short *) devreq)[0];
	int i;
	td_t *tds = memalign (16, sizeof (td_t) * count);
	memset (tds, 0, sizeof (td_t) * count);
	count--;		/* to compensate for 0-indexed array */
	for (i = 0; i < count; i++) {
		tds[i].ptr = virt_to_phys (&tds[i + 1]) | TD_DEPTH_FIRST;
	}
	tds[count].ptr = 0 | TD_DEPTH_FIRST | TD_TERMINATE;

	tds[0].token = UHCI_SETUP |
		dev->address << TD_DEVADDR_SHIFT |
		endp << TD_EP_SHIFT |
		TD_TOGGLE_DATA0 |
		maxlen(drlen) << TD_MAXLEN_SHIFT;
	tds[0].bufptr = virt_to_phys (devreq);
	tds[0].ctrlsts = (3 << TD_COUNTER_SHIFT) |
		(dev->speed?TD_LOWSPEED:0) |
		TD_STATUS_ACTIVE;

	int toggle = 1;
	for (i = 1; i < count; i++) {
		switch (dir) {
			case SETUP: tds[i].token = UHCI_SETUP; break;
			case IN:    tds[i].token = UHCI_IN;    break;
			case OUT:   tds[i].token = UHCI_OUT;   break;
		}
		tds[i].token |= dev->address << TD_DEVADDR_SHIFT |
			endp << TD_EP_SHIFT |
			maxlen (min (mlen, dalen)) << TD_MAXLEN_SHIFT |
			toggle << TD_TOGGLE_SHIFT;
		tds[i].bufptr = virt_to_phys (data);
		tds[i].ctrlsts = (3 << TD_COUNTER_SHIFT) |
			(dev->speed?TD_LOWSPEED:0) |
			TD_STATUS_ACTIVE;
		toggle ^= 1;
		dalen -= mlen;
		data += mlen;
	}

	tds[count].token = ((dir == OUT) ? UHCI_IN : UHCI_OUT) |
		dev->address << TD_DEVADDR_SHIFT |
		endp << TD_EP_SHIFT |
		maxlen(0) << TD_MAXLEN_SHIFT |
		TD_TOGGLE_DATA1;
	tds[count].bufptr = 0;
	tds[count].ctrlsts = (0 << TD_COUNTER_SHIFT) | /* as Linux 2.4.10 does */
		(dev->speed?TD_LOWSPEED:0) |
		TD_STATUS_ACTIVE;
	UHCI_INST (dev->controller)->qh_data->elementlinkptr =
		virt_to_phys (tds) & ~(FLISTP_QH | FLISTP_TERMINATE);
	td_t *td = wait_for_completed_qh (dev->controller,
					  UHCI_INST (dev->controller)->
					  qh_data);
	int result;
	if (td == 0) {
		result = 0;
	} else {
		usb_debug ("control packet, req %x\n", req);
		td_dump (td);
		result = 1;
	}
	free (tds);
	return result;
}