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

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

some code unmessing

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