Changeset 3e490eb in mainline for uspace/drv/usbhub/usbhub.c
- Timestamp:
- 2011-04-09T08:19:55Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 8961c22
- Parents:
- 36cd378
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/usbhub/usbhub.c
r36cd378 r3e490eb 37 37 #include <errno.h> 38 38 #include <str_error.h> 39 #include <inttypes.h> 39 40 40 41 #include <usb_iface.h> … … 54 55 55 56 56 static int usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port, 57 usb_speed_t speed); 57 /** Information for fibril for device discovery. */ 58 struct add_device_phase1 { 59 usb_hub_info_t *hub; 60 size_t port; 61 usb_speed_t speed; 62 }; 63 58 64 59 65 static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev); … … 65 71 static int usb_hub_release_default_address(usb_hub_info_t * hub); 66 72 67 static int usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,68 usb_speed_t speed);69 70 static void usb_hub_finalize_add_device(usb_hub_info_t * hub,71 uint16_t port, usb_speed_t speed);73 //static int usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port, 74 // usb_speed_t speed); 75 76 //static void usb_hub_finalize_add_device(usb_hub_info_t * hub, 77 // uint16_t port, usb_speed_t speed); 72 78 73 79 static void usb_hub_removed_device( … … 77 83 uint16_t port, uint32_t status); 78 84 85 static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port, 86 usb_port_status_t *status); 87 88 static int enable_port_callback(int port_no, void *arg); 89 90 static int add_device_phase1_worker_fibril(void *arg); 91 92 static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port, 93 usb_speed_t speed); 94 79 95 static void usb_hub_process_interrupt(usb_hub_info_t * hub, 80 96 uint16_t port); … … 91 107 // unsigned int port); 92 108 93 static int usb_hub_trigger_connecting_non_removable_devices(94 usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor);109 //static int usb_hub_trigger_connecting_non_removable_devices( 110 // usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor); 95 111 96 112 … … 104 120 * @return zero 105 121 */ 122 /* 106 123 int usb_hub_control_loop(void * hub_info_param) { 107 124 usb_hub_info_t * hub_info = (usb_hub_info_t*) hub_info_param; … … 117 134 return 0; 118 135 } 136 */ 119 137 /// \TODO malloc checking 120 138 … … 183 201 assert(rc == EOK); 184 202 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"); 203 /* 204 * The processing will require opened control pipe and connection 205 * to the host controller. 206 * It is waste of resources but let's hope there will be less 207 * hubs than the phone limit. 208 * FIXME: with some proper locking over pipes and session 209 * auto destruction, this could work better. 210 */ 211 rc = usb_pipe_start_session(&usb_dev->ctrl_pipe); 212 if (rc != EOK) { 213 usb_log_error("Failed to start session on control pipe: %s.\n", 214 str_error(rc)); 215 goto leave; 216 } 217 rc = usb_hc_connection_open(&hub_info->connection); 218 if (rc != EOK) { 219 usb_pipe_end_session(&usb_dev->ctrl_pipe); 220 usb_log_error("Failed to open connection to HC: %s.\n", 221 str_error(rc)); 222 goto leave; 223 } 224 225 rc = usb_device_auto_poll(hub_info->usb_device, 0, 226 hub_port_changes_callback, ((hub_info->port_count+1) / 8) + 1, 227 NULL, hub_info); 228 if (rc != EOK) { 229 usb_log_error("Failed to create polling fibril: %s.\n", 230 str_error(rc)); 231 free(hub_info); 232 return rc; 233 } 194 234 195 235 usb_log_info("Controlling hub `%s' (%d ports).\n", 196 236 hub_info->usb_device->ddf_dev->name, hub_info->port_count); 197 237 return EOK; 238 leave: 239 free(hub_info); 240 241 return rc; 198 242 } 199 243 … … 204 248 // 205 249 //********************************************* 250 251 252 /** Callback for polling hub for port changes. 253 * 254 * @param dev Device where the change occured. 255 * @param change_bitmap Bitmap of changed ports. 256 * @param change_bitmap_size Size of the bitmap in bytes. 257 * @param arg Custom argument, points to @c usb_hub_info_t. 258 * @return Whether to continue polling. 259 */ 260 bool hub_port_changes_callback(usb_device_t *dev, 261 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) 262 { 263 usb_hub_info_t *hub = (usb_hub_info_t *) arg; 264 265 /* FIXME: check that we received enough bytes. */ 266 if (change_bitmap_size == 0) { 267 goto leave; 268 } 269 270 size_t port; 271 for (port = 1; port < hub->port_count + 1; port++) { 272 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2; 273 if (change) { 274 usb_hub_process_interrupt(hub, port); 275 } 276 } 277 278 279 leave: 280 /* FIXME: proper interval. */ 281 async_usleep(1000 * 1000 * 10 ); 282 283 return true; 284 } 285 206 286 207 287 /** … … 378 458 hub_info->port_count = descriptor->ports_count; 379 459 /// \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 460 //hub_info->attached_devs = (usb_hc_attached_device_t*) 461 // malloc((hub_info->port_count + 1) * 462 // sizeof (usb_hc_attached_device_t) 463 // ); 464 hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1)); 465 size_t port; 466 for (port = 0; port < hub_info->port_count + 1; port++) { 467 usb_hub_port_init(&hub_info->ports[port]); 396 468 } 397 469 //handle non-removable devices 398 usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor);470 //usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor); 399 471 usb_log_debug2("freeing data\n"); 400 472 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) / 8407 );408 */409 473 free(descriptor->devices_removable); 410 474 free(descriptor); … … 470 534 } 471 535 536 #if 0 472 537 /** 473 538 * Reset the port with new device and reserve the default address. … … 517 582 return opResult; 518 583 } 519 584 #endif 585 586 #if 0 520 587 /** 521 588 * Finalize adding new device after port reset … … 611 678 new_device_address, child_handle); 612 679 } 680 #endif 613 681 614 682 /** … … 634 702 635 703 //close address 636 if (hub->attached_devs[port].address != 0) { 704 //if (hub->attached_devs[port].address != 0) { 705 if(hub->ports[port].attached_device.address >= 0){ 637 706 /*uncomment this code to use it when DDF allows device removal 638 707 opResult = usb_hc_unregister_device( … … 684 753 } 685 754 755 /** Retrieve port status. 756 * 757 * @param[in] ctrl_pipe Control pipe to use. 758 * @param[in] port Port number (starting at 1). 759 * @param[out] status Where to store the port status. 760 * @return Error code. 761 */ 762 static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port, 763 usb_port_status_t *status) 764 { 765 size_t recv_size; 766 usb_device_request_setup_packet_t request; 767 usb_port_status_t status_tmp; 768 769 usb_hub_set_port_status_request(&request, port); 770 int rc = usb_pipe_control_read(ctrl_pipe, 771 &request, sizeof(usb_device_request_setup_packet_t), 772 &status_tmp, sizeof(status_tmp), &recv_size); 773 if (rc != EOK) { 774 return rc; 775 } 776 777 if (recv_size != sizeof (status_tmp)) { 778 return ELIMIT; 779 } 780 781 if (status != NULL) { 782 *status = status_tmp; 783 } 784 785 return EOK; 786 } 787 788 /** Callback for enabling a specific port. 789 * 790 * We wait on a CV until port is reseted. 791 * That is announced via change on interrupt pipe. 792 * 793 * @param port_no Port number (starting at 1). 794 * @param arg Custom argument, points to @c usb_hub_info_t. 795 * @return Error code. 796 */ 797 static int enable_port_callback(int port_no, void *arg) 798 { 799 usb_hub_info_t *hub = (usb_hub_info_t *) arg; 800 int rc; 801 usb_device_request_setup_packet_t request; 802 usb_hub_port_t *my_port = hub->ports + port_no; 803 804 usb_hub_set_reset_port_request(&request, port_no); 805 rc = usb_pipe_control_write(hub->control_pipe, 806 &request, sizeof(request), NULL, 0); 807 if (rc != EOK) { 808 usb_log_warning("Port reset failed: %s.\n", str_error(rc)); 809 return rc; 810 } 811 812 /* 813 * Wait until reset completes. 814 */ 815 fibril_mutex_lock(&my_port->reset_mutex); 816 while (!my_port->reset_completed) { 817 fibril_condvar_wait(&my_port->reset_cv, &my_port->reset_mutex); 818 } 819 fibril_mutex_unlock(&my_port->reset_mutex); 820 821 /* Clear the port reset change. */ 822 rc = usb_hub_clear_port_feature(hub->control_pipe, 823 port_no, USB_HUB_FEATURE_C_PORT_RESET); 824 if (rc != EOK) { 825 usb_log_error("Failed to clear port %d reset feature: %s.\n", 826 port_no, str_error(rc)); 827 return rc; 828 } 829 830 return EOK; 831 } 832 833 /** Fibril for adding a new device. 834 * 835 * Separate fibril is needed because the port reset completion is announced 836 * via interrupt pipe and thus we cannot block here. 837 * 838 * @param arg Pointer to struct add_device_phase1. 839 * @return 0 Always. 840 */ 841 static int add_device_phase1_worker_fibril(void *arg) 842 { 843 struct add_device_phase1 *data 844 = (struct add_device_phase1 *) arg; 845 846 usb_address_t new_address; 847 devman_handle_t child_handle; 848 849 int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev, 850 &data->hub->connection, data->speed, 851 enable_port_callback, (int) data->port, data->hub, 852 &new_address, &child_handle, 853 NULL, NULL, NULL); 854 855 if (rc != EOK) { 856 usb_log_error("Failed registering device on port %zu: %s.\n", 857 data->port, str_error(rc)); 858 goto leave; 859 } 860 861 data->hub->ports[data->port].attached_device.handle = child_handle; 862 data->hub->ports[data->port].attached_device.address = new_address; 863 864 usb_log_info("Detected new device on `%s' (port %zu), " 865 "address %d (handle %" PRIun ").\n", 866 data->hub->usb_device->ddf_dev->name, data->port, 867 new_address, child_handle); 868 869 leave: 870 free(arg); 871 872 return EOK; 873 } 874 875 876 /** Start device adding when connection change is detected. 877 * 878 * This fires a new fibril to complete the device addition. 879 * 880 * @param hub Hub where the change occured. 881 * @param port Port index (starting at 1). 882 * @param speed Speed of the device. 883 * @return Error code. 884 */ 885 static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port, 886 usb_speed_t speed) 887 { 888 struct add_device_phase1 *data 889 = malloc(sizeof(struct add_device_phase1)); 890 if (data == NULL) { 891 return ENOMEM; 892 } 893 data->hub = hub; 894 data->port = port; 895 data->speed = speed; 896 897 usb_hub_port_t *the_port = hub->ports + port; 898 899 fibril_mutex_lock(&the_port->reset_mutex); 900 the_port->reset_completed = false; 901 fibril_mutex_unlock(&the_port->reset_mutex); 902 903 int rc = usb_hub_clear_port_feature(hub->control_pipe, port, 904 USB_HUB_FEATURE_C_PORT_CONNECTION); 905 if (rc != EOK) { 906 free(data); 907 usb_log_warning("Failed to clear port change flag: %s.\n", 908 str_error(rc)); 909 return rc; 910 } 911 912 fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data); 913 if (fibril == 0) { 914 free(data); 915 return ENOMEM; 916 } 917 fibril_add_ready(fibril); 918 919 return EOK; 920 } 921 922 686 923 /** 687 924 * Process interrupts on given hub port … … 695 932 usb_log_debug("interrupt at port %d\n", port); 696 933 //determine type of change 697 usb_pipe_t *pipe = hub->control_pipe;934 //usb_pipe_t *pipe = hub->control_pipe; 698 935 699 936 int opResult; 700 937 701 938 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"); 939 opResult = get_port_status(&hub->usb_device->ctrl_pipe, port, &status); 940 if (opResult != EOK) { 941 usb_log_error("Failed to get port %zu status: %s.\n", 942 port, str_error(opResult)); 715 943 return; 716 944 } 717 if (rcvd_size != sizeof (usb_port_status_t)) { 718 usb_log_error("received status has incorrect size\n"); 719 return; 720 } 945 721 946 //something connected/disconnected 947 /* 722 948 if (usb_port_connect_change(&status)) { 723 949 usb_log_debug("connection change on port\n"); … … 728 954 usb_hub_removed_device(hub, port); 729 955 } 956 }*/ 957 if (usb_port_connect_change(&status)) { 958 bool device_connected = usb_port_dev_connected(&status); 959 usb_log_debug("Connection change on port %zu: %s.\n", port, 960 device_connected ? "device attached" : "device removed"); 961 962 if (device_connected) { 963 opResult = add_device_phase1_new_fibril(hub, port, 964 usb_port_speed(&status)); 965 if (opResult != EOK) { 966 usb_log_error( 967 "Cannot handle change on port %zu: %s.\n", 968 str_error(opResult)); 969 } 970 } else { 971 usb_hub_removed_device(hub, port); 972 } 730 973 } 731 974 //over current … … 737 980 //port reset 738 981 if (usb_port_reset_completed(&status)) { 982 /* 739 983 usb_log_debug("port reset complete\n"); 740 984 if (usb_port_enabled(&status)) { … … 744 988 usb_log_warning("port reset, but port still not " 745 989 "enabled\n"); 990 } 991 * */ 992 usb_log_debug("Port %zu reset complete.\n", port); 993 if (usb_port_enabled(&status)) { 994 /* Finalize device adding. */ 995 usb_hub_port_t *the_port = hub->ports + port; 996 fibril_mutex_lock(&the_port->reset_mutex); 997 the_port->reset_completed = true; 998 fibril_condvar_broadcast(&the_port->reset_cv); 999 fibril_mutex_unlock(&the_port->reset_mutex); 1000 } else { 1001 usb_log_warning( 1002 "Port %zu reset complete but port not enabled.\n", 1003 port); 746 1004 } 747 1005 } … … 813 1071 } 814 1072 }else{//power reestablished on hub- restart ports 815 int port;1073 size_t port; 816 1074 for(port=0;port<hub_info->port_count;++port){ 817 1075 opResult = usb_hub_set_port_feature( … … 868 1126 } 869 1127 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 hub877 *878 * @param hub_info hub instance879 * @param port port number, counting from 1880 * @return error code881 */882 #if 0883 static 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", port888 );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 0896 897 opResult = usb_pipe_control_read(898 hub_info->control_pipe,899 &request, sizeof (usb_device_request_setup_packet_t),900 &status, 4, &rcvd_size901 );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 #endif923 /**924 * triggers actions to connect non0removable devices925 *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 representation929 * @param descriptor usb hub descriptor930 * @return error code931 */932 static 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 0943 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_size962 );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 port970 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_size979 );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 noticed993 //in driver loop994 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_size1003 );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_size1020 );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 #endif1033 1034 /// \TODO this is just a debug code1035 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 01047 opResult = usb_pipe_control_read(1048 hub->control_pipe,1049 &request,1050 sizeof (usb_device_request_setup_packet_t),1051 &status, 4, &rcvd_size1052 );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/disconnected1062 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 1128 1076 1129
Note:
See TracChangeset
for help on using the changeset viewer.