source: mainline/uspace/drv/ohci/hc.c@ 6bec59b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6bec59b was 6bec59b, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

Port endpoint framework usage from UHCI

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/** @addtogroup drvusbohcihc
29 * @{
30 */
31/** @file
32 * @brief OHCI Host controller driver routines
33 */
34#include <errno.h>
35#include <str_error.h>
36#include <adt/list.h>
37#include <libarch/ddi.h>
38
39#include <usb/debug.h>
40#include <usb/usb.h>
41#include <usb/ddfiface.h>
42#include <usb/usbdevice.h>
43
44#include "hc.h"
45
46static int interrupt_emulator(hc_t *instance);
47static void hc_gain_control(hc_t *instance);
48static void hc_init_hw(hc_t *instance);
49/*----------------------------------------------------------------------------*/
50int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
51{
52 assert(instance);
53 assert(hub_fun);
54
55 usb_address_t hub_address =
56 device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
57 instance->rh.address = hub_address;
58 usb_device_keeper_bind(
59 &instance->manager, hub_address, hub_fun->handle);
60
61 endpoint_t *ep = malloc(sizeof(endpoint_t));
62 assert(ep);
63 int ret = endpoint_init(ep, hub_address, 0, USB_DIRECTION_BOTH,
64 USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64);
65 assert(ret == EOK);
66 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, 0);
67 assert(ret == EOK);
68
69 char *match_str = NULL;
70 ret = asprintf(&match_str, "usb&class=hub");
71// ret = (match_str == NULL) ? ret : EOK;
72 if (ret < 0) {
73 usb_log_error(
74 "Failed(%d) to create root hub match-id string.\n", ret);
75 return ret;
76 }
77
78 ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
79 if (ret != EOK) {
80 usb_log_error("Failed add create root hub match-id.\n");
81 }
82 return ret;
83}
84/*----------------------------------------------------------------------------*/
85int hc_init(hc_t *instance, ddf_fun_t *fun, ddf_dev_t *dev,
86 uintptr_t regs, size_t reg_size, bool interrupts)
87{
88 assert(instance);
89 int ret = EOK;
90#define CHECK_RET_RETURN(ret, message...) \
91if (ret != EOK) { \
92 usb_log_error(message); \
93 return ret; \
94} else (void)0
95
96 ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
97 CHECK_RET_RETURN(ret,
98 "Failed(%d) to gain access to device registers: %s.\n",
99 ret, str_error(ret));
100
101 instance->ddf_instance = fun;
102 usb_device_keeper_init(&instance->manager);
103 ret = usb_endpoint_manager_init(&instance->ep_manager,
104 BANDWIDTH_AVAILABLE_USB11);
105 CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
106 ret, str_error(ret));
107
108 if (!interrupts) {
109 instance->interrupt_emulator =
110 fibril_create((int(*)(void*))interrupt_emulator, instance);
111 fibril_add_ready(instance->interrupt_emulator);
112 }
113
114 hc_gain_control(instance);
115
116 rh_init(&instance->rh, dev, instance->registers);
117
118 hc_init_hw(instance);
119
120 /* TODO: implement */
121 return EOK;
122}
123/*----------------------------------------------------------------------------*/
124int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
125{
126 assert(instance);
127 assert(batch);
128 if (batch->target.address == instance->rh.address) {
129 return rh_request(&instance->rh, batch);
130 }
131 /* TODO: implement */
132 return ENOTSUP;
133}
134/*----------------------------------------------------------------------------*/
135void hc_interrupt(hc_t *instance, uint32_t status)
136{
137 assert(instance);
138 if (status == 0)
139 return;
140 if (status & IS_RHSC)
141 rh_interrupt(&instance->rh);
142
143 usb_log_info("OHCI interrupt: %x.\n", status);
144
145 /* TODO: Check for further interrupt causes */
146 /* TODO: implement */
147}
148/*----------------------------------------------------------------------------*/
149int interrupt_emulator(hc_t *instance)
150{
151 assert(instance);
152 usb_log_info("Started interrupt emulator.\n");
153 while (1) {
154 const uint32_t status = instance->registers->interrupt_status;
155 instance->registers->interrupt_status = status;
156 hc_interrupt(instance, status);
157 async_usleep(1000);
158 }
159 return EOK;
160}
161/*----------------------------------------------------------------------------*/
162void hc_gain_control(hc_t *instance)
163{
164 assert(instance);
165 /* Interrupt routing enabled => smm driver is active */
166 if (instance->registers->control & C_IR) {
167 usb_log_info("Found SMM driver requesting ownership change.\n");
168 instance->registers->command_status |= CS_OCR;
169 while (instance->registers->control & C_IR) {
170 async_usleep(1000);
171 }
172 usb_log_info("Ownership taken from SMM driver.\n");
173 return;
174 }
175
176 const unsigned hc_status =
177 (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
178 /* Interrupt routing disabled && status != USB_RESET => BIOS active */
179 if (hc_status != C_HCFS_RESET) {
180 usb_log_info("Found BIOS driver.\n");
181 if (hc_status == C_HCFS_OPERATIONAL) {
182 usb_log_info("HC operational(BIOS).\n");
183 return;
184 }
185 /* HC is suspended assert resume for 20ms */
186 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
187 async_usleep(20000);
188 return;
189 }
190
191 /* HC is in reset (hw startup) => no other driver
192 * maintain reset for at least the time specified in USB spec (50 ms)*/
193 async_usleep(50000);
194
195 /* turn off legacy emulation */
196 volatile uint32_t *ohci_emulation_reg =
197 (uint32_t*)((char*)instance->registers + 0x100);
198 usb_log_info("OHCI legacy register status %p: %x.\n",
199 ohci_emulation_reg, *ohci_emulation_reg);
200 *ohci_emulation_reg = 0;
201
202}
203/*----------------------------------------------------------------------------*/
204void hc_init_hw(hc_t *instance)
205{
206 assert(instance);
207 const uint32_t fm_interval = instance->registers->fm_interval;
208 instance->registers->command_status = CS_HCR;
209 async_usleep(10);
210 instance->registers->fm_interval = fm_interval;
211 assert((instance->registers->command_status & CS_HCR) == 0);
212 /* hc is now in suspend state */
213 /* TODO: init HCCA block */
214 /* TODO: init queues */
215 /* TODO: enable queues */
216 /* TODO: enable interrupts */
217 /* TODO: set periodic start to 90% */
218
219 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
220 usb_log_info("OHCI HC up and running.\n");
221}
222/**
223 * @}
224 */
Note: See TracBrowser for help on using the repository browser.