source: mainline/uspace/drv/usbhub/usbhub.c@ e93e319

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e93e319 was e93e319, checked in by Matus Dekanek <smekideki@…>, 14 years ago

second check of bug 138 (multiple new devices)

  • Property mode set to 100644
File size: 20.8 KB
RevLine 
[e080332]1/*
2 * Copyright (c) 2010 Matus Dekanek
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 */
[281ebae]28/** @addtogroup drvusbhub
[e080332]29 * @{
30 */
31/** @file
32 * @brief usb hub main functionality
33 */
34
[eb1a2f4]35#include <ddf/driver.h>
[e080332]36#include <bool.h>
37#include <errno.h>
[4e8e1f5]38#include <str_error.h>
[e080332]39
[71ed4849]40#include <usb_iface.h>
[357a302]41#include <usb/ddfiface.h>
[e080332]42#include <usb/descriptor.h>
[4e8e1f5]43#include <usb/recognise.h>
[d81ef61c]44#include <usb/request.h>
[e080332]45#include <usb/classes/hub.h>
[cd4b184]46#include <stdio.h>
[e080332]47
48#include "usbhub.h"
49#include "usbhub_private.h"
50#include "port_status.h"
[f40a1e2]51#include "usb/usb.h"
[d81ef61c]52#include "usb/pipes.h"
[15b0432]53#include "usb/classes/classes.h"
[e080332]54
[eb1a2f4]55static ddf_dev_ops_t hub_device_ops = {
[357a302]56 .interfaces[USB_DEV_IFACE] = &usb_iface_hub_impl
[71ed4849]57};
58
[cd4b184]59/** Hub status-change endpoint description
60 *
61 * For more see usb hub specification in 11.15.1 of
62 */
[15b0432]63static usb_endpoint_description_t status_change_endpoint_description = {
64 .transfer_type = USB_TRANSFER_INTERRUPT,
65 .direction = USB_DIRECTION_IN,
66 .interface_class = USB_CLASS_HUB,
[cd4b184]67 .interface_subclass = 0,
68 .interface_protocol = 0,
[15b0432]69 .flags = 0
70};
71
[cd4b184]72int usb_hub_control_loop(void * hub_info_param){
73 usb_hub_info_t * hub_info = (usb_hub_info_t*)hub_info_param;
[42a3a57]74 int errorCode = EOK;
75
76 while(errorCode == EOK){
77 errorCode = usb_hub_check_hub_changes(hub_info);
[cd4b184]78 async_usleep(1000 * 1000 );/// \TODO proper number once
79 }
[b495a93]80 usb_log_error("something in ctrl loop went wrong, errno %d",errorCode);
81
[cd4b184]82 return 0;
83}
84
[15b0432]85
[e080332]86//*********************************************
87//
88// hub driver code, initialization
89//
90//*********************************************
91
[15b0432]92/**
93 * Initialize connnections to host controller, device, and device
94 * control endpoint
95 * @param hub
96 * @param device
97 * @return
98 */
99static int usb_hub_init_communication(usb_hub_info_t * hub){
[eb1a2f4]100 usb_log_debug("Initializing hub USB communication (hub->device->handle=%zu).\n", hub->device->handle);
[15b0432]101 int opResult;
102 opResult = usb_device_connection_initialize_from_device(
103 &hub->device_connection,
104 hub->device);
105 if(opResult != EOK){
[b495a93]106 usb_log_error("could not initialize connection to hc, errno %d",opResult);
[15b0432]107 return opResult;
108 }
[eb1a2f4]109 usb_log_debug("Initializing USB wire abstraction.\n");
[15b0432]110 opResult = usb_hc_connection_initialize_from_device(&hub->connection,
111 hub->device);
112 if(opResult != EOK){
[b495a93]113 usb_log_error("could not initialize connection to device, errno %d",
114 opResult);
[15b0432]115 return opResult;
116 }
[eb1a2f4]117 usb_log_debug("Initializing default control pipe.\n");
[15b0432]118 opResult = usb_endpoint_pipe_initialize_default_control(&hub->endpoints.control,
119 &hub->device_connection);
120 if(opResult != EOK){
[b495a93]121 usb_log_error("could not initialize connection to device endpoint, errno %d",
122 opResult);
[206f71a]123 return opResult;
[15b0432]124 }
[206f71a]125
126 opResult = usb_endpoint_pipe_probe_default_control(&hub->endpoints.control);
127 if (opResult != EOK) {
[b495a93]128 usb_log_error("failed probing endpoint 0, %d", opResult);
[206f71a]129 return opResult;
[15b0432]130 }
[206f71a]131
132 return EOK;
[15b0432]133}
134
135/**
136 * When entering this function, hub->endpoints.control should be active.
137 * @param hub
138 * @return
139 */
140static int usb_hub_process_configuration_descriptors(
141 usb_hub_info_t * hub){
142 if(hub==NULL) {
143 return EINVAL;
144 }
145 int opResult;
146
147 //device descriptor
148 usb_standard_device_descriptor_t std_descriptor;
149 opResult = usb_request_get_device_descriptor(&hub->endpoints.control,
150 &std_descriptor);
151 if(opResult!=EOK){
[b495a93]152 usb_log_error("could not get device descriptor, %d",opResult);
[15b0432]153 return opResult;
154 }
[b495a93]155 usb_log_info("hub has %d configurations",
[15b0432]156 std_descriptor.configuration_count);
157 if(std_descriptor.configuration_count<1){
[b495a93]158 usb_log_error("THERE ARE NO CONFIGURATIONS AVAILABLE");
[15b0432]159 //shouldn`t I return?
160 }
161
[d70e0a3c]162 /* Retrieve full configuration descriptor. */
163 uint8_t *descriptors = NULL;
164 size_t descriptors_size = 0;
165 opResult = usb_request_get_full_configuration_descriptor_alloc(
[15b0432]166 &hub->endpoints.control, 0,
[d70e0a3c]167 (void **) &descriptors, &descriptors_size);
168 if (opResult != EOK) {
169 usb_log_error("Could not get configuration descriptor: %s.\n",
170 str_error(opResult));
[15b0432]171 return opResult;
172 }
[d70e0a3c]173 usb_standard_configuration_descriptor_t *config_descriptor
174 = (usb_standard_configuration_descriptor_t *) descriptors;
175
176 /* Set configuration. */
[15b0432]177 opResult = usb_request_set_configuration(&hub->endpoints.control,
[d70e0a3c]178 config_descriptor->configuration_number);
[15b0432]179
180 if (opResult != EOK) {
[d70e0a3c]181 usb_log_error("Failed to set hub configuration: %s.\n",
182 str_error(opResult));
[15b0432]183 return opResult;
184 }
[b495a93]185 usb_log_debug("\tused configuration %d",
[d70e0a3c]186 config_descriptor->configuration_number);
[15b0432]187
188 usb_endpoint_mapping_t endpoint_mapping[1] = {
189 {
190 .pipe = &hub->endpoints.status_change,
191 .description = &status_change_endpoint_description,
192 .interface_no =
193 usb_device_get_assigned_interface(hub->device)
194 }
195 };
196 opResult = usb_endpoint_pipe_initialize_from_configuration(
197 endpoint_mapping, 1,
[d70e0a3c]198 descriptors, descriptors_size,
[15b0432]199 &hub->device_connection);
200 if (opResult != EOK) {
[b495a93]201 usb_log_error("Failed to initialize status change pipe: %s",
[15b0432]202 str_error(opResult));
203 return opResult;
204 }
205 if (!endpoint_mapping[0].present) {
[b495a93]206 usb_log_error("Not accepting device, " \
[15b0432]207 "cannot understand what is happenning");
208 return EREFUSED;
209 }
210
211 free(descriptors);
212 return EOK;
213
214}
215
216
217/**
218 * Create hub representation from device information.
219 * @param device
220 * @return pointer to created structure or NULL in case of error
221 */
[eb1a2f4]222usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device) {
[e080332]223 usb_hub_info_t* result = usb_new(usb_hub_info_t);
[15b0432]224 result->device = device;
225 int opResult;
226 opResult = usb_hub_init_communication(result);
227 if(opResult != EOK){
228 free(result);
229 return NULL;
230 }
[d81ef61c]231
[e080332]232 //result->device = device;
233 result->port_count = -1;
234 result->device = device;
[a83e138]235 result->is_default_address_used = false;
[e080332]236
[6bb83c7]237 //result->usb_device = usb_new(usb_hcd_attached_device_info_t);
[15b0432]238 size_t received_size;
[e080332]239
[15b0432]240 // get hub descriptor
[b495a93]241 usb_log_debug("creating serialized descripton");
[e080332]242 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
243 usb_hub_descriptor_t * descriptor;
[b495a93]244 usb_log_debug("starting control transaction");
[d81ef61c]245 usb_endpoint_pipe_start_session(&result->endpoints.control);
[4e900c1]246 opResult = usb_request_set_configuration(&result->endpoints.control, 1);
247 assert(opResult == EOK);
248
[d81ef61c]249 opResult = usb_request_get_descriptor(&result->endpoints.control,
[140c033]250 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
[ad4562c2]251 USB_DESCTYPE_HUB,
252 0, 0, serialized_descriptor,
[e080332]253 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
[d81ef61c]254 usb_endpoint_pipe_end_session(&result->endpoints.control);
255
[e080332]256 if (opResult != EOK) {
[b495a93]257 usb_log_error("failed when receiving hub descriptor, badcode = %d",
258 opResult);
[e080332]259 free(serialized_descriptor);
[332f860]260 free(result);
261 return NULL;
[e080332]262 }
[b495a93]263 usb_log_debug2("deserializing descriptor");
[e080332]264 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
265 if(descriptor==NULL){
[b495a93]266 usb_log_warning("could not deserialize descriptor ");
[332f860]267 free(result);
268 return NULL;
[e080332]269 }
[15b0432]270
[b495a93]271 usb_log_info("setting port count to %d",descriptor->ports_count);
[e080332]272 result->port_count = descriptor->ports_count;
[6bb83c7]273 result->attached_devs = (usb_hc_attached_device_t*)
274 malloc((result->port_count+1) * sizeof(usb_hc_attached_device_t));
[e080332]275 int i;
276 for(i=0;i<result->port_count+1;++i){
[6bb83c7]277 result->attached_devs[i].handle=0;
[e080332]278 result->attached_devs[i].address=0;
279 }
[b495a93]280 usb_log_debug2("freeing data");
[e080332]281 free(serialized_descriptor);
282 free(descriptor->devices_removable);
283 free(descriptor);
284
285 //finish
286
[b495a93]287 usb_log_info("hub info created");
[e080332]288
289 return result;
290}
291
[15b0432]292/**
293 * Create hub representation and add it into hub list
294 * @param dev
295 * @return
296 */
[eb1a2f4]297int usb_add_hub_device(ddf_dev_t *dev) {
[b495a93]298 usb_log_info("add_hub_device(handle=%d)", (int) dev->handle);
[e080332]299
[eb1a2f4]300 //dev->ops = &hub_device_ops;
301 (void) hub_device_ops;
[e080332]302
[d81ef61c]303 usb_hub_info_t * hub_info = usb_create_hub_info(dev);
[332f860]304 if(!hub_info){
305 return EINTR;
306 }
[6bb83c7]307
[e080332]308 int opResult;
309
[15b0432]310 //perform final configurations
311 usb_endpoint_pipe_start_session(&hub_info->endpoints.control);
312 // process descriptors
313 opResult = usb_hub_process_configuration_descriptors(hub_info);
314 if(opResult != EOK){
[b495a93]315 usb_log_error("could not get configuration descriptors, %d",
[15b0432]316 opResult);
[e080332]317 return opResult;
318 }
[15b0432]319 //power ports
[f40a1e2]320 usb_device_request_setup_packet_t request;
[15b0432]321 int port;
[e080332]322 for (port = 1; port < hub_info->port_count+1; ++port) {
323 usb_hub_set_power_port_request(&request, port);
[d81ef61c]324 opResult = usb_endpoint_pipe_control_write(&hub_info->endpoints.control,
325 &request,sizeof(usb_device_request_setup_packet_t), NULL, 0);
[b495a93]326 usb_log_info("powering port %d",port);
[e080332]327 if (opResult != EOK) {
[b495a93]328 usb_log_warning("something went wrong when setting hub`s %dth port", port);
[e080332]329 }
330 }
331 //ports powered, hub seems to be enabled
[d81ef61c]332 usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
[e080332]333
334 //add the hub to list
[cd4b184]335 //is this needed now?
[ba5ab09]336 fibril_mutex_lock(&usb_hub_list_lock);
[e080332]337 usb_lst_append(&usb_hub_list, hub_info);
[ba5ab09]338 fibril_mutex_unlock(&usb_hub_list_lock);
[b495a93]339 usb_log_debug("hub info added to list");
[cd4b184]340
[b495a93]341 usb_log_debug("adding to ddf");
[cc34f32f]342 ddf_fun_t *hub_fun = ddf_fun_create(dev, fun_exposed, "hub");
343 assert(hub_fun != NULL);
344 hub_fun->ops = NULL;
345
346 int rc = ddf_fun_bind(hub_fun);
347 assert(rc == EOK);
348 rc = ddf_fun_add_to_class(hub_fun, "hub");
349 assert(rc == EOK);
350
[cd4b184]351 fid_t fid = fibril_create(usb_hub_control_loop, hub_info);
352 if (fid == 0) {
[b495a93]353 usb_log_error("failed to start monitoring fibril for new hub");
[cd4b184]354 return ENOMEM;
355 }
356 fibril_add_ready(fid);
357
[b495a93]358 usb_log_debug("hub fibril created");
[e080332]359 //(void)hub_info;
[cd4b184]360 //usb_hub_check_hub_changes();
[e080332]361
[b495a93]362 usb_log_info("hub dev added");
[6bb83c7]363 //address is lost...
[b495a93]364 usb_log_debug("\taddress %d, has %d ports ",
[6bb83c7]365 //hub_info->endpoints.control.,
[e080332]366 hub_info->port_count);
367
368 return EOK;
369 //return ENOTSUP;
370}
371
372
373//*********************************************
374//
375// hub driver code, main loop
376//
377//*********************************************
378
[a83e138]379/**
380 * release default address used by given hub
381 *
382 * Also unsets hub->is_default_address_used. Convenience wrapper function.
383 * @note hub->connection MUST be open for communication
384 * @param hub hub representation
385 * @return error code
386 */
387static int usb_hub_release_default_address(usb_hub_info_t * hub){
388 int opResult = usb_hc_release_default_address(&hub->connection);
389 if(opResult!=EOK){
390 usb_log_error("could not release default address, errno %d",opResult);
391 return opResult;
392 }
393 hub->is_default_address_used = false;
394 return EOK;
395}
396
[e080332]397/**
[f40a1e2]398 * Reset the port with new device and reserve the default address.
[e080332]399 * @param hc
400 * @param port
401 * @param target
402 */
[42a3a57]403static void usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
[a7528a16]404 usb_speed_t speed) {
[a83e138]405 //if this hub already uses default address, it cannot request it once more
406 if(hub->is_default_address_used) return;
[e93e319]407 int opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
408 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
409 if(opResult != EOK){
410 usb_log_warning("could not clear port-change-connection flag");
411 }
[a83e138]412
[e080332]413 usb_device_request_setup_packet_t request;
[b495a93]414 usb_log_info("some connection changed");
[6bb83c7]415 assert(hub->endpoints.control.hc_phone);
[e080332]416 //get default address
[42a3a57]417 opResult = usb_hc_reserve_default_address(&hub->connection, speed);
[cd4b184]418
[e080332]419 if (opResult != EOK) {
[b495a93]420 usb_log_warning("cannot assign default address, it is probably used %d",
421 opResult);
[e080332]422 return;
423 }
[a83e138]424 hub->is_default_address_used = true;
[e080332]425 //reset port
426 usb_hub_set_reset_port_request(&request, port);
[6bb83c7]427 opResult = usb_endpoint_pipe_control_write(
428 &hub->endpoints.control,
429 &request,sizeof(usb_device_request_setup_packet_t),
[e080332]430 NULL, 0
431 );
432 if (opResult != EOK) {
[b495a93]433 usb_log_error("something went wrong when reseting a port %d",opResult);
[6bb83c7]434 //usb_hub_release_default_address(hc);
[a83e138]435 usb_hub_release_default_address(hub);
[e080332]436 }
[e93e319]437 return;
[e080332]438}
439
440/**
[f40a1e2]441 * Finalize adding new device after port reset
[e080332]442 * @param hc
443 * @param port
444 * @param target
445 */
446static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
[cc34f32f]447 uint16_t port, bool isLowSpeed) {
[e080332]448
449 int opResult;
[b495a93]450 usb_log_info("finalizing add device");
[6bb83c7]451 opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
[e080332]452 port, USB_HUB_FEATURE_C_PORT_RESET);
[6bb83c7]453
[e080332]454 if (opResult != EOK) {
[b495a93]455 usb_log_error("failed to clear port reset feature");
[a83e138]456 usb_hub_release_default_address(hub);
[e080332]457 return;
458 }
[6bb83c7]459 //create connection to device
460 usb_endpoint_pipe_t new_device_pipe;
461 usb_device_connection_t new_device_connection;
462 usb_device_connection_initialize_on_default_address(
463 &new_device_connection,
464 &hub->connection
465 );
466 usb_endpoint_pipe_initialize_default_control(
467 &new_device_pipe,
468 &new_device_connection);
[206f71a]469 usb_endpoint_pipe_probe_default_control(&new_device_pipe);
[6bb83c7]470 /// \TODO get highspeed info
[cc34f32f]471 usb_speed_t speed = isLowSpeed?USB_SPEED_LOW:USB_SPEED_FULL;
[e080332]472
[6bb83c7]473
474 /* Request address from host controller. */
475 usb_address_t new_device_address = usb_hc_request_address(
476 &hub->connection,
[3e7b7cd]477 speed
[6bb83c7]478 );
[e080332]479 if (new_device_address < 0) {
[b495a93]480 usb_log_error("failed to get free USB address");
[e080332]481 opResult = new_device_address;
[a83e138]482 usb_hub_release_default_address(hub);
[e080332]483 return;
484 }
[b495a93]485 usb_log_info("setting new address %d",new_device_address);
[6bb83c7]486 //opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
487 // new_device_address);
[cd4b184]488 usb_endpoint_pipe_start_session(&new_device_pipe);
[6bb83c7]489 opResult = usb_request_set_address(&new_device_pipe,new_device_address);
[cd4b184]490 usb_endpoint_pipe_end_session(&new_device_pipe);
[e080332]491 if (opResult != EOK) {
[b495a93]492 usb_log_error("could not set address for new device %d",opResult);
[a83e138]493 usb_hub_release_default_address(hub);
[e080332]494 return;
495 }
496
497
[6bb83c7]498 //opResult = usb_hub_release_default_address(hc);
[a83e138]499 opResult = usb_hub_release_default_address(hub);
[e080332]500 if(opResult!=EOK){
501 return;
502 }
503
504 devman_handle_t child_handle;
[6bb83c7]505 //??
506 opResult = usb_device_register_child_in_devman(new_device_address,
[eb1a2f4]507 hub->connection.hc_handle, hub->device, &child_handle,
508 NULL, NULL, NULL);
[6bb83c7]509
[e080332]510 if (opResult != EOK) {
[b495a93]511 usb_log_error("could not start driver for new device %d",opResult);
[e080332]512 return;
513 }
[6bb83c7]514 hub->attached_devs[port].handle = child_handle;
[e080332]515 hub->attached_devs[port].address = new_device_address;
516
[6bb83c7]517 //opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
518 opResult = usb_hc_register_device(
519 &hub->connection,
520 &hub->attached_devs[port]);
[e080332]521 if (opResult != EOK) {
[b495a93]522 usb_log_error("could not assign address of device in hcd %d",opResult);
[e080332]523 return;
524 }
[b495a93]525 usb_log_info("new device address %d, handle %zu",
[e080332]526 new_device_address, child_handle);
527
528}
529
530/**
[f40a1e2]531 * Unregister device address in hc
[e080332]532 * @param hc
533 * @param port
534 * @param target
535 */
536static void usb_hub_removed_device(
[6bb83c7]537 usb_hub_info_t * hub,uint16_t port) {
[e93e319]538
539 int opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
540 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
541 if(opResult != EOK){
542 usb_log_warning("could not clear port-change-connection flag");
543 }
[f40a1e2]544 /** \TODO remove device from device manager - not yet implemented in
545 * devide manager
546 */
[6bb83c7]547
[e080332]548 //close address
549 if(hub->attached_devs[port].address!=0){
[42a3a57]550 /*uncomment this code to use it when DDF allows device removal
[6bb83c7]551 opResult = usb_hc_unregister_device(
552 &hub->connection, hub->attached_devs[port].address);
[e080332]553 if(opResult != EOK) {
[103a3626]554 dprintf(USB_LOG_LEVEL_WARNING, "could not release address of " \
[0cfc68f0]555 "removed device: %d", opResult);
[e080332]556 }
557 hub->attached_devs[port].address = 0;
[6bb83c7]558 hub->attached_devs[port].handle = 0;
[42a3a57]559 */
[e080332]560 }else{
[b495a93]561 usb_log_warning("this is strange, disconnected device had no address");
[e080332]562 //device was disconnected before it`s port was reset - return default address
[a83e138]563 usb_hub_release_default_address(hub);
[e080332]564 }
565}
566
[cd4b184]567
568/**
[b495a93]569 * Process over current condition on port.
[cd4b184]570 *
571 * Turn off the power on the port.
572 *
573 * @param hub
574 * @param port
575 */
576static void usb_hub_over_current( usb_hub_info_t * hub,
577 uint16_t port){
578 int opResult;
579 opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
580 port, USB_HUB_FEATURE_PORT_POWER);
581 if(opResult!=EOK){
[b495a93]582 usb_log_error("cannot power off port %d; %d",
[cd4b184]583 port, opResult);
584 }
585}
586
[e080332]587/**
[f40a1e2]588 * Process interrupts on given hub port
[e080332]589 * @param hc
590 * @param port
591 * @param target
592 */
[d81ef61c]593static void usb_hub_process_interrupt(usb_hub_info_t * hub,
594 uint16_t port) {
[b495a93]595 usb_log_debug("interrupt at port %d", port);
[e080332]596 //determine type of change
[d81ef61c]597 usb_endpoint_pipe_t *pipe = &hub->endpoints.control;
[6bb83c7]598
[cd4b184]599 int opResult;
[d81ef61c]600
[e080332]601 usb_port_status_t status;
602 size_t rcvd_size;
603 usb_device_request_setup_packet_t request;
[d81ef61c]604 //int opResult;
[e080332]605 usb_hub_set_port_status_request(&request, port);
606 //endpoint 0
607
[d81ef61c]608 opResult = usb_endpoint_pipe_control_read(
609 pipe,
610 &request, sizeof(usb_device_request_setup_packet_t),
[e080332]611 &status, 4, &rcvd_size
612 );
613 if (opResult != EOK) {
[b495a93]614 usb_log_error("could not get port status");
[e080332]615 return;
616 }
617 if (rcvd_size != sizeof (usb_port_status_t)) {
[b495a93]618 usb_log_error("received status has incorrect size");
[e080332]619 return;
620 }
621 //something connected/disconnected
622 if (usb_port_connect_change(&status)) {
623 if (usb_port_dev_connected(&status)) {
[b495a93]624 usb_log_info("some connection changed");
[a7528a16]625 usb_hub_init_add_device(hub, port, usb_port_speed(&status));
[e080332]626 } else {
[d81ef61c]627 usb_hub_removed_device(hub, port);
[e080332]628 }
629 }
[cd4b184]630 //over current
631 if (usb_port_overcurrent_change(&status)) {
632 //check if it was not auto-resolved
633 if(usb_port_over_current(&status)){
634 usb_hub_over_current(hub,port);
635 }else{
[b495a93]636 usb_log_info("over current condition was auto-resolved on port %d",
637 port);
[cd4b184]638 }
639 }
[e080332]640 //port reset
641 if (usb_port_reset_completed(&status)) {
[b495a93]642 usb_log_info("port reset complete");
[e080332]643 if (usb_port_enabled(&status)) {
[cc34f32f]644 usb_hub_finalize_add_device(hub, port, usb_port_low_speed(&status));
[e080332]645 } else {
[b495a93]646 usb_log_warning("port reset, but port still not enabled");
[e080332]647 }
648 }
649
650 usb_port_set_connect_change(&status, false);
651 usb_port_set_reset(&status, false);
652 usb_port_set_reset_completed(&status, false);
653 usb_port_set_dev_connected(&status, false);
[f40a1e2]654 if (status>>16) {
[b495a93]655 usb_log_info("there was some unsupported change on port %d: %X",
656 port,status);
[f40a1e2]657
[e080332]658 }
[b495a93]659 /// \TODO handle other changes - is there any?
[e080332]660}
661
[f40a1e2]662/**
[cd4b184]663 * Check changes on particular hub
[42a3a57]664 * @param hub_info_param pointer to usb_hub_info_t structure
665 * @return error code if there is problem when initializing communication with
666 * hub, EOK otherwise
[e080332]667 */
[42a3a57]668int usb_hub_check_hub_changes(usb_hub_info_t * hub_info){
[cd4b184]669 int opResult;
670 opResult = usb_endpoint_pipe_start_session(&hub_info->endpoints.status_change);
671 if(opResult != EOK){
[b495a93]672 usb_log_error("could not initialize communication for hub; %d",
673 opResult);
[42a3a57]674 return opResult;
[cd4b184]675 }
676
677 size_t port_count = hub_info->port_count;
[e080332]678
[cd4b184]679 /// FIXME: count properly
680 size_t byte_length = ((port_count+1) / 8) + 1;
[e080332]681 void *change_bitmap = malloc(byte_length);
[cd4b184]682 size_t actual_size;
[e080332]683
[cd4b184]684 /*
685 * Send the request.
686 */
687 opResult = usb_endpoint_pipe_read(
688 &hub_info->endpoints.status_change,
689 change_bitmap, byte_length, &actual_size
690 );
[e080332]691
[cd4b184]692 if (opResult != EOK) {
[5097bed4]693 free(change_bitmap);
[b495a93]694 usb_log_warning("something went wrong while getting status of hub");
[dff940f8]695 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
[42a3a57]696 return opResult;
[cd4b184]697 }
698 unsigned int port;
699 opResult = usb_endpoint_pipe_start_session(&hub_info->endpoints.control);
[dff940f8]700 if(opResult!=EOK){
[b495a93]701 usb_log_error("could not start control pipe session %d", opResult);
[dff940f8]702 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
[42a3a57]703 return opResult;
[dff940f8]704 }
705 opResult = usb_hc_connection_open(&hub_info->connection);
706 if(opResult!=EOK){
[b495a93]707 usb_log_error("could not start host controller session %d",
[dff940f8]708 opResult);
709 usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
710 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
[42a3a57]711 return opResult;
[dff940f8]712 }
[cd4b184]713
714 ///todo, opresult check, pre obe konekce
715 for (port = 1; port < port_count+1; ++port) {
716 bool interrupt =
717 (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
718 if (interrupt) {
719 usb_hub_process_interrupt(
720 hub_info, port);
721 }
722 }
723 usb_hc_connection_close(&hub_info->connection);
724 usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
725 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
726 free(change_bitmap);
[42a3a57]727 return EOK;
[cd4b184]728}
[e080332]729
730
731
732/**
733 * @}
[71ed4849]734 */
Note: See TracBrowser for help on using the repository browser.