source: mainline/uspace/drv/uhci-rhd/port.c@ 50ba203

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 50ba203 was 6427cf67, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Hack for setting low speed/high speed

Currently, it is only a boolean. Will improve later.

  • Property mode set to 100644
File size: 9.2 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 usb
29 * @{
30 */
31/** @file
32 * @brief UHCI driver
33 */
34#include <errno.h>
35#include <str_error.h>
36
37#include <usb/usb.h> /* usb_address_t */
38#include <usb/usbdevice.h>
39#include <usb/hub.h>
40#include <usb/request.h>
41#include <usb/debug.h>
42#include <usb/recognise.h>
43
44#include "port.h"
45#include "port_status.h"
46
47static int uhci_port_new_device(uhci_port_t *port);
48static int uhci_port_remove_device(uhci_port_t *port);
49static int uhci_port_set_enabled(uhci_port_t *port, bool enabled);
50static int uhci_port_check(void *port);
51
52int uhci_port_init(
53 uhci_port_t *port, port_status_t *address, unsigned number,
54 unsigned usec, device_t *rh, int parent_phone)
55{
56 assert(port);
57 port->address = address;
58 port->number = number;
59 port->wait_period_usec = usec;
60 port->attached_device = 0;
61 port->rh = rh;
62 int rc = usb_hc_connection_initialize_from_device(
63 &port->hc_connection, rh);
64 if (rc != EOK) {
65 usb_log_error("Failed to initialize connection to HC.");
66 return rc;
67 }
68
69 port->checker = fibril_create(uhci_port_check, port);
70 if (port->checker == 0) {
71 usb_log_error(": failed to launch root hub fibril.");
72 return ENOMEM;
73 }
74 fibril_add_ready(port->checker);
75 usb_log_debug(
76 "Added fibril for port %d: %p.\n", number, port->checker);
77 return EOK;
78}
79/*----------------------------------------------------------------------------*/
80void uhci_port_fini(uhci_port_t *port)
81{
82// TODO: destroy fibril
83// TODO: hangup phone
84// fibril_teardown(port->checker);
85 return;
86}
87/*----------------------------------------------------------------------------*/
88int uhci_port_check(void *port)
89{
90 uhci_port_t *port_instance = port;
91 assert(port_instance);
92
93 while (1) {
94 usb_log_debug("Port(%d) status address %p:\n",
95 port_instance->number, port_instance->address);
96
97 /* read register value */
98 port_status_t port_status =
99 port_status_read(port_instance->address);
100
101 /* debug print */
102 usb_log_info("Port(%d) status %#.4x\n",
103 port_instance->number, port_status);
104 print_port_status(port_status);
105
106 if (port_status & STATUS_CONNECTED_CHANGED) {
107 int rc = usb_hc_connection_open(
108 &port_instance->hc_connection);
109 if (rc != EOK) {
110 usb_log_error("Failed to connect to HC.");
111 goto next;
112 }
113
114 if (port_status & STATUS_CONNECTED) {
115 /* new device */
116 uhci_port_new_device(port_instance);
117 } else {
118 uhci_port_remove_device(port_instance);
119 }
120
121 rc = usb_hc_connection_close(
122 &port_instance->hc_connection);
123 if (rc != EOK) {
124 usb_log_error("Failed to disconnect from HC.");
125 goto next;
126 }
127 }
128 next:
129 async_usleep(port_instance->wait_period_usec);
130 }
131 return EOK;
132}
133/*----------------------------------------------------------------------------*/
134static int uhci_port_new_device(uhci_port_t *port)
135{
136 assert(port);
137 assert(usb_hc_connection_is_opened(&port->hc_connection));
138
139 usb_log_info("Adding new device on port %d.\n", port->number);
140
141 /* get address of the future device */
142 const usb_address_t usb_address = usb_hc_request_address(
143 &port->hc_connection, true);
144
145 if (usb_address <= 0) {
146 usb_log_error("Recieved invalid address(%d).\n", usb_address);
147 return usb_address;
148 }
149 usb_log_debug("Sucessfully obtained address %d for port %d.\n",
150 usb_address, port->number);
151
152 /* get default address */
153 int ret = usb_hc_reserve_default_address(&port->hc_connection, true);
154 if (ret != EOK) {
155 usb_log_error("Failed to reserve default address on port %d.\n",
156 port->number);
157 int ret2 = usb_hc_unregister_device(&port->hc_connection,
158 usb_address);
159 if (ret2 != EOK) {
160 usb_log_fatal("Failed to return requested address on port %d.\n",
161 port->number);
162 return ret2;
163 }
164 usb_log_debug("Successfully returned reserved address on port %d.\n",
165 port->number);
166 return ret;
167 }
168 usb_log_debug("Sucessfully obtained default address for port %d.\n",
169 port->number);
170
171 /*
172 * the host then waits for at least 100 ms to allow completion of
173 * an insertion process and for power at the device to become stable.
174 */
175 async_usleep(100000);
176
177 /* enable port */
178 uhci_port_set_enabled(port, true);
179
180 /* The hub maintains the reset signal to that port for 10 ms
181 * (See Section 11.5.1.5)
182 */
183 {
184 usb_log_debug("Reset Signal start on port %d.\n",
185 port->number);
186 port_status_t port_status =
187 port_status_read(port->address);
188 port_status |= STATUS_IN_RESET;
189 port_status_write(port->address, port_status);
190 async_usleep(10000);
191 port_status =
192 port_status_read(port->address);
193 port_status &= ~STATUS_IN_RESET;
194 port_status_write(port->address, port_status);
195 usb_log_debug("Reset Signal stop on port %d.\n",
196 port->number);
197 }
198
199 /*
200 * Initialize connection to the device.
201 */
202 /* FIXME: check for errors. */
203 usb_device_connection_t new_dev_connection;
204 usb_endpoint_pipe_t new_dev_ctrl_pipe;
205 usb_device_connection_initialize_on_default_address(
206 &new_dev_connection, &port->hc_connection);
207 usb_endpoint_pipe_initialize_default_control(&new_dev_ctrl_pipe,
208 &new_dev_connection);
209
210 /*
211 * Assign new address to the device. This function updates
212 * the backing connection to still point to the same device.
213 */
214 /* FIXME: check for errors. */
215 usb_endpoint_pipe_start_session(&new_dev_ctrl_pipe);
216 ret = usb_request_set_address(&new_dev_ctrl_pipe, usb_address);
217 usb_endpoint_pipe_end_session(&new_dev_ctrl_pipe);
218
219 if (ret != EOK) { /* address assigning went wrong */
220 usb_log_error("Failed(%d) to assign address to the device.\n", ret);
221 uhci_port_set_enabled(port, false);
222 int release = usb_hc_release_default_address(&port->hc_connection);
223 if (release != EOK) {
224 usb_log_error("Failed to release default address on port %d.\n",
225 port->number);
226 return release;
227 }
228 usb_log_debug("Sucessfully released default address on port %d.\n",
229 port->number);
230 return ret;
231 }
232 usb_log_debug("Sucessfully assigned address %d for port %d.\n",
233 usb_address, port->number);
234
235 /* release default address */
236 ret = usb_hc_release_default_address(&port->hc_connection);
237 if (ret != EOK) {
238 usb_log_error("Failed to release default address on port %d.\n",
239 port->number);
240 return ret;
241 }
242 usb_log_debug("Sucessfully released default address on port %d.\n",
243 port->number);
244
245 /* communicate and possibly report to devman */
246 assert(port->attached_device == 0);
247
248 ret = usb_device_register_child_in_devman(new_dev_connection.address,
249 new_dev_connection.hc_handle, port->rh, &port->attached_device);
250
251 if (ret != EOK) { /* something went wrong */
252 usb_log_error("Failed(%d) in usb_drv_register_child.\n", ret);
253 uhci_port_set_enabled(port, false);
254 return ENOMEM;
255 }
256 usb_log_info("Sucessfully added device on port(%d) address(%d) handle %d.\n",
257 port->number, usb_address, port->attached_device);
258
259 /*
260 * Register the device in the host controller.
261 */
262 usb_hc_attached_device_t new_device = {
263 .address = new_dev_connection.address,
264 .handle = port->attached_device
265 };
266
267 ret = usb_hc_register_device(&port->hc_connection, &new_device);
268 // TODO: proper error check here
269 assert(ret == EOK);
270
271 return EOK;
272}
273/*----------------------------------------------------------------------------*/
274static int uhci_port_remove_device(uhci_port_t *port)
275{
276 usb_log_error("Don't know how to remove device %#x.\n",
277 (unsigned int)port->attached_device);
278// uhci_port_set_enabled(port, false);
279 return EOK;
280}
281/*----------------------------------------------------------------------------*/
282static int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
283{
284 assert(port);
285
286 /* read register value */
287 port_status_t port_status
288 = port_status_read(port->address);
289
290 /* enable port: register write */
291 if (enabled) {
292 port_status |= STATUS_ENABLED;
293 } else {
294 port_status &= ~STATUS_ENABLED;
295 }
296 port_status_write(port->address, port_status);
297
298 usb_log_info("%s port %d.\n",
299 enabled ? "Enabled" : "Disabled", port->number);
300 return EOK;
301}
302/*----------------------------------------------------------------------------*/
303/**
304 * @}
305 */
Note: See TracBrowser for help on using the repository browser.