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