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

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

All debug output uses port.id_string

  • Property mode set to 100644
File size: 8.5 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#include <fibril_synch.h>
37
38#include <usb/usb.h> /* usb_address_t */
39#include <usb/usbdevice.h>
40#include <usb/hub.h>
41#include <usb/request.h>
42#include <usb/debug.h>
43#include <usb/recognise.h>
44
45#include "port.h"
46#include "port_status.h"
47
48static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed);
49static int uhci_port_remove_device(uhci_port_t *port);
50static int uhci_port_set_enabled(uhci_port_t *port, bool enabled);
51static int uhci_port_check(void *port);
52static int uhci_port_reset_enable(int portno, void *arg);
53/*----------------------------------------------------------------------------*/
54/** Initializes UHCI root hub port instance.
55 *
56 * @param[in] port Memory structure to use.
57 * @param[in] addr Address of I/O register.
58 * @param[in] number Port number.
59 * @param[in] usec Polling interval.
60 * @param[in] rh Pointer to ddf instance fo the root hub driver.
61 * @return Error code.
62 *
63 * Starts the polling fibril.
64 */
65int uhci_port_init(uhci_port_t *port,
66 port_status_t *address, unsigned number, unsigned usec, ddf_dev_t *rh)
67{
68 assert(port);
69 asprintf(&port->id_string, "Port (%p - %d)", port, number);
70 if (port->id_string == NULL) {
71 return ENOMEM;
72 }
73
74 port->address = address;
75 port->number = number;
76 port->wait_period_usec = usec;
77 port->attached_device = 0;
78 port->rh = rh;
79
80 int rc = usb_hc_connection_initialize_from_device(
81 &port->hc_connection, rh);
82 if (rc != EOK) {
83 usb_log_error("Failed to initialize connection to HC.");
84 return rc;
85 }
86
87 port->checker = fibril_create(uhci_port_check, port);
88 if (port->checker == 0) {
89 usb_log_error("Port(%p - %d): failed to launch root hub fibril.",
90 port->address, port->number);
91 return ENOMEM;
92 }
93
94 fibril_add_ready(port->checker);
95 usb_log_debug("Port(%p - %d): Added fibril. %x\n",
96 port->address, port->number, port->checker);
97 return EOK;
98}
99/*----------------------------------------------------------------------------*/
100/** Finishes UHCI root hub port instance.
101 *
102 * @param[in] port Memory structure to use.
103 *
104 * Stops the polling fibril.
105 */
106void uhci_port_fini(uhci_port_t *port)
107{
108 /* TODO: Kill fibril here */
109 return;
110}
111/*----------------------------------------------------------------------------*/
112/** Periodically checks port status and reports new devices.
113 *
114 * @param[in] port Memory structure to use.
115 * @return Error code.
116 */
117int uhci_port_check(void *port)
118{
119 uhci_port_t *instance = port;
120 assert(instance);
121
122 while (1) {
123 async_usleep(instance->wait_period_usec);
124
125 /* read register value */
126 port_status_t port_status = uhci_port_read_status(instance);
127
128 print_port_status(instance->id_string, port_status);
129
130 if ((port_status & STATUS_CONNECTED_CHANGED) == 0)
131 continue;
132
133 usb_log_debug("%s: Connected change detected: %x.\n",
134 instance->id_string, port_status);
135
136 int rc =
137 usb_hc_connection_open(&instance->hc_connection);
138 if (rc != EOK) {
139 usb_log_error("%s: Failed to connect to HC.",
140 instance->id_string);
141 continue;
142 }
143
144 /* Remove any old device */
145 if (instance->attached_device) {
146 usb_log_debug2("%s: Removing device.\n",
147 instance->id_string);
148 uhci_port_remove_device(instance);
149 }
150
151 if ((port_status & STATUS_CONNECTED) != 0) {
152 /* New device */
153 const usb_speed_t speed =
154 ((port_status & STATUS_LOW_SPEED) != 0) ?
155 USB_SPEED_LOW : USB_SPEED_FULL;
156 uhci_port_new_device(instance, speed);
157 } else {
158 /* Write one to WC bits, to ack changes */
159 uhci_port_write_status(instance, port_status);
160 usb_log_debug("%s: Change status ACK.\n",
161 instance->id_string);
162 }
163
164 rc = usb_hc_connection_close(&instance->hc_connection);
165 if (rc != EOK) {
166 usb_log_error("%s: Failed to disconnect.",
167 instance->id_string);
168 }
169 }
170 return EOK;
171}
172/*----------------------------------------------------------------------------*/
173/** Callback for enabling port during adding a new device.
174 *
175 * @param portno Port number (unused).
176 * @param arg Pointer to uhci_port_t of port with the new device.
177 * @return Error code.
178 */
179int uhci_port_reset_enable(int portno, void *arg)
180{
181 uhci_port_t *port = (uhci_port_t *) arg;
182
183 usb_log_debug2("%s: new_device_enable_port.\n",
184 port->id_string);
185
186 /*
187 * The host then waits for at least 100 ms to allow completion of
188 * an insertion process and for power at the device to become stable.
189 */
190 async_usleep(100000);
191
192
193 /* The hub maintains the reset signal to that port for 10 ms
194 * (See Section 11.5.1.5)
195 */
196 {
197 usb_log_debug("%s: Reset Signal start.\n",
198 port->id_string);
199 port_status_t port_status = uhci_port_read_status(port);
200 port_status |= STATUS_IN_RESET;
201 uhci_port_write_status(port, port_status);
202 async_usleep(10000);
203 port_status = uhci_port_read_status(port);
204 port_status &= ~STATUS_IN_RESET;
205 uhci_port_write_status(port, port_status);
206 usb_log_debug("%s: Reset Signal stop.\n",
207 port->id_string);
208 }
209
210 /* Enable the port. */
211 uhci_port_set_enabled(port, true);
212 return EOK;
213}
214/*----------------------------------------------------------------------------*/
215/** Initializes and reports connected device.
216 *
217 * @param[in] port Memory structure to use.
218 * @param[in] speed Detected speed.
219 * @return Error code.
220 *
221 * Uses libUSB function to do the actual work.
222 */
223int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed)
224{
225 assert(port);
226 assert(usb_hc_connection_is_opened(&port->hc_connection));
227
228 usb_log_info("%s: Detected new device.\n",
229 port->id_string);
230
231 usb_address_t dev_addr;
232 int rc = usb_hc_new_device_wrapper(port->rh, &port->hc_connection,
233 speed, uhci_port_reset_enable, port->number, port,
234 &dev_addr, &port->attached_device, NULL, NULL, NULL);
235
236 if (rc != EOK) {
237 usb_log_error("%s: Failed(%d) to add device: %s.\n",
238 port->id_string, rc, str_error(rc));
239 uhci_port_set_enabled(port, false);
240 return rc;
241 }
242
243 usb_log_info("%s: New device has address %d (handle %zu).\n",
244 port->id_string, dev_addr, port->attached_device);
245
246 return EOK;
247}
248/*----------------------------------------------------------------------------*/
249/** Removes device.
250 *
251 * @param[in] port Memory structure to use.
252 * @return Error code.
253 *
254 * Does not work DDF does not support device removal.
255 */
256int uhci_port_remove_device(uhci_port_t *port)
257{
258 usb_log_error("%s: Don't know how to remove device %d.\n",
259 port->id_string, (unsigned int)port->attached_device);
260 return EOK;
261}
262/*----------------------------------------------------------------------------*/
263/** Enables and disables port.
264 *
265 * @param[in] port Memory structure to use.
266 * @return Error code. (Always EOK)
267 */
268int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
269{
270 assert(port);
271
272 /* Read register value */
273 port_status_t port_status = uhci_port_read_status(port);
274
275 /* Set enabled bit */
276 if (enabled) {
277 port_status |= STATUS_ENABLED;
278 } else {
279 port_status &= ~STATUS_ENABLED;
280 }
281
282 /* Write new value. */
283 uhci_port_write_status(port, port_status);
284
285 usb_log_info("%s: %sabled port.\n",
286 port->id_string, enabled ? "En" : "Dis");
287 return EOK;
288}
289/*----------------------------------------------------------------------------*/
290/**
291 * @}
292 */
Note: See TracBrowser for help on using the repository browser.