1/*
2 * Copyright (c) 2007-2013 ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <barrelfish/barrelfish.h>
13
14#include <usb/usb.h>
15
16#include <usb_xfer.h>
17#include <usb_device.h>
18#include <usb_controller.h>
19#include <usb_hub.h>
20#include "usb_ohci.h"
21#include "usb_ohci_pipe.h"
22
23#include "usb_ohci_xfer.h"
24
25/*
26 * ------------------------------------------------------------------------
27 * OHCI General Pipe Function
28 * ------------------------------------------------------------------------
29 */
30
31/*
32 * ------------------------------------------------------------------------
33 * OHCI Bulk Pipe Functions
34 * ------------------------------------------------------------------------
35 * These functions provide OHCI specific implementations for bulk type
36 * pipes.
37 */
38static void
39usb_ohci_xfer_bulk_open(struct usb_xfer *xfer);
40static void
41usb_ohci_xfer_bulk_close(struct usb_xfer *xfer);
42static void
43usb_ohci_xfer_bulk_enter(struct usb_xfer *xfer);
44static void
45usb_ohci_xfer_bulk_start(struct usb_xfer *xfer);
46
47// data structure containing the function pointers
48struct usb_hcdi_pipe_fn usb_ohci_xfer_bulk_fun = {
49.open = usb_ohci_xfer_bulk_open, .close = usb_ohci_xfer_bulk_close, .enter =
50        usb_ohci_xfer_bulk_enter, .start = usb_ohci_xfer_bulk_start
51};
52
53/**
54 * \brief Function to open a bulk pipe. Bulk types do not need any
55 *        processing so this is a noop.
56 *
57 * \param xfer  usb transfer request
58 */
59static void usb_ohci_xfer_bulk_open(struct usb_xfer *xfer)
60{
61    return; /* noop */
62}
63
64/**
65 * \brief Function to close a bulk pipe. Calling this function
66 *        means to cancel all outstanding requests for this pipe.
67 *
68 * \param xfer  usb transfer request
69 */
70static void usb_ohci_xfer_bulk_close(struct usb_xfer *xfer)
71{
72    usb_ohci_xfer_remove(xfer, USB_ERR_CANCELLED);
73}
74
75/**
76 * \brief Function to enter a bulk pipe. Bulk type pipes do not need
77 *        to be entered thus this is a noop.
78 *
79 * \param xfer  usb transfer request
80 */
81static void usb_ohci_xfer_bulk_enter(struct usb_xfer *xfer)
82{
83    return; /* noop */
84}
85
86/**
87 * \brief Function to start a bulk pipe. This function sets up the
88 queues for the requests
89 *
90 * \param xfer  usb transfer request
91 */
92static void usb_ohci_xfer_bulk_start(struct usb_xfer *xfer)
93{
94    // get the host controller of this transfer
95    usb_ohci_hc_t *hc = (usb_ohci_hc_t *) xfer->host_controller->hc_control;
96
97    // setup the transfer descriptors and queue heads
98    usb_ohci_xfer_start(xfer, &hc->qh_bulk_last);
99
100    // enqueue it on the interrupt queue
101    usb_ohci_xfer_enqueue(xfer);
102}
103
104/*
105 * ------------------------------------------------------------------------
106 * OHCI Control Pipe Functions
107 * ------------------------------------------------------------------------
108 * These functions provide OHCI specific implementations for control type
109 * pipes.
110 */
111static void
112usb_ohci_xfer_ctrl_open(struct usb_xfer *xfer);
113static void
114usb_ohci_xfer_ctrl_close(struct usb_xfer *xfer);
115static void
116usb_ohci_xfer_ctrl_enter(struct usb_xfer *xfer);
117static void
118usb_ohci_xfer_ctrl_start(struct usb_xfer *xfer);
119
120// data structure containing the function pointers
121struct usb_hcdi_pipe_fn usb_ohci_xfer_ctrl_fun = {
122.open = usb_ohci_xfer_ctrl_open, .close = usb_ohci_xfer_ctrl_close, .enter =
123        usb_ohci_xfer_ctrl_enter, .start = usb_ohci_xfer_ctrl_start
124};
125
126/**
127 * \brief Function to open a control pipe. Control pipes do not need any
128 *        processing so this is a noop.
129 *
130 * \param xfer  usb transfer request
131 */
132static void usb_ohci_xfer_ctrl_open(struct usb_xfer *xfer)
133{
134    return; /* just a noop */
135}
136
137/**
138 * \brief Function to close a control pipe. Calling this function
139 *        means to cancel all outstanding requests for this pipe.
140 *
141 * \param xfer  usb transfer request
142 */
143static void usb_ohci_xfer_ctrl_close(struct usb_xfer *xfer)
144{
145    usb_ohci_xfer_remove(xfer, USB_ERR_CANCELLED);
146}
147
148/**
149 * \brief Function to enter a control pipe. Control pipes do not need
150 *        to be entered thus this is a noop.
151 *
152 * \param xfer  usb transfer request
153 */
154static void usb_ohci_xfer_ctrl_enter(struct usb_xfer *xfer)
155{
156    return; /* noop */
157}
158
159/**
160 * \brief Function to start a control pipe. This function sets up the
161 queues for the requests
162 *
163 * \param xfer  usb transfer request
164 */
165static void usb_ohci_xfer_ctrl_start(struct usb_xfer *xfer)
166{
167    // get the host controller
168    usb_ohci_hc_t *hc = (usb_ohci_hc_t *) xfer->host_controller->hc_control;
169
170    // setup the queue heads and transfer descriptors
171    usb_ohci_xfer_start(xfer, &hc->qh_ctrl_last);
172
173    // enqueue it on the interrupt queue
174    usb_ohci_xfer_enqueue(xfer);
175}
176
177/*
178 * ------------------------------------------------------------------------
179 * OHCI Interrupt Pipe Functions
180 * ------------------------------------------------------------------------
181 * These functions provide OHCI specific implementations for interrupt type
182 * pipes.
183 */
184static void
185usb_ohci_xfer_intr_open(struct usb_xfer *xfer);
186static void
187usb_ohci_xfer_intr_close(struct usb_xfer *xfer);
188static void
189usb_ohci_xfer_intr_enter(struct usb_xfer *xfer);
190static void
191usb_ohci_xfer_intr_start(struct usb_xfer *xfer);
192
193// data structure containing the function pointers
194struct usb_hcdi_pipe_fn usb_ohci_xfer_intr_fun = {
195.open = usb_ohci_xfer_intr_open, .close = usb_ohci_xfer_intr_close, .enter =
196        usb_ohci_xfer_intr_enter, .start = usb_ohci_xfer_intr_start
197};
198
199/**
200 * \brief Function to open a interrupt pipe. Requests on interrupt
201 *        pipes need to be paced on the correct position in the
202 *        interrupt tree. This function places the transfer request
203 *        in the positions indicated by the xfer->interval field.
204 *
205 * \param xfer  usb transfer request
206 */
207static void usb_ohci_xfer_intr_open(struct usb_xfer *xfer)
208{
209    usb_ohci_hc_t *hc = (usb_ohci_hc_t *) xfer->host_controller->hc_control;
210
211    uint16_t best;
212    uint16_t bit;
213    uint16_t x;
214
215    best = 0;
216    /*
217     * we have USB_OHCI_NO_EP_DESCRIPTORS total endpoint descriptors
218     * in the interrupt transfer lists. This consist of half
219     * interrupt endpoints and half isochronus endpoints
220     */
221    bit = USB_OHCI_NO_EP_DESCRIPTORS / 2;
222
223    /*
224     * loop over the possible interrupt intervals and find the best
225     * bucket to place it. i.e. where the least transfers are
226     */
227    while (bit) {
228        if (xfer->interval >= bit) {
229            x = bit;
230            best = bit;
231            while (x & bit) {
232                if (hc->intr_stats[x] < hc->intr_stats[best]) {
233                    best = x;
234                }
235                x++;
236            }
237            break;
238        }
239        bit >>= 1;
240    }
241
242    // we are going to add the transfer into this interval
243    hc->intr_stats[best]++;
244    xfer->intr_qh_pos = best;
245}
246
247/**
248 * \brief Function to close a interrupt pipe. Calling this function
249 *        means to cancel all outstanding requests for this pipe.
250 *
251 * \param xfer  usb transfer request
252 */
253static void usb_ohci_xfer_intr_close(struct usb_xfer *xfer)
254{
255    // get the host controller
256    usb_ohci_hc_t *hc = (usb_ohci_hc_t *) xfer->host_controller->hc_control;
257
258    // update the usage statistics for the interval type
259    hc->intr_stats[xfer->intr_qh_pos]--;
260
261    // remove the transfer
262    usb_ohci_xfer_remove(xfer, USB_ERR_CANCELLED);
263}
264
265/**
266 * \brief Function to enter a interrupt pipe. Interrupt pipes do not need
267 *        to be entered thus this is a noop.
268 *
269 * \param xfer  usb transfer request
270 */
271static void usb_ohci_xfer_intr_enter(struct usb_xfer *xfer)
272{
273    return; /* noop */
274}
275
276/**
277 * \brief Function to start a interrupt pipe. This function sets up the
278 queues for the requests
279 *
280 * \param xfer  usb transfer request
281 */
282static void usb_ohci_xfer_intr_start(struct usb_xfer *xfer)
283{
284    // get the host controller
285    usb_ohci_hc_t *hc = (usb_ohci_hc_t *) xfer->host_controller->hc_control;
286
287    // setup the queue heads and the transfer descriptors
288    usb_ohci_xfer_start(xfer, &hc->qh_intr_last[xfer->intr_qh_pos]);
289
290    // enqueue it on the interrupt queue
291    usb_ohci_xfer_enqueue(xfer);
292}
293
294/*
295 * ------------------------------------------------------------------------
296 * OHCI Isochronus Pipe Functions
297 * ------------------------------------------------------------------------
298 * These functions provide OHCI specific implementations for Isochronus type
299 * pipes.
300 */
301static void
302usb_ohci_xfer_isoc_open(struct usb_xfer *xfer);
303static void
304usb_ohci_xfer_isoc_close(struct usb_xfer *xfer);
305static void
306usb_ohci_xfer_isoc_enter(struct usb_xfer *xfer);
307static void
308usb_ohci_xfer_isoc_start(struct usb_xfer *xfer);
309
310// data structure containing the function pointers
311struct usb_hcdi_pipe_fn usb_ohci_xfer_isoc_fun = {
312.open = usb_ohci_xfer_isoc_open, .close = usb_ohci_xfer_isoc_close, .enter =
313        usb_ohci_xfer_isoc_enter, .start = usb_ohci_xfer_isoc_start
314};
315
316/**
317 * \brief Function to open a isochronus pipe. There is no special
318 *        handling for opening a isochronus pipe.
319 *
320 * \param xfer  usb transfer request
321 */
322static void usb_ohci_xfer_isoc_open(struct usb_xfer *xfer)
323{
324    return; /* noop */
325}
326
327/**
328 * \brief Function to close a isochronus pipe. Calling this function
329 *        means to cancel all outstanding requests for this pipe.
330 *
331 * \param xfer  usb transfer request
332 */
333static void usb_ohci_xfer_isoc_close(struct usb_xfer *xfer)
334{
335    usb_ohci_xfer_remove(xfer, USB_ERR_CANCELLED);
336}
337
338/**
339 * \brief Function to enter a isochronus pipe. Here we have to place
340 *        isochronus request on the correct position after the
341 *        last interrupt request on the interrupt tree.
342 *
343 * \param xfer  usb transfer request
344 */
345static void usb_ohci_xfer_isoc_enter(struct usb_xfer *xfer)
346{
347    // TODO: Implement
348    assert(!"NYI: cannot create isochronus transfers at this time");
349}
350
351/**
352 * \brief Function to start a interrupt pipe. This function sets up the
353 queues for the requests
354 *
355 * \param xfer  usb transfer request
356 */
357static void usb_ohci_xfer_isoc_start(struct usb_xfer *xfer)
358{
359    // put the transfer on the interrupt queue
360    usb_ohci_xfer_enqueue(xfer);
361}
362
363/*
364 * Exported functions
365 */
366
367struct usb_hcdi_pipe_fn *usb_ohci_get_bulk_pipe_fn(void)
368{
369    return &usb_ohci_xfer_bulk_fun;
370}
371
372struct usb_hcdi_pipe_fn *usb_ohci_get_ctrl_pipe_fn(void)
373{
374    return &usb_ohci_xfer_ctrl_fun;
375}
376
377struct usb_hcdi_pipe_fn *usb_ohci_get_isoc_pipe_fn(void)
378{
379    return &usb_ohci_xfer_isoc_fun;
380}
381
382struct usb_hcdi_pipe_fn *usb_ohci_get_intr_pipe_fn(void)
383{
384    return &usb_ohci_xfer_intr_fun;
385}
386