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

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f673f60 was f673f60, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

UHCI root hub hides IPC phones even more

  • 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(&port->hc_connection);
143
144 if (usb_address <= 0) {
145 usb_log_error("Recieved invalid address(%d).\n", usb_address);
146 return usb_address;
147 }
148 usb_log_debug("Sucessfully obtained address %d for port %d.\n",
149 usb_address, port->number);
150
151 /* get default address */
152 int ret = usb_hc_reserve_default_address(&port->hc_connection);
153 if (ret != EOK) {
154 usb_log_error("Failed to reserve default address on port %d.\n",
155 port->number);
156 int ret2 = usb_hc_unregister_device(&port->hc_connection,
157 usb_address);
158 if (ret2 != EOK) {
159 usb_log_fatal("Failed to return requested address on port %d.\n",
160 port->number);
161 return ret2;
162 }
163 usb_log_debug("Successfully returned reserved address on port %d.\n",
164 port->number);
165 return ret;
166 }
167 usb_log_debug("Sucessfully obtained default address for port %d.\n",
168 port->number);
169
170 /*
171 * the host then waits for at least 100 ms to allow completion of
172 * an insertion process and for power at the device to become stable.
173 */
174 async_usleep(100000);
175
176 /* enable port */
177 uhci_port_set_enabled(port, true);
178
179 /* The hub maintains the reset signal to that port for 10 ms
180 * (See Section 11.5.1.5)
181 */
182 {
183 usb_log_debug("Reset Signal start on port %d.\n",
184 port->number);
185 port_status_t port_status =
186 port_status_read(port->address);
187 port_status |= STATUS_IN_RESET;
188 port_status_write(port->address, port_status);
189 async_usleep(10000);
190 port_status =
191 port_status_read(port->address);
192 port_status &= ~STATUS_IN_RESET;
193 port_status_write(port->address, port_status);
194 usb_log_debug("Reset Signal stop on port %d.\n",
195 port->number);
196 }
197
198 /*
199 * Initialize connection to the device.
200 */
201 /* FIXME: check for errors. */
202 usb_device_connection_t new_dev_connection;
203 usb_endpoint_pipe_t new_dev_ctrl_pipe;
204 usb_device_connection_initialize_on_default_address(
205 &new_dev_connection, &port->hc_connection);
206 usb_endpoint_pipe_initialize_default_control(&new_dev_ctrl_pipe,
207 &new_dev_connection);
208
209 /*
210 * Assign new address to the device. This function updates
211 * the backing connection to still point to the same device.
212 */
213 /* FIXME: check for errors. */
214 usb_endpoint_pipe_start_session(&new_dev_ctrl_pipe);
215 ret = usb_request_set_address(&new_dev_ctrl_pipe, usb_address);
216 usb_endpoint_pipe_end_session(&new_dev_ctrl_pipe);
217
218 if (ret != EOK) { /* address assigning went wrong */
219 usb_log_error("Failed(%d) to assign address to the device.\n", ret);
220 uhci_port_set_enabled(port, false);
221 int release = usb_hc_release_default_address(&port->hc_connection);
222 if (release != EOK) {
223 usb_log_error("Failed to release default address on port %d.\n",
224 port->number);
225 return release;
226 }
227 usb_log_debug("Sucessfully released default address on port %d.\n",
228 port->number);
229 return ret;
230 }
231 usb_log_debug("Sucessfully assigned address %d for port %d.\n",
232 usb_address, port->number);
233
234 /* release default address */
235 ret = usb_hc_release_default_address(&port->hc_connection);
236 if (ret != EOK) {
237 usb_log_error("Failed to release default address on port %d.\n",
238 port->number);
239 return ret;
240 }
241 usb_log_debug("Sucessfully released default address on port %d.\n",
242 port->number);
243
244 /* communicate and possibly report to devman */
245 assert(port->attached_device == 0);
246
247 ret = usb_device_register_child_in_devman(new_dev_connection.address,
248 new_dev_connection.hc_handle, port->rh, &port->attached_device);
249
250 if (ret != EOK) { /* something went wrong */
251 usb_log_error("Failed(%d) in usb_drv_register_child.\n", ret);
252 uhci_port_set_enabled(port, false);
253 return ENOMEM;
254 }
255 usb_log_info("Sucessfully added device on port(%d) address(%d) handle %d.\n",
256 port->number, usb_address, port->attached_device);
257
258 /*
259 * Register the device in the host controller.
260 */
261 usb_hc_attached_device_t new_device = {
262 .address = new_dev_connection.address,
263 .handle = port->attached_device
264 };
265
266 ret = usb_hc_register_device(&port->hc_connection, &new_device);
267 // TODO: proper error check here
268 assert(ret == EOK);
269
270 return EOK;
271}
272/*----------------------------------------------------------------------------*/
273static int uhci_port_remove_device(uhci_port_t *port)
274{
275 usb_log_error("Don't know how to remove device %#x.\n",
276 (unsigned int)port->attached_device);
277// uhci_port_set_enabled(port, false);
278 return EOK;
279}
280/*----------------------------------------------------------------------------*/
281static int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
282{
283 assert(port);
284
285 /* read register value */
286 port_status_t port_status
287 = port_status_read(port->address);
288
289 /* enable port: register write */
290 if (enabled) {
291 port_status |= STATUS_ENABLED;
292 } else {
293 port_status &= ~STATUS_ENABLED;
294 }
295 port_status_write(port->address, port_status);
296
297 usb_log_info("%s port %d.\n",
298 enabled ? "Enabled" : "Disabled", port->number);
299 return EOK;
300}
301/*----------------------------------------------------------------------------*/
302/**
303 * @}
304 */
Note: See TracBrowser for help on using the repository browser.