source: mainline/uspace/drv/uhci/root_hub/port.c@ 4046c1ea

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

Merge parent branch

  • Property mode set to 100644
File size: 4.8 KB
Line 
1
2#include <errno.h>
3#include <str_error.h>
4//#include <usb/devreq.h> /* for usb_device_request_setup_packet_t */
5#include <usb/usb.h>
6#include <usb/usbdrv.h>
7
8#include "debug.h"
9#include "uhci.h"
10#include "port.h"
11#include "port_status.h"
12
13static int uhci_port_new_device(uhci_port_t *port);
14static int uhci_port_remove_device(uhci_port_t *port);
15static int uhci_port_set_enabled(uhci_port_t *port, bool enabled);
16
17/*----------------------------------------------------------------------------*/
18int uhci_port_check(void *port)
19{
20 uhci_port_t *port_instance = port;
21 assert(port_instance);
22 port_instance->hc_phone = devman_device_connect(port_instance->hc->handle, 0);
23
24 while (1) {
25 /* Read port status. */
26 port_status_t port_status =
27 port_status_read(port_instance->address);
28
29 uhci_print_info("Port %d: %04X (@ 0x%x) = " \
30 "%s,%s,%s,%s,[%s,%s],%s,%s,%s,%s\n",
31 port_instance->number, port_status, port_instance->address,
32 UHCI_GET_STR_FLAG(port_status, STATUS_SUSPEND, "suspend", "up"),
33 UHCI_GET_STR_FLAG(port_status, STATUS_IN_RESET, "in reset", "-"),
34 UHCI_GET_STR_FLAG(port_status, STATUS_LOW_SPEED, "lowsp", "fullsp"),
35 UHCI_GET_STR_FLAG(port_status, STATUS_RESUME, "resume", "k-state"),
36 UHCI_GET_STR_FLAG(port_status, STATUS_LINE_D_MINUS, "D- on", "D- off"),
37 UHCI_GET_STR_FLAG(port_status, STATUS_LINE_D_PLUS, "D+ on", "D+ off"),
38 UHCI_GET_STR_FLAG(port_status, STATUS_ENABLED_CHANGED, "enblchg", "-"),
39 UHCI_GET_STR_FLAG(port_status, STATUS_ENABLED, "enabled", "disabled"),
40 UHCI_GET_STR_FLAG(port_status, STATUS_CONNECTED_CHANGED, "connchg", "-"),
41 UHCI_GET_STR_FLAG(port_status, STATUS_CONNECTED, "hasdev", "nodev"));
42
43 if (port_status & STATUS_CONNECTED_CHANGED) {
44 if (port_status & STATUS_CONNECTED) {
45 /* new device */
46 uhci_port_new_device(port_instance);
47 } else {
48 uhci_port_remove_device(port_instance);
49 }
50 }
51 async_usleep(port_instance->wait_period_usec);
52 }
53 return EOK;
54}
55/*----------------------------------------------------------------------------*/
56static int uhci_port_new_device(uhci_port_t *port)
57{
58 assert(port);
59 assert(port->hc);
60
61 uhci_print_info("Adding new device on port %d.\n", port->number);
62
63 uhci_t *uhci_instance = (uhci_t*)(port->hc->driver_data);
64
65 /* get default address */
66 usb_address_keeping_reserve_default(&uhci_instance->address_manager);
67
68 const usb_address_t usb_address =
69 usb_address_keeping_request(&uhci_instance->address_manager);
70
71 if (usb_address <= 0) {
72 return usb_address;
73 }
74 /*
75 * the host then waits for at least 100 ms to allow completion of
76 * an insertion process and for power at the device to become stable.
77 */
78 async_usleep(100000);
79
80 /* enable port */
81 uhci_port_set_enabled(port, true);
82
83 /* The hub maintains the reset signal to that port for 10 ms
84 * (See Section 11.5.1.5)
85 */
86 port_status_t port_status =
87 port_status_read(port->address);
88 port_status |= STATUS_IN_RESET;
89 port_status_write(port->address, port_status);
90 async_usleep(10000);
91 port_status =
92 port_status_read(port->address);
93 port_status &= ~STATUS_IN_RESET;
94 port_status_write(port->address, port_status);
95
96 /* assign address to device */
97 int ret = usb_drv_req_set_address(port->hc_phone, 0, usb_address);
98
99
100 if (ret != EOK) { /* address assigning went wrong */
101 uhci_print_error("Failed to assign address (port %d): %s.\n",
102 port->number, str_error(ret));
103 uhci_port_set_enabled(port, false);
104 usb_address_keeping_release_default(&uhci_instance->address_manager);
105 return ENOMEM;
106 }
107
108 /* release default address */
109 usb_address_keeping_release_default(&uhci_instance->address_manager);
110
111 /* communicate and possibly report to devman */
112 assert(port->attached_device == 0);
113
114 ret = usb_drv_register_child_in_devman(port->hc_phone, port->hc, usb_address,
115 &port->attached_device);
116
117 if (ret != EOK) { /* something went wrong */
118 uhci_print_error("Failed(%d) in usb_drv_register_child.\n", ret);
119 uhci_port_set_enabled(port, false);
120 return ENOMEM;
121 }
122
123 return EOK;
124}
125/*----------------------------------------------------------------------------*/
126static int uhci_port_remove_device(uhci_port_t *port)
127{
128 uhci_print_error("Don't know how to remove device %#x.\n",
129 port->attached_device);
130 uhci_port_set_enabled(port, false);
131 return EOK;
132}
133/*----------------------------------------------------------------------------*/
134static int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
135{
136 assert(port);
137
138 /* read register value */
139 port_status_t port_status
140 = port_status_read(port->address);
141
142 /* enable port: register write */
143 if (enabled) {
144 port_status |= STATUS_ENABLED;
145 } else {
146 port_status &= ~STATUS_ENABLED;
147 }
148 port_status_write(port->address, port_status);
149
150 uhci_print_info("%s port %d.\n",
151 enabled ? "Enabled" : "Disabled", port->number);
152 return EOK;
153}
154/*----------------------------------------------------------------------------*/
Note: See TracBrowser for help on using the repository browser.