source: mainline/uspace/drv/usbhub/usbhub.c@ 195890b

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

codelifting

  • Property mode set to 100644
File size: 25.5 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
[df3ad97]55
[6c399765]56static int usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
[195890b]57 usb_speed_t speed);
[e6223239]58
[df3ad97]59static int usb_hub_trigger_connecting_non_removable_devices(
[195890b]60 usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor);
[e6223239]61
[df3ad97]62/**
63 * control loop running in hub`s fibril
64 *
65 * Hub`s fibril periodically asks for changes on hub and if needded calls
66 * change handling routine.
67 * @warning currently hub driver asks for changes once a second
68 * @param hub_info_param hub representation pointer
69 * @return zero
70 */
[195890b]71int usb_hub_control_loop(void * hub_info_param) {
72 usb_hub_info_t * hub_info = (usb_hub_info_t*) hub_info_param;
[42a3a57]73 int errorCode = EOK;
74
[195890b]75 while (errorCode == EOK) {
76 async_usleep(1000 * 1000 * 10); /// \TODO proper number once
[42a3a57]77 errorCode = usb_hub_check_hub_changes(hub_info);
[195890b]78
[cd4b184]79 }
[195890b]80 usb_log_error("something in ctrl loop went wrong, errno %d\n",
81 errorCode);
[b495a93]82
[cd4b184]83 return 0;
84}
85
[15b0432]86
[e080332]87//*********************************************
88//
89// hub driver code, initialization
90//
91//*********************************************
92
[15b0432]93/**
[09daa8b]94 * create usb_hub_info_t structure
95 *
96 * Does only basic copying of known information into new structure.
97 * @param usb_dev usb device structure
98 * @return basic usb_hub_info_t structure
[15b0432]99 */
[09daa8b]100static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) {
101 usb_hub_info_t * result = usb_new(usb_hub_info_t);
[195890b]102 if (!result) return NULL;
[09daa8b]103 result->usb_device = usb_dev;
104 result->status_change_pipe = usb_dev->pipes[0].pipe;
105 result->control_pipe = &usb_dev->ctrl_pipe;
106 result->is_default_address_used = false;
107 return result;
108}
109
110/**
[e6223239]111 * Load hub-specific information into hub_info structure and process if needed
[09daa8b]112 *
113 * Particularly read port count and initialize structure holding port
[e6223239]114 * information. If there are non-removable devices, start initializing them.
[09daa8b]115 * This function is hub-specific and should be run only after the hub is
116 * configured using usb_hub_set_configuration function.
[df3ad97]117 * @param hub_info hub representation
[09daa8b]118 * @return error code
119 */
[195890b]120static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) {
[09daa8b]121 // get hub descriptor
122 usb_log_debug("creating serialized descriptor\n");
123 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
124 usb_hub_descriptor_t * descriptor;
125
126 /* this was one fix of some bug, should not be needed anymore
[e6223239]127 * these lines allow to reset hub once more, it can be used as
128 * brute-force initialization for non-removable devices
[6c399765]129 */
130 int opResult = usb_request_set_configuration(hub_info->control_pipe,
[195890b]131 1);
132 if (opResult != EOK) {
133 usb_log_error("could not set default configuration, errno %d",
134 opResult);
[15b0432]135 return opResult;
136 }
[195890b]137
138
[09daa8b]139 size_t received_size;
[6c399765]140 opResult = usb_request_get_descriptor(&hub_info->usb_device->ctrl_pipe,
[195890b]141 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
142 USB_DESCTYPE_HUB,
143 0, 0, serialized_descriptor,
144 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
[09daa8b]145
146 if (opResult != EOK) {
[195890b]147 usb_log_error("failed when receiving hub descriptor, "
148 "badcode = %d\n",
149 opResult);
[09daa8b]150 free(serialized_descriptor);
[15b0432]151 return opResult;
152 }
[09daa8b]153 usb_log_debug2("deserializing descriptor\n");
154 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
[195890b]155 if (descriptor == NULL) {
[09daa8b]156 usb_log_warning("could not deserialize descriptor \n");
[206f71a]157 return opResult;
[15b0432]158 }
[195890b]159 usb_log_debug("setting port count to %d\n", descriptor->ports_count);
[09daa8b]160 hub_info->port_count = descriptor->ports_count;
161 hub_info->attached_devs = (usb_hc_attached_device_t*)
[195890b]162 malloc((hub_info->port_count + 1) *
163 sizeof (usb_hc_attached_device_t)
164 );
[09daa8b]165 int i;
[195890b]166 for (i = 0; i < hub_info->port_count + 1; ++i) {
167 hub_info->attached_devs[i].handle = 0;
168 hub_info->attached_devs[i].address = 0;
[15b0432]169 }
[df3ad97]170 //handle non-removable devices
171 usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor);
[09daa8b]172 usb_log_debug2("freeing data\n");
173 free(serialized_descriptor);
[6c399765]174 hub_info->descriptor = descriptor;
175 hub_info->not_initialized_non_removables =
[195890b]176 (uint8_t*) malloc((hub_info->port_count + 8) / 8);
[6c399765]177 memcpy(hub_info->not_initialized_non_removables,
178 descriptor->devices_removable,
[195890b]179 (hub_info->port_count + 8) / 8
[6c399765]180 );
181
182 //free(descriptor->devices_removable);
183 //free(descriptor);
[206f71a]184 return EOK;
[15b0432]185}
[195890b]186
[15b0432]187/**
[09daa8b]188 * Set configuration of hub
189 *
190 * Check whether there is at least one configuration and sets the first one.
191 * This function should be run prior to running any hub-specific action.
[df3ad97]192 * @param hub_info hub representation
193 * @return error code
[15b0432]194 */
[195890b]195static int usb_hub_set_configuration(usb_hub_info_t * hub_info) {
[15b0432]196 //device descriptor
[625f1ba]197 usb_standard_device_descriptor_t *std_descriptor
[195890b]198 = &hub_info->usb_device->descriptors.device;
[fbefd0e]199 usb_log_debug("hub has %d configurations\n",
[195890b]200 std_descriptor->configuration_count);
201 if (std_descriptor->configuration_count < 1) {
[4d0c40b]202 usb_log_error("there are no configurations available\n");
[625f1ba]203 return EINVAL;
[15b0432]204 }
205
[d70e0a3c]206 usb_standard_configuration_descriptor_t *config_descriptor
[195890b]207 = (usb_standard_configuration_descriptor_t *)
208 hub_info->usb_device->descriptors.configuration;
[d70e0a3c]209
210 /* Set configuration. */
[625f1ba]211 int opResult = usb_request_set_configuration(
[195890b]212 &hub_info->usb_device->ctrl_pipe,
213 config_descriptor->configuration_number);
[15b0432]214
215 if (opResult != EOK) {
[d70e0a3c]216 usb_log_error("Failed to set hub configuration: %s.\n",
[195890b]217 str_error(opResult));
[15b0432]218 return opResult;
219 }
[09daa8b]220 usb_log_debug("\tused configuration %d\n",
[195890b]221 config_descriptor->configuration_number);
[625f1ba]222
[15b0432]223 return EOK;
224}
225
226/**
[09daa8b]227 * Initialize hub device driver fibril
228 *
229 * Creates hub representation and fibril that periodically checks hub`s status.
230 * Hub representation is passed to the fibril.
231 * @param usb_dev generic usb device information
232 * @return error code
[15b0432]233 */
[195890b]234int usb_hub_add_device(usb_device_t * usb_dev) {
235 if (!usb_dev) return EINVAL;
[09daa8b]236 usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
237 //create hc connection
238 usb_log_debug("Initializing USB wire abstraction.\n");
239 int opResult = usb_hc_connection_initialize_from_device(
[195890b]240 &hub_info->connection,
241 hub_info->usb_device->ddf_dev);
242 if (opResult != EOK) {
243 usb_log_error("could not initialize connection to device, "
244 "errno %d\n",
245 opResult);
[09daa8b]246 free(hub_info);
247 return opResult;
[332f860]248 }
[195890b]249
[3954a63b]250 usb_pipe_start_session(hub_info->control_pipe);
[09daa8b]251 //set hub configuration
252 opResult = usb_hub_set_configuration(hub_info);
[195890b]253 if (opResult != EOK) {
254 usb_log_error("could not set hub configuration, errno %d\n",
255 opResult);
[09daa8b]256 free(hub_info);
[e080332]257 return opResult;
258 }
[09daa8b]259 //get port count and create attached_devs
[e6223239]260 opResult = usb_hub_process_hub_specific_info(hub_info);
[195890b]261 if (opResult != EOK) {
262 usb_log_error("could not set hub configuration, errno %d\n",
263 opResult);
[09daa8b]264 free(hub_info);
265 return opResult;
[e080332]266 }
[3954a63b]267 usb_pipe_end_session(hub_info->control_pipe);
[e080332]268
[cd4b184]269
[09daa8b]270 /// \TODO what is this?
[625f1ba]271 usb_log_debug("Creating `hub' function.\n");
[09daa8b]272 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
[195890b]273 fun_exposed, "hub");
[cc34f32f]274 assert(hub_fun != NULL);
275 hub_fun->ops = NULL;
276
277 int rc = ddf_fun_bind(hub_fun);
278 assert(rc == EOK);
279 rc = ddf_fun_add_to_class(hub_fun, "hub");
280 assert(rc == EOK);
281
[09daa8b]282 //create fibril for the hub control loop
[cd4b184]283 fid_t fid = fibril_create(usb_hub_control_loop, hub_info);
284 if (fid == 0) {
[195890b]285 usb_log_error("failed to start monitoring fibril for new"
286 " hub.\n");
[cd4b184]287 return ENOMEM;
288 }
289 fibril_add_ready(fid);
[625f1ba]290 usb_log_debug("Hub fibril created.\n");
291
292 usb_log_info("Controlling hub `%s' (%d ports).\n",
[195890b]293 hub_info->usb_device->ddf_dev->name, hub_info->port_count);
[e080332]294 return EOK;
295}
296
297
298//*********************************************
299//
[e6223239]300// hub driver code, main loop and port handling
[e080332]301//
302//*********************************************
303
[e6223239]304/**
[df3ad97]305 * triggers actions to connect non0removable devices
[e6223239]306 *
307 * This will trigger operations leading to activated non-removable device.
308 * Control pipe of the hub must be open fo communication.
[df3ad97]309 * @param hub hub representation
[e6223239]310 * @param descriptor usb hub descriptor
311 * @return error code
312 */
[6c399765]313static int usb_hub_trigger_connecting_non_removable_devices(
[195890b]314 usb_hub_info_t * hub,
315 usb_hub_descriptor_t * descriptor) {
[e6223239]316 usb_log_info("attaching non-removable devices(if any)\n");
[6c399765]317 //usb_device_request_setup_packet_t request;
[e6223239]318 int opResult;
[6c399765]319 //size_t rcvd_size;
320 //usb_port_status_t status;
[e6223239]321 uint8_t * non_removable_dev_bitmap = descriptor->devices_removable;
322 int port;
[6c399765]323
324 opResult = usb_request_set_configuration(hub->control_pipe,
[195890b]325 1);
326 if (opResult != EOK) {
327 usb_log_error("could not set default configuration, errno %d",
328 opResult);
[6c399765]329 return opResult;
330 }
331#if 0
[195890b]332 for (port = 1; port <= descriptor->ports_count; ++port) {
[e6223239]333 bool is_non_removable =
[195890b]334 ((non_removable_dev_bitmap[port / 8]) >> (port % 8)) % 2;
335 if (is_non_removable) {
336 usb_log_debug("non-removable device on port %d\n", port);
[e6223239]337 usb_hub_set_port_status_request(&request, port);
338 opResult = usb_pipe_control_read(
[195890b]339 hub->control_pipe,
340 &request,
341 sizeof (usb_device_request_setup_packet_t),
342 &status, 4, &rcvd_size
343 );
[e6223239]344 if (opResult != EOK) {
[195890b]345 usb_log_error("could not get port status of "
346 "port %d errno:%d\n",
347 port, opResult);
[e6223239]348 return opResult;
349 }
[6c399765]350 //try to reset port
[195890b]351 if (usb_port_dev_connected(&status) || true) {
352 usb_hub_set_enable_port_feature_request(
353 &request, port,
354 USB_HUB_FEATURE_PORT_RESET);
[6c399765]355 opResult = usb_pipe_control_read(
[195890b]356 hub->control_pipe,
357 &request,
358 sizeof (usb_device_request_setup_packet_t),
359 &status, 4, &rcvd_size
360 );
[6c399765]361 if (opResult != EOK) {
362 usb_log_warning(
[195890b]363 "could not reset port %d "
364 "errno:%d\n",
365 port, opResult);
[6c399765]366 }
[195890b]367 usb_log_debug("port reset, should look like "
368 "%d,x%x\n",
369 (1 << USB_HUB_FEATURE_PORT_RESET),
370 (1 << USB_HUB_FEATURE_PORT_RESET)
371 );
[4fbcd2a]372 }
[195890b]373 //set the status change bit, so it will be noticed
374 //in driver loop
375 if (usb_port_dev_connected(&status) && false) {
376 usb_hub_set_disable_port_feature_request(
377 &request, port,
378 USB_HUB_FEATURE_PORT_CONNECTION);
[8123695a]379 opResult = usb_pipe_control_read(
[195890b]380 hub->control_pipe,
381 &request,
382 sizeof (usb_device_request_setup_packet_t),
383 &status, 4, &rcvd_size
384 );
[8123695a]385 if (opResult != EOK) {
386 usb_log_warning(
[195890b]387 "could not clear port "
388 "connection on port %d "
389 "errno:%d\n",
390 port, opResult);
[8123695a]391 }
392 usb_log_debug("cleared port connection\n");
[195890b]393 usb_hub_set_enable_port_feature_request(&request,
394 port,
395 USB_HUB_FEATURE_PORT_ENABLE);
[df3ad97]396 opResult = usb_pipe_control_read(
[195890b]397 hub->control_pipe,
398 &request,
399 sizeof (usb_device_request_setup_packet_t),
400 &status, 4, &rcvd_size
401 );
[df3ad97]402 if (opResult != EOK) {
403 usb_log_warning(
[195890b]404 "could not set port enabled "
405 "on port %d errno:%d\n",
406 port, opResult);
[df3ad97]407 }
[195890b]408 usb_log_debug("port set to enabled - "
409 "should lead to connection change\n");
[6c399765]410 }
[e6223239]411 }
412 }
[6c399765]413#endif
414
[a9c7c6f]415 /// \TODO this is just a debug code
[195890b]416 for (port = 1; port <= descriptor->ports_count; ++port) {
[a9c7c6f]417 bool is_non_removable =
[195890b]418 ((non_removable_dev_bitmap[port / 8]) >> (port % 8)) % 2;
419 if (is_non_removable) {
420 usb_log_debug("CHECKING port %d is non-removable\n",
421 port);
[a9c7c6f]422 usb_port_status_t status;
423 size_t rcvd_size;
424 usb_device_request_setup_packet_t request;
425 //int opResult;
426 usb_hub_set_port_status_request(&request, port);
427 //endpoint 0
428 opResult = usb_pipe_control_read(
[195890b]429 hub->control_pipe,
430 &request,
431 sizeof (usb_device_request_setup_packet_t),
432 &status, 4, &rcvd_size
433 );
[a9c7c6f]434 if (opResult != EOK) {
[195890b]435 usb_log_error("could not get port status %d\n",
436 opResult);
[a9c7c6f]437 }
438 if (rcvd_size != sizeof (usb_port_status_t)) {
[195890b]439 usb_log_error("received status has incorrect"
440 " size\n");
[a9c7c6f]441 }
442 //something connected/disconnected
443 if (usb_port_connect_change(&status)) {
444 usb_log_debug("some connection changed\n");
445 }
[195890b]446 usb_log_debug("status: %s\n", usb_debug_str_buffer(
447 (uint8_t *) & status, 4, 4));
[a9c7c6f]448 }
449 }
[6c399765]450
[e6223239]451 return EOK;
452}
453
[a83e138]454/**
455 * release default address used by given hub
456 *
457 * Also unsets hub->is_default_address_used. Convenience wrapper function.
458 * @note hub->connection MUST be open for communication
459 * @param hub hub representation
460 * @return error code
461 */
[195890b]462static int usb_hub_release_default_address(usb_hub_info_t * hub) {
[a83e138]463 int opResult = usb_hc_release_default_address(&hub->connection);
[195890b]464 if (opResult != EOK) {
465 usb_log_error("could not release default address, errno %d\n",
466 opResult);
[a83e138]467 return opResult;
468 }
469 hub->is_default_address_used = false;
470 return EOK;
471}
472
[e080332]473/**
[f40a1e2]474 * Reset the port with new device and reserve the default address.
[df3ad97]475 * @param hub hub representation
476 * @param port port number, starting from 1
477 * @param speed transfer speed of attached device, one of low, full or high
[6c399765]478 * @return error code
[e080332]479 */
[6c399765]480static int usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
[195890b]481 usb_speed_t speed) {
[a83e138]482 //if this hub already uses default address, it cannot request it once more
[195890b]483 if (hub->is_default_address_used) return EREFUSED;
[fbefd0e]484 usb_log_debug("some connection changed\n");
[09daa8b]485 assert(hub->control_pipe->hc_phone);
486 int opResult = usb_hub_clear_port_feature(hub->control_pipe,
[195890b]487 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
488 if (opResult != EOK) {
[09daa8b]489 usb_log_warning("could not clear port-change-connection flag\n");
[e93e319]490 }
[e080332]491 usb_device_request_setup_packet_t request;
[195890b]492
[e080332]493 //get default address
[42a3a57]494 opResult = usb_hc_reserve_default_address(&hub->connection, speed);
[195890b]495
[e080332]496 if (opResult != EOK) {
[195890b]497 usb_log_warning("cannot assign default address, it is probably "
498 "used %d\n",
499 opResult);
[6c399765]500 return opResult;
[e080332]501 }
[a83e138]502 hub->is_default_address_used = true;
[e080332]503 //reset port
504 usb_hub_set_reset_port_request(&request, port);
[3954a63b]505 opResult = usb_pipe_control_write(
[195890b]506 hub->control_pipe,
507 &request, sizeof (usb_device_request_setup_packet_t),
508 NULL, 0
509 );
[e080332]510 if (opResult != EOK) {
[195890b]511 usb_log_error("something went wrong when reseting a port %d\n",
512 opResult);
[a83e138]513 usb_hub_release_default_address(hub);
[e080332]514 }
[6c399765]515 return opResult;
[e080332]516}
517
518/**
[f40a1e2]519 * Finalize adding new device after port reset
[df3ad97]520 *
521 * Set device`s address and start it`s driver.
522 * @param hub hub representation
523 * @param port port number, starting from 1
524 * @param speed transfer speed of attached device, one of low, full or high
[e080332]525 */
[195890b]526static void usb_hub_finalize_add_device(usb_hub_info_t * hub,
527 uint16_t port, usb_speed_t speed) {
[e080332]528
529 int opResult;
[fbefd0e]530 usb_log_debug("finalizing add device\n");
[09daa8b]531 opResult = usb_hub_clear_port_feature(hub->control_pipe,
[195890b]532 port, USB_HUB_FEATURE_C_PORT_RESET);
[6bb83c7]533
[e080332]534 if (opResult != EOK) {
[09daa8b]535 usb_log_error("failed to clear port reset feature\n");
[a83e138]536 usb_hub_release_default_address(hub);
[e080332]537 return;
538 }
[6bb83c7]539 //create connection to device
[a372663]540 usb_pipe_t new_device_pipe;
[6bb83c7]541 usb_device_connection_t new_device_connection;
542 usb_device_connection_initialize_on_default_address(
[195890b]543 &new_device_connection,
544 &hub->connection
545 );
[3954a63b]546 usb_pipe_initialize_default_control(
[195890b]547 &new_device_pipe,
548 &new_device_connection);
[3954a63b]549 usb_pipe_probe_default_control(&new_device_pipe);
[6bb83c7]550
551 /* Request address from host controller. */
552 usb_address_t new_device_address = usb_hc_request_address(
[195890b]553 &hub->connection,
554 speed
555 );
[e080332]556 if (new_device_address < 0) {
[09daa8b]557 usb_log_error("failed to get free USB address\n");
[e080332]558 opResult = new_device_address;
[a83e138]559 usb_hub_release_default_address(hub);
[e080332]560 return;
561 }
[195890b]562 usb_log_debug("setting new address %d\n", new_device_address);
[6bb83c7]563 //opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
564 // new_device_address);
[3954a63b]565 usb_pipe_start_session(&new_device_pipe);
[195890b]566 opResult = usb_request_set_address(&new_device_pipe,
567 new_device_address);
[3954a63b]568 usb_pipe_end_session(&new_device_pipe);
[e080332]569 if (opResult != EOK) {
[195890b]570 usb_log_error("could not set address for new device %d\n",
571 opResult);
[a83e138]572 usb_hub_release_default_address(hub);
[e080332]573 return;
574 }
575
[6bb83c7]576 //opResult = usb_hub_release_default_address(hc);
[a83e138]577 opResult = usb_hub_release_default_address(hub);
[195890b]578 if (opResult != EOK) {
[e080332]579 return;
580 }
581
582 devman_handle_t child_handle;
[6bb83c7]583 //??
[195890b]584 opResult = usb_device_register_child_in_devman(new_device_address,
585 hub->connection.hc_handle, hub->usb_device->ddf_dev,
586 &child_handle,
587 NULL, NULL, NULL);
[6bb83c7]588
[e080332]589 if (opResult != EOK) {
[195890b]590 usb_log_error("could not start driver for new device %d\n",
591 opResult);
[e080332]592 return;
593 }
[6bb83c7]594 hub->attached_devs[port].handle = child_handle;
[e080332]595 hub->attached_devs[port].address = new_device_address;
596
[6bb83c7]597 //opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
598 opResult = usb_hc_register_device(
[195890b]599 &hub->connection,
600 &hub->attached_devs[port]);
[e080332]601 if (opResult != EOK) {
[195890b]602 usb_log_error("could not assign address of device in hcd %d\n",
603 opResult);
[e080332]604 return;
605 }
[fbefd0e]606 usb_log_info("Detected new device on `%s' (port %d), " \
607 "address %d (handle %llu).\n",
[195890b]608 hub->usb_device->ddf_dev->name, (int) port,
609 new_device_address, child_handle);
[e080332]610}
611
612/**
[df3ad97]613 * routine called when a device on port has been removed
614 *
615 * If the device on port had default address, it releases default address.
616 * Otherwise does not do anything, because DDF does not allow to remove device
617 * from it`s device tree.
618 * @param hub hub representation
619 * @param port port number, starting from 1
[e080332]620 */
621static void usb_hub_removed_device(
[195890b]622 usb_hub_info_t * hub, uint16_t port) {
[e93e319]623
[09daa8b]624 int opResult = usb_hub_clear_port_feature(hub->control_pipe,
[195890b]625 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
626 if (opResult != EOK) {
[09daa8b]627 usb_log_warning("could not clear port-change-connection flag\n");
[e93e319]628 }
[f40a1e2]629 /** \TODO remove device from device manager - not yet implemented in
630 * devide manager
631 */
[195890b]632
[e080332]633 //close address
[195890b]634 if (hub->attached_devs[port].address != 0) {
[42a3a57]635 /*uncomment this code to use it when DDF allows device removal
[6bb83c7]636 opResult = usb_hc_unregister_device(
[195890b]637 &hub->connection,
638 hub->attached_devs[port].address);
[e080332]639 if(opResult != EOK) {
[195890b]640 dprintf(USB_LOG_LEVEL_WARNING, "could not release "
641 "address of "
[0cfc68f0]642 "removed device: %d", opResult);
[e080332]643 }
644 hub->attached_devs[port].address = 0;
[6bb83c7]645 hub->attached_devs[port].handle = 0;
[42a3a57]646 */
[195890b]647 } else {
648 usb_log_warning("this is strange, disconnected device had "
649 "no address\n");
650 //device was disconnected before it`s port was reset -
651 //return default address
[a83e138]652 usb_hub_release_default_address(hub);
[e080332]653 }
654}
655
[cd4b184]656/**
[b495a93]657 * Process over current condition on port.
[195890b]658 *
[cd4b184]659 * Turn off the power on the port.
660 *
[df3ad97]661 * @param hub hub representation
662 * @param port port number, starting from 1
[cd4b184]663 */
[195890b]664static void usb_hub_over_current(usb_hub_info_t * hub,
665 uint16_t port) {
[cd4b184]666 int opResult;
[09daa8b]667 opResult = usb_hub_clear_port_feature(hub->control_pipe,
[195890b]668 port, USB_HUB_FEATURE_PORT_POWER);
669 if (opResult != EOK) {
[09daa8b]670 usb_log_error("cannot power off port %d; %d\n",
[195890b]671 port, opResult);
[cd4b184]672 }
673}
674
[e080332]675/**
[f40a1e2]676 * Process interrupts on given hub port
[df3ad97]677 *
678 * Accepts connection, over current and port reset change.
679 * @param hub hub representation
680 * @param port port number, starting from 1
[e080332]681 */
[195890b]682static void usb_hub_process_interrupt(usb_hub_info_t * hub,
683 uint16_t port) {
[09daa8b]684 usb_log_debug("interrupt at port %d\n", port);
[e080332]685 //determine type of change
[a372663]686 usb_pipe_t *pipe = hub->control_pipe;
[195890b]687
[cd4b184]688 int opResult;
[d81ef61c]689
[e080332]690 usb_port_status_t status;
691 size_t rcvd_size;
692 usb_device_request_setup_packet_t request;
[d81ef61c]693 //int opResult;
[e080332]694 usb_hub_set_port_status_request(&request, port);
695 //endpoint 0
696
[3954a63b]697 opResult = usb_pipe_control_read(
[195890b]698 pipe,
699 &request, sizeof (usb_device_request_setup_packet_t),
700 &status, 4, &rcvd_size
701 );
[e080332]702 if (opResult != EOK) {
[09daa8b]703 usb_log_error("could not get port status\n");
[e080332]704 return;
705 }
706 if (rcvd_size != sizeof (usb_port_status_t)) {
[09daa8b]707 usb_log_error("received status has incorrect size\n");
[e080332]708 return;
709 }
710 //something connected/disconnected
711 if (usb_port_connect_change(&status)) {
[8123695a]712 usb_log_debug("connection change on port\n");
[e080332]713 if (usb_port_dev_connected(&status)) {
[fbefd0e]714 usb_log_debug("some connection changed\n");
[195890b]715 usb_hub_init_add_device(hub, port,
716 usb_port_speed(&status));
[e080332]717 } else {
[d81ef61c]718 usb_hub_removed_device(hub, port);
[e080332]719 }
720 }
[cd4b184]721 //over current
722 if (usb_port_overcurrent_change(&status)) {
723 //check if it was not auto-resolved
[8123695a]724 usb_log_debug("overcurrent change on port\n");
[195890b]725 if (usb_port_over_current(&status)) {
726 usb_hub_over_current(hub, port);
727 } else {
728 usb_log_debug("over current condition was "
729 "auto-resolved on port %d\n",
730 port);
[cd4b184]731 }
732 }
[e080332]733 //port reset
734 if (usb_port_reset_completed(&status)) {
[fbefd0e]735 usb_log_debug("port reset complete\n");
[e080332]736 if (usb_port_enabled(&status)) {
[195890b]737 usb_hub_finalize_add_device(hub, port,
738 usb_port_speed(&status));
[e080332]739 } else {
[195890b]740 usb_log_warning("port reset, but port still not "
741 "enabled\n");
[e080332]742 }
743 }
[195890b]744 usb_log_debug("status x%x : %d\n ", status, status);
[e080332]745
746 usb_port_set_connect_change(&status, false);
747 usb_port_set_reset(&status, false);
748 usb_port_set_reset_completed(&status, false);
749 usb_port_set_dev_connected(&status, false);
[195890b]750 if (status >> 16) {
[09daa8b]751 usb_log_info("there was some unsupported change on port %d: %X\n",
[195890b]752 port, status);
[f40a1e2]753
[e080332]754 }
755}
756
[6c399765]757static int initialize_non_removable(usb_hub_info_t * hub_info,
[195890b]758 unsigned int port) {
[6c399765]759 int opResult;
760 usb_log_debug("there is not pluged in non-removable device on "
[195890b]761 "port %d\n", port
[6c399765]762 );
763 //usb_hub_init_add_device(hub_info, port, usb_port_speed(&status));
764 usb_port_status_t status;
765 size_t rcvd_size;
766 usb_device_request_setup_packet_t request;
767 //int opResult;
768 usb_hub_set_port_status_request(&request, port);
769 //endpoint 0
770
771 opResult = usb_pipe_control_read(
[195890b]772 hub_info->control_pipe,
773 &request, sizeof (usb_device_request_setup_packet_t),
774 &status, 4, &rcvd_size
775 );
[6c399765]776 if (opResult != EOK) {
[195890b]777 usb_log_error("could not get port status %d\n", opResult);
[6c399765]778 return opResult;
779 }
780 if (rcvd_size != sizeof (usb_port_status_t)) {
781 usb_log_error("received status has incorrect size\n");
782 return opResult;
783 }
[195890b]784 usb_log_debug("port status %d, x%x\n", status, status);
785 if (usb_port_dev_connected(&status)) {
[6c399765]786 usb_log_debug("there is connected device on this port\n");
787 }
[195890b]788 if (!hub_info->is_default_address_used)
789 usb_hub_init_add_device(hub_info, port,
790 usb_port_speed(&status));
[6c399765]791 return opResult;
792}
793
[f40a1e2]794/**
[df3ad97]795 * check changes on hub
796 *
797 * Handles changes on each port with a status change.
798 * @param hub_info hub representation
799 * @return error code
[e080332]800 */
[195890b]801int usb_hub_check_hub_changes(usb_hub_info_t * hub_info) {
[cd4b184]802 int opResult;
[3954a63b]803 opResult = usb_pipe_start_session(
[195890b]804 hub_info->status_change_pipe);
805 //this might not be necessary - if all non-removables are ok, it is
806 //not needed here
[6c399765]807 opResult = usb_pipe_start_session(hub_info->control_pipe);
[195890b]808 if (opResult != EOK) {
[09daa8b]809 usb_log_error("could not initialize communication for hub; %d\n",
[195890b]810 opResult);
[42a3a57]811 return opResult;
[cd4b184]812 }
813
814 size_t port_count = hub_info->port_count;
[6c399765]815 //first check non-removable devices
816 {
[195890b]817 unsigned int port;
818 for (port = 1; port <= port_count; ++port) {
819 bool is_non_removable =
820 hub_info->not_initialized_non_removables[port/8]
821 & (1 << (port % 8));
822 if (is_non_removable) {
823 opResult = initialize_non_removable(hub_info,
824 port);
825 }
[6c399765]826 }
827 }
828
[e080332]829
[cd4b184]830 /// FIXME: count properly
[195890b]831 size_t byte_length = ((port_count + 1) / 8) + 1;
832 void *change_bitmap = malloc(byte_length);
[cd4b184]833 size_t actual_size;
[e080332]834
[cd4b184]835 /*
836 * Send the request.
837 */
[3954a63b]838 opResult = usb_pipe_read(
[195890b]839 hub_info->status_change_pipe,
840 change_bitmap, byte_length, &actual_size
841 );
[e080332]842
[cd4b184]843 if (opResult != EOK) {
[5097bed4]844 free(change_bitmap);
[195890b]845 usb_log_warning("something went wrong while getting the"
846 "status of hub\n");
[3954a63b]847 usb_pipe_end_session(hub_info->status_change_pipe);
[42a3a57]848 return opResult;
[cd4b184]849 }
850 unsigned int port;
[195890b]851
852 if (opResult != EOK) {
853 usb_log_error("could not start control pipe session %d\n",
854 opResult);
[3954a63b]855 usb_pipe_end_session(hub_info->status_change_pipe);
[42a3a57]856 return opResult;
[dff940f8]857 }
858 opResult = usb_hc_connection_open(&hub_info->connection);
[195890b]859 if (opResult != EOK) {
[09daa8b]860 usb_log_error("could not start host controller session %d\n",
[195890b]861 opResult);
[3954a63b]862 usb_pipe_end_session(hub_info->control_pipe);
863 usb_pipe_end_session(hub_info->status_change_pipe);
[42a3a57]864 return opResult;
[dff940f8]865 }
[cd4b184]866
867 ///todo, opresult check, pre obe konekce
[195890b]868 for (port = 1; port < port_count + 1; ++port) {
[cd4b184]869 bool interrupt =
[195890b]870 (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
[cd4b184]871 if (interrupt) {
872 usb_hub_process_interrupt(
[195890b]873 hub_info, port);
[cd4b184]874 }
875 }
876 usb_hc_connection_close(&hub_info->connection);
[3954a63b]877 usb_pipe_end_session(hub_info->control_pipe);
878 usb_pipe_end_session(hub_info->status_change_pipe);
[cd4b184]879 free(change_bitmap);
[42a3a57]880 return EOK;
[cd4b184]881}
[e080332]882
883
884
885/**
886 * @}
[71ed4849]887 */
Note: See TracBrowser for help on using the repository browser.