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

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

Doxygen and other comments uhci-rhd refactoring.

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