Changes in uspace/drv/usbhub/ports.c [2ad98fd:69df9373] in mainline
- File:
-
- 1 edited
-
uspace/drv/usbhub/ports.c (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/usbhub/ports.c
r2ad98fd r69df9373 33 33 * Hub ports functions. 34 34 */ 35 36 #include < bool.h>35 #include "port_status.h" 36 #include <inttypes.h> 37 37 #include <errno.h> 38 38 #include <str_error.h> 39 #include <inttypes.h> 40 #include <fibril_synch.h> 41 39 #include <usb/request.h> 42 40 #include <usb/debug.h> 43 41 44 #include "ports.h" 45 #include "usbhub.h" 46 #include "usbhub_private.h" 47 #include "port_status.h" 48 42 /** Retrieve port status. 43 * 44 * @param[in] ctrl_pipe Control pipe to use. 45 * @param[in] port Port number (starting at 1). 46 * @param[out] status Where to store the port status. 47 * @return Error code. 48 */ 49 static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port, 50 usb_port_status_t *status) 51 { 52 size_t recv_size; 53 usb_device_request_setup_packet_t request; 54 usb_port_status_t status_tmp; 55 56 usb_hub_set_port_status_request(&request, port); 57 int rc = usb_pipe_control_read(ctrl_pipe, 58 &request, sizeof(usb_device_request_setup_packet_t), 59 &status_tmp, sizeof(status_tmp), &recv_size); 60 if (rc != EOK) { 61 return rc; 62 } 63 64 if (recv_size != sizeof (status_tmp)) { 65 return ELIMIT; 66 } 67 68 if (status != NULL) { 69 *status = status_tmp; 70 } 71 72 return EOK; 73 } 49 74 50 75 /** Information for fibril for device discovery. */ … … 55 80 }; 56 81 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 port78 *79 * Accepts connection, over current and port reset change.80 * @param hub hub representation81 * @param port port number, starting from 182 */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 change87 //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 change99 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 current118 if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT)) {119 //check if it was not auto-resolved120 usb_log_debug("overcurrent change on port\n");121 usb_hub_port_over_current(hub, port, status);122 }123 //port reset124 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 removed148 *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 device151 * from it`s device tree.152 * @param hub hub representation153 * @param port port number, starting from 1154 */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 in164 * devide manager165 */166 167 //close address168 //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 removal171 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 usb_log_warning("this is strange, disconnected device had "184 "no address\n");185 //device was disconnected before it`s port was reset -186 //return default address187 usb_hub_release_default_address(hub);188 }189 }190 191 192 /**193 * Process port reset change194 *195 * After this change port should be enabled, unless some problem occured.196 * This functions triggers second phase of enabling new device.197 * @param hub198 * @param port199 * @param status200 */201 static void usb_hub_port_reset_completed(usb_hub_info_t * hub,202 uint16_t port, uint32_t status){203 usb_log_debug("Port %zu reset complete.\n", port);204 if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_ENABLE)) {205 /* Finalize device adding. */206 usb_hub_port_t *the_port = hub->ports + port;207 fibril_mutex_lock(&the_port->reset_mutex);208 the_port->reset_completed = true;209 fibril_condvar_broadcast(&the_port->reset_cv);210 fibril_mutex_unlock(&the_port->reset_mutex);211 } else {212 usb_log_warning(213 "Port %zu reset complete but port not enabled.\n",214 port);215 }216 }217 218 /**219 * Process over current condition on port.220 *221 * Turn off the power on the port.222 *223 * @param hub hub representation224 * @param port port number, starting from 1225 */226 static void usb_hub_port_over_current(usb_hub_info_t * hub,227 uint16_t port, uint32_t status) {228 int opResult;229 if(usb_port_is_status(status, USB_HUB_FEATURE_PORT_OVER_CURRENT)){230 opResult = usb_hub_clear_port_feature(hub->control_pipe,231 port, USB_HUB_FEATURE_PORT_POWER);232 if (opResult != EOK) {233 usb_log_error("cannot power off port %d; %d\n",234 port, opResult);235 }236 }else{237 opResult = usb_hub_set_port_feature(hub->control_pipe,238 port, USB_HUB_FEATURE_PORT_POWER);239 if (opResult != EOK) {240 usb_log_error("cannot power on port %d; %d\n",241 port, opResult);242 }243 }244 }245 246 /** Retrieve port status.247 *248 * @param[in] ctrl_pipe Control pipe to use.249 * @param[in] port Port number (starting at 1).250 * @param[out] status Where to store the port status.251 * @return Error code.252 */253 static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,254 usb_port_status_t *status)255 {256 size_t recv_size;257 usb_device_request_setup_packet_t request;258 usb_port_status_t status_tmp;259 260 usb_hub_set_port_status_request(&request, port);261 int rc = usb_pipe_control_read(ctrl_pipe,262 &request, sizeof(usb_device_request_setup_packet_t),263 &status_tmp, sizeof(status_tmp), &recv_size);264 if (rc != EOK) {265 return rc;266 }267 268 if (recv_size != sizeof (status_tmp)) {269 return ELIMIT;270 }271 272 if (status != NULL) {273 *status = status_tmp;274 }275 276 return EOK;277 }278 279 82 /** Callback for enabling a specific port. 280 83 * … … 288 91 static int enable_port_callback(int port_no, void *arg) 289 92 { 290 usb_hub_info_t *hub = arg;93 usb_hub_info_t *hub = (usb_hub_info_t *) arg; 291 94 int rc; 292 95 usb_device_request_setup_packet_t request; … … 353 156 data->hub->ports[data->port].attached_device.address = new_address; 354 157 355 usb_log_info("Detected new device on `%s' (port %zu), " 158 usb_log_info("Detected new device on `%s' (port %zu), " \ 356 159 "address %d (handle %" PRIun ").\n", 357 160 data->hub->usb_device->ddf_dev->name, data->port, … … 363 166 return EOK; 364 167 } 365 366 168 367 169 /** Start device adding when connection change is detected. … … 374 176 * @return Error code. 375 177 */ 376 static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,178 static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port, 377 179 usb_speed_t speed) 378 180 { … … 411 213 } 412 214 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 413 329 /** 414 330 * @}
Note:
See TracChangeset
for help on using the changeset viewer.
