1/**
2 * \brief this file contains the initialization code for the generic
3 *        host controller
4 */
5
6/*
7 * Copyright (c) 2007-2013 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18
19#include <barrelfish/barrelfish.h>
20
21#include <usb/usb.h>
22
23#include <usb_controller.h>
24#include <usb_device.h>
25
26#include "controller/ohci/usb_ohci.h"
27#include "controller/uhci/usb_uhci.h"
28#include "controller/ehci/usb_ehci.h"
29#include "controller/xhci/usb_xhci.h"
30
31/// list of currently available host controllers
32static usb_host_controller_t *host_controllers = NULL;
33
34/**
35 * \brief initializes the USB host controller
36 *
37 * \param hc pointer ot the generic host controller
38 * \param version the version [{O, U, E, X}HCI]
39 * \param controller_base the base address of the controller
40 */
41usb_error_t usb_hc_init(usb_host_controller_t *hc, usb_hc_version_t version,
42        uintptr_t controller_base)
43{
44    if (hc == NULL) {
45        return (USB_ERR_NOMEM);
46    }
47
48    /* initialize the done queue and the interrupt queue of the host controller*/
49    hc->done_queue.head.first = NULL;
50    hc->done_queue.head.last_next = &(hc->done_queue.head.first);
51
52    hc->intr_queue.head.first = NULL;
53    hc->intr_queue.head.last_next = &(hc->intr_queue.head.first);
54
55    usb_error_t err = USB_ERR_INVAL;
56    void *controller;
57
58    /* initalize the specific host controller */
59    switch (version) {
60        case USB_UHCI:
61            USER_PANIC("UHCI controller currently not supported\n");
62            break;
63        case USB_OHCI:
64            /* XXX: some functionality is implemented, but not tested... */
65            controller = malloc(sizeof(usb_ohci_hc_t));
66            if (controller == NULL) {
67                return (USB_ERR_NOMEM);
68            }
69            memset(controller, 0, sizeof(usb_ohci_hc_t));
70            hc->hc_type = USB_OHCI;
71            hc->hc_control = controller;
72            ((usb_ohci_hc_t*) controller)->controller = hc;
73            err = usb_ohci_init((usb_ohci_hc_t*) controller,
74                    (uintptr_t) controller_base);
75            break;
76        case USB_EHCI:
77            /* allocate the ehci controller */
78            controller = malloc(sizeof(usb_ehci_hc_t));
79
80            if (controller == NULL) {
81                return (USB_ERR_NOMEM);
82            }
83            memset(controller, 0, sizeof(usb_ehci_hc_t));
84
85            /* associate it with the generic host controller */
86            hc->hc_type = USB_EHCI;
87            hc->hc_control = controller;
88            ((usb_ehci_hc_t*) controller)->controller = hc;
89
90            /* set the interrupt handler function */
91            hc->handle_intr = usb_ehci_interrupt;
92
93            /* initalize the controller */
94            err = usb_ehci_init((usb_ehci_hc_t*) controller, controller_base);
95            break;
96        case USB_XHCI:
97            USER_PANIC("XHCI controller currently not supported\n");
98            break;
99        default:
100            return (USB_ERR_INVAL);
101            break;
102
103    }
104
105    /* on success: link the new controller into the host controller list */
106    if (err == USB_ERR_OK) {
107        if (host_controllers == NULL) {
108            hc->next = NULL;
109            hc->prev_next = NULL;
110            host_controllers = hc;
111        } else {
112            hc->next = host_controllers;
113            host_controllers->prev_next = &(hc->next);
114            host_controllers = hc;
115        }
116        hc->initialized = 1;
117
118        return (USB_ERR_OK);
119    }
120
121    return (err);
122
123}
124
125/**
126 *  \brief interrupt handler function for host controller interrupts
127 *
128 *  \param arg currently null
129 *
130 *  This function is called on every interrupt. The interrupt is then forwared
131 *  to the specific interrupt handler functions of the respective HCs
132 */
133void usb_hc_intr_handler(void *arg)
134{
135    usb_host_controller_t *hc = host_controllers;
136
137    while (hc != NULL) {
138        if (hc->handle_intr != NULL) {
139            (hc->handle_intr)(hc);
140        }
141        hc = hc->next;
142    }
143}
144