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