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

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

Move port_status.h functionality to port.h

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