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 "ohci_device.h" 15 16#include <usb/usb.h> 17 18#include <usb_xfer.h> 19#include <usb_device.h> 20#include <usb_controller.h> 21#include <usb_hub.h> 22 23#include <usb_memory.h> 24 25#include "usb_ohci.h" 26#include "usb_ohci_root_hub.h" 27#include "usb_ohci_bus.h" 28 29 30#include "usb_ohci_xfer.h" 31#include "usb_ohci_pipe.h" 32#include "usb_ohci_queue.h" 33 34 35 36/* 37 * ------------------------------------------------------------------------ 38 * OHCI Bus Functions 39 * ------------------------------------------------------------------------ 40 */ 41 42/* 43 * \brief this function polls the interrupt queue and checks for each element 44 * if the transfer has been completed. If so the transfer is 45 * removed from the list 46 * 47 * \param hc pointer to the host controller 48 */ 49void usb_ohci_do_poll(struct usb_host_controller *hc) 50{ 51 struct usb_xfer *xfer; 52 53 uint8_t repeat = 1; 54 55 while (repeat) { 56 repeat = 0; 57 58 for ((xfer) = (((&hc->intr_queue.head))->first); (xfer); (xfer) = 59 (((xfer))->wait_entry.next)) { 60 /* 61 * check if transfer is transferred 62 */ 63 if (usb_ohci_xfer_is_finished(xfer)) { 64 /* queue has been modified */ 65 repeat = 1; 66 } 67 } 68 } 69} 70 71/* 72 * \brief this function initializes the endpoint with the correct 73 * pipe functions 74 * 75 * \param device the device the endpoint belongs to 76 * \param ep_desc the description of the endpoint 77 * \param ep the endpoint 78 */ 79static void usb_ohci_ep_init(struct usb_device *device, 80 struct usb_endpoint_descriptor *ep_desc, struct usb_endpoint *ep) 81{ 82 if (device->flags.usb_mode != USB_MODE_HOST) { 83 /* this usb device mode is not supported */ 84 return; 85 } 86 87 usb_ohci_hc_t *hc = (usb_ohci_hc_t *) device->controller->hc_control; 88 89 /* 90 * we can only initialize endpoints for function devices 91 */ 92 if (device->device_index != hc->root_hub_address) { 93 switch (ep_desc->bmAttributes.xfer_type) { 94 case USB_ENDPOINT_TYPE_CONTROL: 95 ep->pipe_fn = usb_ohci_get_ctrl_pipe_fn(); 96 break; 97 case USB_ENDPOINT_TYPE_INTR: 98 ep->pipe_fn = usb_ohci_get_intr_pipe_fn(); 99 break; 100 case USB_ENDPOINT_TYPE_ISOCHR: 101 if (device->speed == USB_SPEED_FULL) { 102 ep->pipe_fn = usb_ohci_get_isoc_pipe_fn(); 103 } 104 break; 105 case USB_ENDPOINT_TYPE_BULK: 106 ep->pipe_fn = usb_ohci_get_bulk_pipe_fn(); 107 break; 108 default: 109 /* transfer type unkown, do nothing */ 110 break; 111 } 112 } 113 114} 115 116/** 117 * \brief this function resumes an USB device, this function takes 118 * inserts the USB transfers to their respective transfer lists 119 * 120 * \param device the device to suspend 121 */ 122static void usb_ohci_device_resume(struct usb_device *device) 123{ 124 struct usb_xfer *xfer; 125 usb_ohci_hc_t *hc; 126 usb_ohci_ed_t *ed; 127 128 hc = (usb_ohci_hc_t *) (device->controller->hc_control); 129 130 for ((xfer) = (((&device->controller->intr_queue.head))->first); (xfer); 131 (xfer) = (((xfer))->wait_entry.next)) { 132 ed = xfer->hcd_qh_start[xfer->flags_internal.curr_dma_set]; 133 switch (xfer->type) { 134 case USB_TYPE_BULK: 135 usb_ohci_append_qh(ed, hc->qh_bulk_last); 136 ohci_cmdstatus_blf_wrf(hc->ohci_base, 0x1); 137 break; 138 case USB_TYPE_CTRL: 139 usb_ohci_append_qh(ed, hc->qh_ctrl_last); 140 ohci_cmdstatus_clf_wrf(hc->ohci_base, 0x1); 141 break; 142 143 case USB_TYPE_INTR: 144 usb_ohci_append_qh(ed, hc->qh_intr_last[xfer->intr_qh_pos]); 145 break; 146 default: 147 /* noop */ 148 break; 149 } 150 } 151 152} 153 154/** 155 * \brief this function suspends an USB device. the outstanding transfers 156 * for this device are descheduled and inserted into the wait list 157 * 158 * \param device the device to resume 159 */ 160static void usb_ohci_device_suspend(struct usb_device *device) 161{ 162 struct usb_xfer *xfer; 163 usb_ohci_hc_t *hc; 164 usb_ohci_ed_t *ed; 165 166 hc = (usb_ohci_hc_t *) (device->controller->hc_control); 167 168 for ((xfer) = (((&device->controller->intr_queue.head))->first); (xfer); 169 (xfer) = (((xfer))->wait_entry.next)) { 170 /* 171 * only remove those transfers that belong to the given device 172 */ 173 if (xfer->device == device) { 174 ed = xfer->hcd_qh_start[xfer->flags_internal.curr_dma_set]; 175 switch (xfer->type) { 176 case USB_TYPE_BULK: 177 usb_ohci_remove_qh(ed, hc->qh_bulk_last); 178 break; 179 case USB_TYPE_CTRL: 180 usb_ohci_remove_qh(ed, hc->qh_ctrl_last); 181 break; 182 183 case USB_TYPE_INTR: 184 usb_ohci_remove_qh(ed, hc->qh_intr_last[xfer->intr_qh_pos]); 185 break; 186 default: 187 /* noop */ 188 break; 189 } 190 } 191 192 } 193} 194 195static void usb_ohci_set_hw_power(struct usb_host_controller *controller) 196{ 197 /* 198 * TODO: implement 199 */ 200 assert(!"NYI: Power control not implemented"); 201} 202 203static void usb_ohci_set_hw_power_sleep(struct usb_host_controller *controller, uint32_t state) 204{ 205 /* 206 * TODO: implement 207 */ 208 assert(!"NYI: Power control not implemented"); 209} 210 211 212 213static struct usb_hcdi_bus_fn usb_ohci_bus_fn = { 214 .roothub_exec = usb_ohci_roothub_exec, 215 .endpoint_init = usb_ohci_ep_init, 216 .xfer_setup = usb_ohci_xfer_setup, 217 .xfer_unsetup = usb_ohci_xfer_unsetup, 218 .device_resume = usb_ohci_device_resume, 219 .device_suspend = usb_ohci_device_suspend, 220 .set_hw_power = usb_ohci_set_hw_power, 221 .set_hw_power_sleep = usb_ohci_set_hw_power_sleep, 222 .xfer_poll = usb_ohci_do_poll 223}; 224 225struct usb_hcdi_bus_fn *usb_ohci_get_bus_fn(void) 226{ 227 return &usb_ohci_bus_fn; 228} 229 230