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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <string.h>
13#include <barrelfish/barrelfish.h>
14
15#include <usb/usb.h>
16
17#include <usb_memory.h>
18
19#include "usb_ohci.h"
20#include "usb_ohci_memory.h"
21
22static struct usb_ohci_td *free_tds = NULL;
23static struct usb_ohci_ed *free_eds = NULL;
24
25static struct usb_page *free_pages = NULL;
26
27static struct usb_ohci_hcca *hcca = NULL;
28static usb_paddr_t hcca_phys = 0;
29
30struct usb_ohci_hcca *usb_ohci_hcca_alloc(void)
31{
32    if (hcca != NULL) {
33        return hcca;
34    }
35
36    // we do not have any free page anymore
37    if (free_pages == NULL) {
38        free_pages = usb_mem_page_alloc();
39    }
40
41    uint32_t ret_size;
42    struct usb_memory_block mem;
43
44    // allocate a new memory block in the usb page
45    ret_size = usb_mem_next_block(USB_OHCI_HCCA_SIZE, USB_OHCI_HCCA_ALIGN,
46            free_pages, &mem);
47
48    /*
49     * check if we have enough space, this may occur when we have just a few
50     * bytes left in the page, allocate new page and try again
51     */
52    if (ret_size < USB_OHCI_HCCA_SIZE) {
53        if (free_pages->free.size < sizeof(struct usb_ohci_ed)) {
54            /*
55             * TODO: memory waste
56             */
57        } else if (free_pages->free.size < 64) {
58            /*
59             * we can allocate a endpoint descriptor instead and store it
60             */
61            struct usb_ohci_ed *ed = usb_ohci_ed_alloc();
62            ed->obj_next = free_eds;
63            free_eds = ed;
64        }
65        // get a new page;
66        free_pages = usb_mem_page_alloc();
67    }
68
69    /*
70     * retry allocating a new hcca in the given block
71     */
72    ret_size = usb_mem_next_block(USB_OHCI_HCCA_SIZE, USB_OHCI_HCCA_ALIGN,
73            free_pages, &mem);
74
75    assert(ret_size >= USB_OHCI_HCCA_SIZE);
76
77    hcca = (struct usb_ohci_hcca *) mem.buffer;
78    hcca_phys = mem.phys_addr;
79
80    return hcca;
81}
82
83usb_paddr_t usb_ohci_hcca_physaddr(void)
84{
85    if (hcca_phys != 0) {
86        return hcca_phys;
87    }
88    usb_ohci_hcca_alloc();
89    return hcca_phys;
90}
91
92/**
93 * \brief   this function allocates a td descriptor used for the usb transfers
94 *
95 * \return  pointer to a usb_ohci_td struct
96 */
97struct usb_ohci_td *usb_ohci_td_alloc(void)
98{
99    struct usb_ohci_td * ret = NULL;
100
101    /*
102     * check if we have a free td left
103     */
104    if (free_tds != NULL) {
105        ret = free_tds;
106        free_tds = free_tds->obj_next;
107        ret->obj_next = NULL;
108        return ret;
109    }
110
111    uint32_t min_size = sizeof(struct usb_ohci_td);
112
113    // we do not have any free page anymore
114    if (free_pages == NULL) {
115        free_pages = usb_mem_page_alloc();
116    }
117
118    uint32_t ret_size;
119    struct usb_memory_block mem;
120
121    // allocate a new memory block in the usb page
122    ret_size = usb_mem_next_block(sizeof(struct usb_ohci_td), USB_OHCI_TD_ALIGN,
123            free_pages, &mem);
124
125    /*
126     * check if we have enough space, this may occur when we have just a few
127     * bytes left in the page, allocate new page and try again
128     */
129    if (ret_size < min_size) {
130        if (free_pages->free.size < 32) {
131            /*
132             * TODO: memory waste
133             */
134        } else if (free_pages->free.size < 64) {
135            /*
136             * we can allocate a endpoint descriptor instead and store it
137             */
138            struct usb_ohci_ed *ed = usb_ohci_ed_alloc();
139            ed->obj_next = free_eds;
140            free_eds = ed;
141        }
142        // get a new page;
143        free_pages = usb_mem_page_alloc();
144    }
145
146    /*
147     * retry allocating a new td descriptor in the given block
148     */
149    ret_size = usb_mem_next_block(sizeof(struct usb_ohci_td), USB_OHCI_TD_ALIGN,
150            free_pages, &mem);
151
152    assert(ret_size >= min_size);
153
154    // now we have memory for the td descriptor and we can set it up
155
156    ret = (struct usb_ohci_td *) mem.buffer;
157    ret->td_self = mem.phys_addr;
158    ret->td_current_buffer = mem.phys_addr + USB_OHCI_TD_BUFFER_OFFSET;
159    ret->td_buffer_end = ret->td_current_buffer + USB_OHCI_TD_BUFFER_SIZE;
160    ret->obj_next = NULL;
161
162    return ret;
163}
164
165void usb_ohci_td_free(struct usb_ohci_td *td)
166{
167    td->td_current_buffer = td->td_self + USB_OHCI_TD_BUFFER_OFFSET;
168    td->td_buffer_end = td->td_current_buffer + USB_OHCI_TD_BUFFER_SIZE;
169    td->td_nextTD = 0;
170    td->alt_next = NULL;
171    td->len = 0;
172    td->obj_next = free_tds;
173    free_tds = td;
174}
175
176struct usb_ohci_ed *usb_ohci_ed_alloc(void)
177{
178    struct usb_ohci_ed * ret = NULL;
179
180    /*
181     * check if we have a free td left
182     */
183    if (free_tds != NULL) {
184        ret = free_eds;
185        free_eds = free_eds->obj_next;
186        ret->obj_next = NULL;
187        return ret;
188    }
189
190    uint32_t min_size = sizeof(struct usb_ohci_ed);
191
192    // we do not have any free page anymore
193    if (free_pages == NULL) {
194        free_pages = usb_mem_page_alloc();
195    }
196
197    uint32_t ret_size;
198    struct usb_memory_block mem;
199
200    // allocate a new memory block in the usb page
201    ret_size = usb_mem_next_block(sizeof(struct usb_ohci_ed), USB_OHCI_ED_ALIGN,
202            free_pages, &mem);
203
204    /*
205     * check if we have enough space, this may occur when we have just a few
206     * bytes left in the page, allocate new page and try again
207     */
208    if (ret_size < min_size) {
209        if (free_pages->free.size < 32) {
210            /*
211             * TODO: memory waste
212             */
213        }
214        // get a new page;
215        free_pages = usb_mem_page_alloc();
216        /*
217         * retry allocating a new td descriptor in the given block
218         */
219        ret_size = usb_mem_next_block(sizeof(struct usb_ohci_ed),
220                USB_OHCI_ED_ALIGN, free_pages, &mem);
221    }
222
223    assert(ret_size >= min_size);
224
225    // now we have memory for the td descriptor and we can set it up
226
227    ret = (struct usb_ohci_ed *) mem.buffer;
228    memset(ret, 0, sizeof(struct usb_ohci_ed));
229
230    ret->ed_self = mem.phys_addr;
231
232    return ret;
233
234}
235
236void usb_ohci_ed_free(struct usb_ohci_ed *ed)
237{
238    /*
239     * delete the hardware part of the descriptor
240     */
241    memset(ed, 0, USB_OHCI_ED_HW_SIZE);
242    ed->obj_next = free_eds;
243    ed->prev = NULL;
244    ed->next = NULL;
245    free_eds = ed;
246}
247
248struct usb_ohci_itd *usb_ohci_itd_alloc(void)
249{
250    assert(!"NYI: allocating itd is not implemented. ");
251    return NULL;
252}
253
254void usb_ohci_itd_free(struct usb_ohci_itd *td)
255{
256    assert(!"NYI: freeing itd is not implemented. ");
257}
258
259usb_paddr_t usb_ohci_buffer_alloc(uint32_t size, uint32_t align)
260{
261    return 0;
262}
263
264void usb_ohci_buffer_free(usb_paddr_t buf)
265{
266
267}
268