Exemple #1
0
hci_t *
ehci_init (pcidev_t addr)
{
    int i;
    hci_t *controller = new_controller ();

    if (!controller)
        usb_fatal("Could not create USB controller instance.\n");

    controller->instance = malloc (sizeof (ehci_t));
    if(!controller->instance)
        usb_fatal("Not enough memory creating USB controller instance.\n");

#define PCI_COMMAND 4
#define PCI_COMMAND_IO 1
#define PCI_COMMAND_MEMORY 2
#define PCI_COMMAND_MASTER 4

    u32 pci_command = pci_read_config32(addr, PCI_COMMAND);
    pci_command = (pci_command | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_IO ;
    pci_write_config32(addr, PCI_COMMAND, pci_command);

    controller->start = ehci_start;
    controller->stop = ehci_stop;
    controller->reset = ehci_reset;
    controller->shutdown = ehci_shutdown;
    controller->bulk = ehci_bulk;
    controller->control = ehci_control;
    controller->create_intr_queue = ehci_create_intr_queue;
    controller->destroy_intr_queue = ehci_destroy_intr_queue;
    controller->poll_intr_queue = ehci_poll_intr_queue;
    for (i = 0; i < 128; i++) {
        controller->devices[i] = 0;
    }
    init_device_entry (controller, 0);

    EHCI_INST(controller)->capabilities = phys_to_virt(pci_read_config32(addr, USBBASE));
    EHCI_INST(controller)->operation = (hc_op_t *)(phys_to_virt(pci_read_config32(addr, USBBASE)) + EHCI_INST(controller)->capabilities->caplength);

    /* default value for frame length adjust */
    pci_write_config8(addr, FLADJ, FLADJ_framelength(60000));

    /* Enable operation of controller */
    controller->start(controller);

    /* take over all ports. USB1 should be blind now */
    EHCI_INST(controller)->operation->configflag = 1;

    /* TODO lots of stuff missing */

    controller->devices[0]->controller = controller;
    controller->devices[0]->init = ehci_rh_init;
    controller->devices[0]->init (controller->devices[0]);

    return controller;
}
Exemple #2
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;
}
Exemple #3
0
static void ehci_stop (hci_t *controller)
{
    EHCI_INST(controller)->operation->rs = 0;
}
Exemple #4
0
/* FIXME: Handle control transfers as 3 QHs, so the 2nd stage can be >0x4000 bytes */
static int ehci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq,
                         int dalen, u8 *data)
{
    int endp = 0; // this is control. always 0 (for now)
    int toggle = 0;
    int mlen = dev->endpoints[0].maxpacketsize;
    int result = 0;

    /* create qTDs */
    qtd_t *head = memalign(32, sizeof(qtd_t));
    qtd_t *cur = head;
    memset(cur, 0, sizeof(qtd_t));
    cur->active = 1;
    cur->dt = toggle;
    cur->pid = EHCI_SETUP;
    cur->cerr = 3;
    if (fill_td(cur, devreq, drlen) != drlen) {
        printf("ERROR: couldn't send the entire device request\n");
    }
    qtd_t *next = memalign(32, sizeof(qtd_t));
    cur->next_qtd = virt_to_phys(next);
    cur->alt_terminate = 1;

    /* FIXME: We're limited to 16-20K (depending on alignment) for payload for now.
     * Figure out, how toggle can be set sensibly in this scenario */
    if (dalen > 0) {
        toggle ^= 1;
        cur = next;
        memset(cur, 0, sizeof(qtd_t));
        cur->active = 1;
        cur->dt = toggle;
        cur->pid = (dir == OUT)?EHCI_OUT:EHCI_IN;
        cur->cerr = 3;
        if (fill_td(cur, data, dalen) != dalen) {
            printf("ERROR: couldn't send the entire control payload\n");
        }
        next = memalign(32, sizeof(qtd_t));
        cur->next_qtd = virt_to_phys(next);
        cur->alt_terminate = 1;
    }

    toggle = 1;
    cur = next;
    memset(cur, 0, sizeof(qtd_t));
    cur->active = 1;
    cur->dt = toggle;
    cur->pid = (dir == OUT)?EHCI_IN:EHCI_OUT;
    cur->cerr = 0;
    fill_td(cur, NULL, 0);
    cur->next_qtd = virt_to_phys(0);
    cur->terminate = 1;
    cur->alt_terminate = 1;

    /* create QH */
    ehci_qh_t *qh = memalign(32, sizeof(ehci_qh_t));
    memset(qh, 0, sizeof(ehci_qh_t));
    qh->horiz_link_ptr = virt_to_phys(qh);
    qh->type = 1; // FIXME: proper symbols for type. this is QH
    qh->addr = dev->address;
    qh->ep = endp;
    qh->eps = dev->speed;
    qh->dtc = 1; /* Take data toggle from TD, as control transfers are special */
    qh->reclaim_head = 1;
    qh->max_packet_len = mlen;
    qh->non_hs_control_ep = 0; // no support for non-HS devices at this time
    qh->nak_cnt_reload = 0;
    qh->pipe_multiplier = 3;
    qh->td.next_qtd = virt_to_phys(head);

    /* hook up QH */
    EHCI_INST(dev->controller)->operation->asynclistaddr = virt_to_phys(qh);

    /* start async schedule */
    EHCI_INST(dev->controller)->operation->async_sched_enable = 1;
    while (!EHCI_INST(dev->controller)->operation->async_sched_status) ; /* wait */

    result = wait_for_tds(head);

    /* disable async schedule */
    EHCI_INST(dev->controller)->operation->async_sched_enable = 0;
    while (EHCI_INST(dev->controller)->operation->async_sched_status) ; /* wait */

    free_qh_and_tds(qh, head);
    return result;
}
Exemple #5
0
static int ehci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
{
    int result = 0;
    int endp = ep->endpoint & 0xf;
    int pid = (ep->direction==IN)?EHCI_IN:EHCI_OUT;

    qtd_t *head = memalign(32, sizeof(qtd_t));
    qtd_t *cur = head;
    while (1) {
        memset(cur, 0, sizeof(qtd_t));
        cur->active = 1;
        cur->pid = pid;
        cur->cerr = 0;
        u32 chunk = fill_td(cur, data, size);
        size -= chunk;
        data += chunk;

        cur->alt_terminate = 1;
        if (size == 0) {
            cur->next_qtd = virt_to_phys(0);
            cur->terminate = 1;
            break;
        } else {
            qtd_t *next = memalign(32, sizeof(qtd_t));
            cur->next_qtd = virt_to_phys(next);
            cur = next;
        }
    }

    /* create QH */
    ehci_qh_t *qh = memalign(32, sizeof(ehci_qh_t));
    memset(qh, 0, sizeof(ehci_qh_t));
    qh->horiz_link_ptr = virt_to_phys(qh);
    qh->type = 1; // FIXME: proper symbols for type. this is QH
    qh->addr = ep->dev->address;
    qh->ep = endp;
    qh->eps = ep->dev->speed;
    qh->dtc = 0;
    qh->reclaim_head = 1;
    qh->max_packet_len = ep->maxpacketsize;
    qh->nak_cnt_reload = 0;
    qh->pipe_multiplier = 3;

    qh->td.next_qtd = virt_to_phys(head);
    qh->td.dt = ep->toggle;
    head->dt = ep->toggle;

    /* hook up QH */
    EHCI_INST(ep->dev->controller)->operation->asynclistaddr = virt_to_phys(qh);

    /* start async schedule */
    EHCI_INST(ep->dev->controller)->operation->async_sched_enable = 1;
    while (!EHCI_INST(ep->dev->controller)->operation->async_sched_status) ; /* wait */

    /* wait for result */
    result = wait_for_tds(head);

    /* disable async schedule */
    EHCI_INST(ep->dev->controller)->operation->async_sched_enable = 0;
    while (EHCI_INST(ep->dev->controller)->operation->async_sched_status) ; /* wait */

    ep->toggle = cur->dt;

    free_qh_and_tds(qh, head);
    return result;
}