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