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_controller.h> 18#include <usb_xfer.h> 19 20#include "usb_ehci.h" 21#include "usb_ehci_xfer.h" 22#include "usb_ehci_queue.h" 23 24 25/** 26 * \brief this function enqueues a transfer on the interrupt queue 27 * transfers on this queue are to be scheduled by the host controller 28 */ 29void usb_ehci_enqueue_xfer_intrq(struct usb_xfer *xfer) 30{ 31 USB_DEBUG_TR_ENTER; 32 33 /* 34 * check if the transfer is already finished 35 */ 36 if (usb_ehci_xfer_is_finished(xfer)) { 37 USB_DEBUG("NOTICE: transfer already finished...\n"); 38 return; 39 } 40 41 /* 42 * enqueue it on the transfer interrupt queue 43 */ 44 usb_xfer_enqueue(&xfer->host_controller->intr_queue, xfer); 45 46 /* 47 * TODO: start timeout handler, if the transfer takes too long to be executed 48 * then it should be removed with a timeout condition 49 * 50 * if (xfer->timeout != 0) { 51 * 52 * } 53 */ 54} 55 56/** 57 * \brief enqueues a new split isochronus transaction descriptor into the queue 58 * 59 * \param sitd the siTD to insert into the list 60 * \param last the last element of the list 61 */ 62usb_ehci_sitd_t *usb_ehci_enq_fs_td(usb_ehci_sitd_t *sitd, 63 usb_ehci_sitd_t *last) 64{ 65 /* 66 * update the virtual links 67 */ 68 sitd->next = last->next; 69 sitd->prev = last; 70 last->next = sitd; 71 72 /* 73 * update the physical links 74 */ 75 sitd->sitd_next = last->sitd_next; 76 last->sitd_next = sitd->sitd_self; 77 78 return (sitd); 79} 80 81/** 82 * \brief removes the element from the list 83 * 84 * \param sitd the siTD element to be removed 85 * \param last the last element of the list 86 */ 87usb_ehci_sitd_t *usb_ehci_deq_fs_td(usb_ehci_sitd_t *sitd, 88 usb_ehci_sitd_t *last) 89{ 90 /* 91 * update virtual pointers 92 */ 93 sitd->prev->next = sitd->next; 94 95 /* 96 * update the physical links 97 */ 98 sitd->prev->sitd_next = sitd->sitd_next; 99 100 if (sitd->next) { 101 sitd->next->prev = sitd->prev; 102 } 103 104 return ((last == sitd) ? sitd->prev : last); 105} 106 107/* 108 * \brief enqueues a new isochronus transaction descriptor into the queue 109 * 110 * \param std the iTD to insert into the list 111 * \param last the last element of the list 112 */ 113usb_ehci_itd_t *usb_ehci_enq_hs_td(usb_ehci_itd_t *std, usb_ehci_itd_t *last) 114{ 115 /* 116 * update the virtual links 117 */ 118 std->next = last->next; 119 std->prev = last; 120 last->next = std; 121 122 /* 123 * update the physical links 124 */ 125 std->itd_next = last->itd_next; 126 last->itd_next = std->itd_self; 127 128 return (std); 129 130} 131 132/** 133 * \brief removes a high speed isochronus transfer descriptor from the list 134 * 135 * \param std the iTD to be removed 136 * \param last the last element of the list 137 */ 138usb_ehci_itd_t *usb_ehci_deq_hs_td(usb_ehci_itd_t *std, usb_ehci_itd_t *last) 139{ 140 /* 141 * update virtual pointers 142 */ 143 std->prev->next = std->next; 144 145 /* 146 * update the physical links 147 */ 148 std->prev->itd_next = std->itd_next; 149 150 if (std->next) { 151 std->next->prev = std->prev; 152 } 153 154 return ((last == std) ? std->prev : last); 155} 156 157/** 158 * \brief enqueues a queue head descriptor into the qh list 159 * 160 * \param qh the queue head descriptor to insert 161 * \param last the last element fo the list 162 */ 163usb_ehci_qh_t *usb_ehci_enq_qh(usb_ehci_qh_t *qh, usb_ehci_qh_t *last) 164{ 165 USB_DEBUG_TR_ENTER; 166 167 /* 168 * a queue head can only be linked once 169 */ 170 if (qh->prev != NULL) { 171 USB_DEBUG("NOTICE: Tried to double enqueue a queue head\n"); 172 return (last); 173 } 174 175 qh->next = last->next; 176 qh->qh_link = last->qh_link; 177 178 qh->prev = last; 179 180 last->next = qh; 181 last->qh_link = qh->qh_self | USB_EHCI_LINKTYPE_QH; 182 183 return (qh); 184} 185 186/** 187 * \brief removes a queue head from the qh list 188 * 189 * \param qh the queue head to be removed 190 * \param last the last element of the list 191 */ 192usb_ehci_qh_t *usb_ehci_deq_qh(usb_ehci_qh_t *qh, usb_ehci_qh_t *last) 193{ 194 /* 195 * check if the queue head is in fact on a list 196 */ 197 if (qh->prev == NULL) { 198 return (last); 199 } 200 201 /* 202 * update virtual pointers 203 */ 204 qh->prev->next = qh->next; 205 206 /* 207 * update physical pointer 208 */ 209 qh->prev->qh_link = qh->qh_link; 210 211 if (qh->next) { 212 qh->next->prev = qh->prev; 213 } 214 215 last = ((last == qh) ? qh->prev : last); 216 217 qh->prev = NULL; 218 219 return (last); 220 221} 222