source: mainline/uspace/drv/usbhub/usbhub.c@ 9d06563

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

fix for non-removables #4

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