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
17#include <usb_device.h>
18#include <usb_controller.h>
19#include <usb_hub.h>
20#include <usb_xfer.h>
21
22#include "usb_ehci.h"
23#include "usb_ehci_pipe.h"
24#include "usb_ehci_queue.h"
25#include "usb_ehci_xfer.h"
26
27
28
29/*
30 * -------------------------------------------------------------------------
31 * EHCI bulk transfer support
32 * -------------------------------------------------------------------------
33 */
34
35/**
36 * \brief handles the pipe open event of a new bulk transfer
37 */
38static void usb_ehci_xfer_bulk_open(struct usb_xfer *xfer)
39{
40    return; /* no-op */
41}
42
43
44/**
45 * \brief handles cancel event of an bulk xfer. this removes the
46 *        transfer from the queues with the cancelled state
47 */
48static void usb_ehci_xfer_bulk_close(struct usb_xfer *xfer)
49{
50    usb_ehci_xfer_remove(xfer, USB_ERR_CANCELLED);
51}
52
53
54/**
55 *  \brief handles the enter event of a new bulk xfer,
56 *         there is nothing to do, thus this is a no-op.
57 */
58static void usb_ehci_xfer_bulk_enter(struct usb_xfer *xfer)
59{
60    return; /* no-op */
61}
62
63/**
64 * \brief handles the start event of a new bulk xfer
65 */
66static void usb_ehci_xfer_bulk_start(struct usb_xfer *xfer)
67{
68    // get the host controller of this transfer
69    usb_ehci_hc_t *hc = (usb_ehci_hc_t *) (xfer->host_controller->hc_control);
70
71    /* setup the standard transfer descriptors */
72    usb_ehci_xfer_standard_setup(xfer, &(hc->qh_async_last));
73
74    /* enqueue on the xfer interrupt queue*/
75    usb_ehci_enqueue_xfer_intrq(xfer);
76}
77
78/// stores the function pointers to the bulk pipe functions
79static struct usb_hcdi_pipe_fn usb_ehci_bulk_pipe_fn = {
80        .open = usb_ehci_xfer_bulk_open,
81        .close = usb_ehci_xfer_bulk_close,
82        .enter = usb_ehci_xfer_bulk_enter,
83        .start = usb_ehci_xfer_bulk_start
84};
85
86/**
87 * \brief gets the function pointers for bulk pipe functions
88 */
89struct usb_hcdi_pipe_fn *usb_ehci_get_bulk_pipe_fn(void)
90{
91    return (&usb_ehci_bulk_pipe_fn);
92}
93
94
95/*
96 * -------------------------------------------------------------------------
97 * EHCI control transfer support
98 * -------------------------------------------------------------------------
99 */
100
101/**
102 * \brief opens a new control transfer pipe, there is nothing to be done
103 *        here, thus this is a no-op
104 */
105static void usb_ehci_xfer_ctrl_open(struct usb_xfer *xfer)
106{
107    USB_DEBUG_TR_ENTER;
108
109    return; /* no-op */
110}
111
112/**
113 * \brief closes a control transfer pipe and canceles outstanding requests
114 */
115static void usb_ehci_xfer_ctrl_close(struct usb_xfer *xfer)
116{
117    USB_DEBUG_TR_ENTER;
118
119    usb_ehci_xfer_remove(xfer, USB_ERR_CANCELLED);
120}
121
122/**
123 * \brief handles the control transfer enter event, there is nothing to be
124 *        done here
125 */
126static void usb_ehci_xfer_ctrl_enter(struct usb_xfer *xfer)
127{
128    USB_DEBUG_TR_ENTER;
129
130    return; /* no-op */
131}
132
133/**
134 * \brief handles the start event of a new control xfer
135 */
136static void usb_ehci_xfer_ctrl_start(struct usb_xfer *xfer)
137{
138    USB_DEBUG_TR_ENTER;
139
140    // get the host controller of this transfer
141    usb_ehci_hc_t *hc = (usb_ehci_hc_t *) (xfer->host_controller->hc_control);
142
143    assert(xfer->error == USB_ERR_OK);
144
145    /* setup the standard transfer descriptors */
146    usb_ehci_xfer_standard_setup(xfer, &(hc->qh_async_last));
147
148    assert(xfer->error == USB_ERR_OK);
149
150    /* enqueue on the xfer interrupt queue*/
151    usb_ehci_enqueue_xfer_intrq(xfer);
152
153    USB_DEBUG_TR_RETURN;
154}
155
156
157static struct usb_hcdi_pipe_fn usb_ehci_ctrl_pipe_fn = {
158        .open = usb_ehci_xfer_ctrl_open,
159        .close = usb_ehci_xfer_ctrl_close,
160        .enter = usb_ehci_xfer_ctrl_enter,
161        .start = usb_ehci_xfer_ctrl_start
162};
163
164/**
165 * \brief returns the function pointers of the control pipe type
166 */
167struct usb_hcdi_pipe_fn *usb_ehci_get_ctrl_pipe_fn(void)
168{
169    return (&usb_ehci_ctrl_pipe_fn);
170}
171
172
173/*
174 * -------------------------------------------------------------------------
175 * EHCI interrupt transfer type support
176 * -------------------------------------------------------------------------
177 */
178
179/**
180 * \brief handles the opening event of an interrupt transfer
181 */
182static void usb_ehci_xfer_intr_open(struct usb_xfer *xfer)
183{
184    USB_DEBUG_TR_ENTER;
185
186    // get the host controller of this transfer
187    usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
188
189    usb_hub_bandwidth_alloc(xfer);
190
191    /*
192     * find the best qh position for the given interrupt interval
193     */
194
195    uint16_t interval = USB_EHCI_VFRAMELIST_COUNT / 2;
196    uint16_t match = 0;
197    uint16_t tmp = 0;
198
199    while(interval) {
200        if (xfer->interval >= interval) {
201            tmp = interval;
202            match = interval;
203            while (tmp & interval) {
204                if (hc->qh_intr_stat[tmp] < hc->qh_intr_stat[match]) {
205                    match = tmp;
206                }
207                tmp++;
208            }
209            break;
210        }
211        interval >>= 1;
212    }
213
214    hc->qh_intr_stat[match]++;
215
216    xfer->intr_qh_pos = match;
217
218}
219
220/**
221 * \brief handles the closing of an interrupt pipe
222 */
223static void usb_ehci_xfer_intr_close(struct usb_xfer *xfer)
224{
225    USB_DEBUG_TR_ENTER;
226
227    // get the host controller of this transfer
228    usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
229
230    // decrease the number of interrupt transfers
231    hc->qh_intr_stat[xfer->intr_qh_pos]--;
232
233    // remove the bandwidth
234    usb_ehci_xfer_remove(xfer, USB_ERR_CANCELLED);
235
236    /* we have allocated the bandwidth, so we have to free it again */
237    usb_hub_bandwidth_free(xfer);
238}
239
240/**
241 * \brief handles the enter event of an interupt transfer, this is a noop
242 */
243static void usb_ehci_xfer_intr_enter(struct usb_xfer *xfer)
244{
245    USB_DEBUG_TR_ENTER;
246
247    return; /* no-op */
248}
249
250static void usb_ehci_xfer_intr_start(struct usb_xfer *xfer)
251{
252    USB_DEBUG_TR_ENTER;
253
254    assert(xfer != NULL);
255
256   // get the host controller of this transfer
257   usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
258
259   /* setup the transfer descriptors */
260   usb_ehci_xfer_standard_setup(xfer, &hc->qh_intr_last[xfer->intr_qh_pos]);
261
262   usb_ehci_enqueue_xfer_intrq(xfer);
263}
264
265/// function pointers to the interrupt pointers
266static struct usb_hcdi_pipe_fn usb_ehci_intr_pipe_fn = {
267        .open = usb_ehci_xfer_intr_open,
268        .close = usb_ehci_xfer_intr_close,
269        .enter = usb_ehci_xfer_intr_enter,
270        .start = usb_ehci_xfer_intr_start
271};
272
273/**
274 * \brief gets the function pointers of the intr type transfer functions
275 */
276struct usb_hcdi_pipe_fn *usb_ehci_get_intr_pipe_fn(void)
277{
278    return (&usb_ehci_intr_pipe_fn);
279}
280
281
282/*
283 * -------------------------------------------------------------------------
284 * EHCI high speed isochronus transfer support
285 * -------------------------------------------------------------------------
286 */
287
288/**
289 * \brief handles the open event for an high speed isochronus transfer
290 */
291static void usb_ehci_xfer_hs_isoc_open(struct usb_xfer *xfer)
292{
293    // get the host controller of this transfer
294    //usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
295    assert(!"NYI");
296}
297
298/**
299 * \brief handles the close event for an high speed isochronus transfer
300 */
301static void usb_ehci_xfer_hs_isoc_close(struct usb_xfer *xfer)
302{
303    usb_ehci_xfer_remove(xfer, USB_ERR_CANCELLED);
304}
305
306/**
307 * \brief handles the enter event for a high speed isochronus transfer
308 */
309static void usb_ehci_xfer_hs_isoc_enter(struct usb_xfer *xfer)
310{
311    // get the host controller of this transfer
312    //usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
313    assert(!"NYI");
314}
315
316/**
317 * \brief handles the start event for a high speed isochronus transfer
318 */
319static void usb_ehci_xfer_hs_isoc_start(struct usb_xfer *xfer)
320{
321    // get the host controller of this transfer
322    //usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
323    assert(!"NYI");
324}
325
326
327/// function pointers to the interrupt pointers
328static struct usb_hcdi_pipe_fn usb_ehci_hs_isoc_pipe_fn = {
329        .open = usb_ehci_xfer_hs_isoc_open,
330        .close = usb_ehci_xfer_hs_isoc_close,
331        .enter = usb_ehci_xfer_hs_isoc_enter,
332        .start = usb_ehci_xfer_hs_isoc_start
333};
334
335/**
336 * \brief gets the function pointers of the intr type transfer functions
337 */
338struct usb_hcdi_pipe_fn *usb_ehci_get_hs_isoc_pipe_fn(void)
339{
340    return (&usb_ehci_hs_isoc_pipe_fn);
341}
342
343
344/*
345 * -------------------------------------------------------------------------
346 * EHCI full speed isochronus transfer support
347 * -------------------------------------------------------------------------
348 */
349
350/**
351 * \brief handles the open event for an full speed isochronus transfer
352 */
353static void usb_ehci_xfer_fs_isoc_open(struct usb_xfer *xfer)
354{
355    // get the host controller of this transfer
356    //usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
357
358    assert(!"NYI");
359}
360
361/**
362 * \brief handles the close event for an full speed isochronus transfer
363 */
364static void usb_ehci_xfer_fs_isoc_close(struct usb_xfer *xfer)
365{
366    usb_ehci_xfer_remove(xfer, USB_ERR_CANCELLED);
367}
368
369/**
370 * \brief handles the enter event for a full speed isochronus transfer
371 */
372static void usb_ehci_xfer_fs_isoc_enter(struct usb_xfer *xfer)
373{
374    // get the host controller of this transfer
375    //usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
376
377    assert(!"NYI");
378}
379
380/**
381 * \brief handles the start event for a full speed isochronus transfer
382 */
383static void usb_ehci_xfer_fs_isoc_start(struct usb_xfer *xfer)
384{
385    // get the host controller of this transfer
386    //usb_ehci_hc_t *hc = (usb_ehci_hc_t *) xfer->host_controller->hc_control;
387    assert(!"NYI");
388}
389
390
391/// function pointers to the interrupt pointers
392static struct usb_hcdi_pipe_fn usb_ehci_fs_isoc_pipe_fn = {
393        .open = usb_ehci_xfer_fs_isoc_open,
394        .close = usb_ehci_xfer_fs_isoc_close,
395        .enter = usb_ehci_xfer_fs_isoc_enter,
396        .start = usb_ehci_xfer_fs_isoc_start
397};
398
399/**
400 * \brief gets the function pointers of the full speed isochronus transfer
401 */
402struct usb_hcdi_pipe_fn *usb_ehci_get_fs_isoc_pipe_fn(void)
403{
404    return (&usb_ehci_fs_isoc_pipe_fn);
405}
406