Changeset e50cd7f in mainline for uspace/drv/usbhub/ports.c
- Timestamp:
- 2011-04-17T19:17:55Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 63517c2, cfbbe1d3
- Parents:
- ef354b6 (diff), 8595577b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/usbhub/ports.c
ref354b6 re50cd7f 33 33 * Hub ports functions. 34 34 */ 35 #include "port_status.h" 36 #include < inttypes.h>35 36 #include <bool.h> 37 37 #include <errno.h> 38 38 #include <str_error.h> 39 #include <usb/request.h> 39 #include <inttypes.h> 40 #include <fibril_synch.h> 41 40 42 #include <usb/debug.h> 43 44 #include "ports.h" 45 #include "usbhub.h" 46 #include "usbhub_private.h" 47 #include "port_status.h" 48 49 50 /** Information for fibril for device discovery. */ 51 struct add_device_phase1 { 52 usb_hub_info_t *hub; 53 size_t port; 54 usb_speed_t speed; 55 }; 56 57 static void usb_hub_removed_device( 58 usb_hub_info_t * hub, uint16_t port); 59 60 static void usb_hub_port_reset_completed(usb_hub_info_t * hub, 61 uint16_t port, uint32_t status); 62 63 static void usb_hub_port_over_current(usb_hub_info_t * hub, 64 uint16_t port, uint32_t status); 65 66 static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port, 67 usb_port_status_t *status); 68 69 static int enable_port_callback(int port_no, void *arg); 70 71 static int add_device_phase1_worker_fibril(void *arg); 72 73 static int create_add_device_fibril(usb_hub_info_t *hub, size_t port, 74 usb_speed_t speed); 75 76 /** 77 * Process interrupts on given hub port 78 * 79 * Accepts connection, over current and port reset change. 80 * @param hub hub representation 81 * @param port port number, starting from 1 82 */ 83 void usb_hub_process_interrupt(usb_hub_info_t * hub, 84 uint16_t port) { 85 usb_log_debug("interrupt at port %d\n", port); 86 //determine type of change 87 //usb_pipe_t *pipe = hub->control_pipe; 88 89 int opResult; 90 91 usb_port_status_t status; 92 opResult = get_port_status(&hub->usb_device->ctrl_pipe, port, &status); 93 if (opResult != EOK) { 94 usb_log_error("Failed to get port %zu status: %s.\n", 95 port, str_error(opResult)); 96 return; 97 } 98 //connection change 99 if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_CONNECTION)) { 100 bool device_connected = usb_port_is_status(status, 101 USB_HUB_FEATURE_PORT_CONNECTION); 102 usb_log_debug("Connection change on port %zu: %s.\n", port, 103 device_connected ? "device attached" : "device removed"); 104 105 if (device_connected) { 106 opResult = create_add_device_fibril(hub, port, 107 usb_port_speed(status)); 108 if (opResult != EOK) { 109 usb_log_error( 110 "Cannot handle change on port %zu: %s.\n", 111 str_error(opResult)); 112 } 113 } else { 114 usb_hub_removed_device(hub, port); 115 } 116 } 117 //over current 118 if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT)) { 119 //check if it was not auto-resolved 120 usb_log_debug("overcurrent change on port\n"); 121 usb_hub_port_over_current(hub, port, status); 122 } 123 //port reset 124 if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_RESET)) { 125 usb_hub_port_reset_completed(hub, port, status); 126 } 127 usb_log_debug("status x%x : %d\n ", status, status); 128 129 usb_port_status_set_bit( 130 &status, USB_HUB_FEATURE_C_PORT_CONNECTION,false); 131 usb_port_status_set_bit( 132 &status, USB_HUB_FEATURE_PORT_RESET,false); 133 usb_port_status_set_bit( 134 &status, USB_HUB_FEATURE_C_PORT_RESET,false); 135 usb_port_status_set_bit( 136 &status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT,false); 137 /// \TODO what about port power change? 138 if (status >> 16) { 139 usb_log_info("there was unsupported change on port %d: %X\n", 140 port, status); 141 142 } 143 } 144 145 146 /** 147 * routine called when a device on port has been removed 148 * 149 * If the device on port had default address, it releases default address. 150 * Otherwise does not do anything, because DDF does not allow to remove device 151 * from it`s device tree. 152 * @param hub hub representation 153 * @param port port number, starting from 1 154 */ 155 static void usb_hub_removed_device( 156 usb_hub_info_t * hub, uint16_t port) { 157 158 int opResult = usb_hub_clear_port_feature(hub->control_pipe, 159 port, USB_HUB_FEATURE_C_PORT_CONNECTION); 160 if (opResult != EOK) { 161 usb_log_warning("could not clear port-change-connection flag\n"); 162 } 163 /** \TODO remove device from device manager - not yet implemented in 164 * devide manager 165 */ 166 167 //close address 168 //if (hub->attached_devs[port].address != 0) { 169 if(hub->ports[port].attached_device.address >= 0){ 170 /*uncomment this code to use it when DDF allows device removal 171 opResult = usb_hc_unregister_device( 172 &hub->connection, 173 hub->attached_devs[port].address); 174 if(opResult != EOK) { 175 dprintf(USB_LOG_LEVEL_WARNING, "could not release " 176 "address of " 177 "removed device: %d", opResult); 178 } 179 hub->attached_devs[port].address = 0; 180 hub->attached_devs[port].handle = 0; 181 */ 182 } else { 183 // TODO: is this really reason to print a warning? 184 usb_log_warning("Device removed before being registered.\n"); 185 186 /* 187 * Device was removed before port reset completed. 188 * We will announce a failed port reset to unblock the 189 * port reset callback from new device wrapper. 190 */ 191 usb_hub_port_t *the_port = hub->ports + port; 192 fibril_mutex_lock(&the_port->reset_mutex); 193 the_port->reset_completed = true; 194 the_port->reset_okay = false; 195 fibril_condvar_broadcast(&the_port->reset_cv); 196 fibril_mutex_unlock(&the_port->reset_mutex); 197 } 198 } 199 200 201 /** 202 * Process port reset change 203 * 204 * After this change port should be enabled, unless some problem occured. 205 * This functions triggers second phase of enabling new device. 206 * @param hub 207 * @param port 208 * @param status 209 */ 210 static void usb_hub_port_reset_completed(usb_hub_info_t * hub, 211 uint16_t port, uint32_t status){ 212 usb_log_debug("Port %zu reset complete.\n", port); 213 if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_ENABLE)) { 214 /* Finalize device adding. */ 215 usb_hub_port_t *the_port = hub->ports + port; 216 fibril_mutex_lock(&the_port->reset_mutex); 217 the_port->reset_completed = true; 218 the_port->reset_okay = true; 219 fibril_condvar_broadcast(&the_port->reset_cv); 220 fibril_mutex_unlock(&the_port->reset_mutex); 221 } else { 222 usb_log_warning( 223 "Port %zu reset complete but port not enabled.\n", 224 port); 225 } 226 } 227 228 /** 229 * Process over current condition on port. 230 * 231 * Turn off the power on the port. 232 * 233 * @param hub hub representation 234 * @param port port number, starting from 1 235 */ 236 static void usb_hub_port_over_current(usb_hub_info_t * hub, 237 uint16_t port, uint32_t status) { 238 int opResult; 239 if(usb_port_is_status(status, USB_HUB_FEATURE_PORT_OVER_CURRENT)){ 240 opResult = usb_hub_clear_port_feature(hub->control_pipe, 241 port, USB_HUB_FEATURE_PORT_POWER); 242 if (opResult != EOK) { 243 usb_log_error("cannot power off port %d; %d\n", 244 port, opResult); 245 } 246 }else{ 247 opResult = usb_hub_set_port_feature(hub->control_pipe, 248 port, USB_HUB_FEATURE_PORT_POWER); 249 if (opResult != EOK) { 250 usb_log_error("cannot power on port %d; %d\n", 251 port, opResult); 252 } 253 } 254 } 41 255 42 256 /** Retrieve port status. … … 73 287 } 74 288 75 /** Information for fibril for device discovery. */76 struct add_device_phase1 {77 usb_hub_info_t *hub;78 size_t port;79 usb_speed_t speed;80 };81 82 289 /** Callback for enabling a specific port. 83 290 * … … 91 298 static int enable_port_callback(int port_no, void *arg) 92 299 { 93 usb_hub_info_t *hub = (usb_hub_info_t *)arg;300 usb_hub_info_t *hub = arg; 94 301 int rc; 95 302 usb_device_request_setup_packet_t request; … … 122 329 } 123 330 124 return EOK; 331 if (my_port->reset_okay) { 332 return EOK; 333 } else { 334 return ESTALL; 335 } 125 336 } 126 337 … … 156 367 data->hub->ports[data->port].attached_device.address = new_address; 157 368 158 usb_log_info("Detected new device on `%s' (port %zu), " \369 usb_log_info("Detected new device on `%s' (port %zu), " 159 370 "address %d (handle %" PRIun ").\n", 160 371 data->hub->usb_device->ddf_dev->name, data->port, … … 166 377 return EOK; 167 378 } 379 168 380 169 381 /** Start device adding when connection change is detected. … … 176 388 * @return Error code. 177 389 */ 178 static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port,390 static int create_add_device_fibril(usb_hub_info_t *hub, size_t port, 179 391 usb_speed_t speed) 180 392 { … … 213 425 } 214 426 215 /** Process change on a single port.216 *217 * @param hub Hub to which the port belongs.218 * @param port Port index (starting at 1).219 */220 static void process_port_change(usb_hub_info_t *hub, size_t port)221 {222 int rc;223 224 usb_port_status_t port_status;225 226 rc = get_port_status(&hub->usb_device->ctrl_pipe, port, &port_status);227 if (rc != EOK) {228 usb_log_error("Failed to get port %zu status: %s.\n",229 port, str_error(rc));230 return;231 }232 233 /*234 * Check exact nature of the change.235 */236 usb_log_debug("Port %zu change status: %x.\n", port,237 (unsigned int) port_status);238 239 if (usb_port_connect_change(&port_status)) {240 bool device_connected = usb_port_dev_connected(&port_status);241 usb_log_debug("Connection change on port %zu: %s.\n", port,242 device_connected ? "device attached" : "device removed");243 244 if (device_connected) {245 rc = add_device_phase1_new_fibril(hub, port,246 usb_port_speed(&port_status));247 if (rc != EOK) {248 usb_log_error(249 "Cannot handle change on port %zu: %s.\n",250 str_error(rc));251 }252 } else {253 usb_hub_removed_device(hub, port);254 }255 }256 257 if (usb_port_overcurrent_change(&port_status)) {258 if (usb_port_over_current(&port_status)) {259 usb_log_warning("Overcurrent on port %zu.\n", port);260 usb_hub_over_current(hub, port);261 } else {262 usb_log_debug("Overcurrent on port %zu autoresolved.\n",263 port);264 }265 }266 267 if (usb_port_reset_completed(&port_status)) {268 usb_log_debug("Port %zu reset complete.\n", port);269 if (usb_port_enabled(&port_status)) {270 /* Finalize device adding. */271 usb_hub_port_t *the_port = hub->ports + port;272 fibril_mutex_lock(&the_port->reset_mutex);273 the_port->reset_completed = true;274 fibril_condvar_broadcast(&the_port->reset_cv);275 fibril_mutex_unlock(&the_port->reset_mutex);276 } else {277 usb_log_warning(278 "Port %zu reset complete but port not enabled.\n",279 port);280 }281 }282 283 usb_port_set_connect_change(&port_status, false);284 usb_port_set_reset(&port_status, false);285 usb_port_set_reset_completed(&port_status, false);286 usb_port_set_dev_connected(&port_status, false);287 if (port_status >> 16) {288 usb_log_warning("Unsupported change on port %zu: %x.\n",289 port, (unsigned int) port_status);290 }291 }292 293 294 /** Callback for polling hub for port changes.295 *296 * @param dev Device where the change occured.297 * @param change_bitmap Bitmap of changed ports.298 * @param change_bitmap_size Size of the bitmap in bytes.299 * @param arg Custom argument, points to @c usb_hub_info_t.300 * @return Whether to continue polling.301 */302 bool hub_port_changes_callback(usb_device_t *dev,303 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg)304 {305 usb_hub_info_t *hub = (usb_hub_info_t *) arg;306 307 /* FIXME: check that we received enough bytes. */308 if (change_bitmap_size == 0) {309 goto leave;310 }311 312 size_t port;313 for (port = 1; port < hub->port_count + 1; port++) {314 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;315 if (change) {316 process_port_change(hub, port);317 }318 }319 320 321 leave:322 /* FIXME: proper interval. */323 async_usleep(1000 * 1000 * 10 );324 325 return true;326 }327 328 329 427 /** 330 428 * @}
Note:
See TracChangeset
for help on using the changeset viewer.