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 <string.h> 12#include <barrelfish/barrelfish.h> 13 14#include <usb/usb.h> 15#include <usb/usb_descriptor.h> 16 17#include <usb_controller.h> 18 19#include <usb_xfer.h> 20#include <usb_pipe.h> 21 22 23/** 24 * \brief this function handles the start of a new transfer when it is on the 25 * endpoint queue 26 */ 27void usb_pipe_start(struct usb_xfer_queue *queue) 28{ 29 USB_DEBUG_TR_ENTER; 30 31 /* get the xfer from the queue */ 32 struct usb_xfer *xfer = queue->current; 33 34 assert(xfer != NULL); 35 36 struct usb_endpoint *ep = xfer->endpoint; 37 38 uint8_t type; 39 40 if (ep->is_stalled) { 41 USB_DEBUG_XFER("NOTICE: endpoint is already stalled...\n"); 42 43 USB_DEBUG_TR_RETURN; 44 return; 45 } 46 47 if (xfer->flags.pipe_stalled) { 48 USB_DEBUG("NOTICE: Stalling pipe...\n"); 49 /* TODO: Stall pipe */ 50 assert(!"NYI: Stall pipe"); 51 } 52 53 if (xfer->num_frames == 0) { 54 USB_DEBUG_XFER("NOTICE: No frames to process... finishing transfer"); 55 xfer->actual_frames = 0; 56 usb_xfer_done(xfer, USB_ERR_OK); 57 USB_DEBUG_TR_RETURN; 58 return; 59 } 60 61 if (xfer->interval > 0) { 62 type = (ep->descriptor->bmAttributes.xfer_type); 63 switch (type) { 64 case USB_ENDPOINT_TYPE_BULK: 65 case USB_ENDPOINT_TYPE_CONTROL: 66 /* TODO: Delay the transfer start... */ 67 assert(!"NYI: delayed start"); 68 return; 69 break; 70 default: 71 /* noop */ 72 break; 73 } 74 } 75 76 if (xfer->error == USB_ERR_OK) { 77 xfer->flags_internal.notify = 1; 78 /* call the start function */ 79 ep->pipe_fn->start(xfer); 80 } 81 82 xfer->flags_internal.cancellable = 1; 83 84 if (xfer->error != USB_ERR_OK) { 85 /* there was an error while starting, cancel the transfer */ 86 usb_xfer_done(xfer, 0); 87 } 88 USB_DEBUG_TR_RETURN; 89 90} 91 92/** 93 * \brief this function handles the event when a new transfer enters the system 94 * 95 */ 96void usb_pipe_enter(struct usb_xfer *xfer) 97{ 98 USB_DEBUG_TR_ENTER; 99 100 assert(xfer != NULL); 101 102 struct usb_endpoint *ep = xfer->endpoint; 103 104 /* call the enter function of the pipe */ 105 (ep->pipe_fn->enter)(xfer); 106 107 xfer->flags_internal.cancellable = 1; 108 109 if (xfer->error != USB_ERR_OK) { 110 USB_DEBUG("ERROR: xfer returned with error..."); 111 usb_xfer_done(xfer, 0); 112 USB_DEBUG_TR_RETURN; 113 return; 114 } 115 116 if (ep->transfers.current != xfer) { 117 /* there is already a transfer happening, so enqueue it on the endpoint */ 118 usb_xfer_enqueue(&ep->transfers, xfer); 119 120 if (ep->transfers.current != NULL) { 121 USB_DEBUG_XFER("Some thing is already processing...\n"); 122 123 USB_DEBUG_TR_RETURN; 124 return; 125 } 126 } 127 128 if (!ep->transfers.recurse_1) { 129 ep->transfers.recurse_1 = 1; 130 if (ep->transfers.current == NULL) { 131 xfer = ep->transfers.head.first; 132 133 if (xfer) { 134 if (xfer->wait_entry.next != NULL) { 135 xfer->wait_entry.next->wait_entry.prev_next = xfer 136 ->wait_entry.prev_next; 137 *(xfer->wait_entry.prev_next) = xfer->wait_entry.next; 138 } else { 139 (&ep->transfers.head)->last_next = &(&ep->transfers.head)->first; 140 (&ep->transfers.head)->first = NULL; 141 //xfer->wait_entry.prev_next; 142 xfer->wait_entry.prev_next = &xfer->wait_entry.next; 143 } 144 xfer->wait_queue = NULL; 145 /* set the current xfer to be handled in the queue */ 146 ep->transfers.current = xfer; 147 USB_DEBUG_XFER("ep->transfers.command\n"); 148 /* execute the start command on the new xfer on the endpoint */ 149 (ep->transfers.command)(&ep->transfers); 150 } 151 ep->transfers.recurse_1 = 0; 152 } 153 } 154 155 USB_DEBUG_TR_RETURN; 156} 157