diff options
Diffstat (limited to 'drivers/usb/chipidea/udc.c')
-rw-r--r-- | drivers/usb/chipidea/udc.c | 324 |
1 files changed, 160 insertions, 164 deletions
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 4ab2cb62dfce..7739c64ef259 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c | |||
@@ -178,19 +178,6 @@ static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir) | |||
178 | } | 178 | } |
179 | 179 | ||
180 | /** | 180 | /** |
181 | * hw_test_and_clear_setup_status: test & clear setup status (execute without | ||
182 | * interruption) | ||
183 | * @n: endpoint number | ||
184 | * | ||
185 | * This function returns setup status | ||
186 | */ | ||
187 | static int hw_test_and_clear_setup_status(struct ci_hdrc *ci, int n) | ||
188 | { | ||
189 | n = ep_to_bit(ci, n); | ||
190 | return hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(n)); | ||
191 | } | ||
192 | |||
193 | /** | ||
194 | * hw_ep_prime: primes endpoint (execute without interruption) | 181 | * hw_ep_prime: primes endpoint (execute without interruption) |
195 | * @num: endpoint number | 182 | * @num: endpoint number |
196 | * @dir: endpoint direction | 183 | * @dir: endpoint direction |
@@ -962,6 +949,156 @@ __acquires(hwep->lock) | |||
962 | } | 949 | } |
963 | 950 | ||
964 | /** | 951 | /** |
952 | * isr_setup_packet_handler: setup packet handler | ||
953 | * @ci: UDC descriptor | ||
954 | * | ||
955 | * This function handles setup packet | ||
956 | */ | ||
957 | static void isr_setup_packet_handler(struct ci_hdrc *ci) | ||
958 | __releases(ci->lock) | ||
959 | __acquires(ci->lock) | ||
960 | { | ||
961 | struct ci_hw_ep *hwep = &ci->ci_hw_ep[0]; | ||
962 | struct usb_ctrlrequest req; | ||
963 | int type, num, dir, err = -EINVAL; | ||
964 | u8 tmode = 0; | ||
965 | |||
966 | /* | ||
967 | * Flush data and handshake transactions of previous | ||
968 | * setup packet. | ||
969 | */ | ||
970 | _ep_nuke(ci->ep0out); | ||
971 | _ep_nuke(ci->ep0in); | ||
972 | |||
973 | /* read_setup_packet */ | ||
974 | do { | ||
975 | hw_test_and_set_setup_guard(ci); | ||
976 | memcpy(&req, &hwep->qh.ptr->setup, sizeof(req)); | ||
977 | } while (!hw_test_and_clear_setup_guard(ci)); | ||
978 | |||
979 | type = req.bRequestType; | ||
980 | |||
981 | ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX; | ||
982 | |||
983 | switch (req.bRequest) { | ||
984 | case USB_REQ_CLEAR_FEATURE: | ||
985 | if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && | ||
986 | le16_to_cpu(req.wValue) == | ||
987 | USB_ENDPOINT_HALT) { | ||
988 | if (req.wLength != 0) | ||
989 | break; | ||
990 | num = le16_to_cpu(req.wIndex); | ||
991 | dir = num & USB_ENDPOINT_DIR_MASK; | ||
992 | num &= USB_ENDPOINT_NUMBER_MASK; | ||
993 | if (dir) /* TX */ | ||
994 | num += ci->hw_ep_max / 2; | ||
995 | if (!ci->ci_hw_ep[num].wedge) { | ||
996 | spin_unlock(&ci->lock); | ||
997 | err = usb_ep_clear_halt( | ||
998 | &ci->ci_hw_ep[num].ep); | ||
999 | spin_lock(&ci->lock); | ||
1000 | if (err) | ||
1001 | break; | ||
1002 | } | ||
1003 | err = isr_setup_status_phase(ci); | ||
1004 | } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && | ||
1005 | le16_to_cpu(req.wValue) == | ||
1006 | USB_DEVICE_REMOTE_WAKEUP) { | ||
1007 | if (req.wLength != 0) | ||
1008 | break; | ||
1009 | ci->remote_wakeup = 0; | ||
1010 | err = isr_setup_status_phase(ci); | ||
1011 | } else { | ||
1012 | goto delegate; | ||
1013 | } | ||
1014 | break; | ||
1015 | case USB_REQ_GET_STATUS: | ||
1016 | if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && | ||
1017 | type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && | ||
1018 | type != (USB_DIR_IN|USB_RECIP_INTERFACE)) | ||
1019 | goto delegate; | ||
1020 | if (le16_to_cpu(req.wLength) != 2 || | ||
1021 | le16_to_cpu(req.wValue) != 0) | ||
1022 | break; | ||
1023 | err = isr_get_status_response(ci, &req); | ||
1024 | break; | ||
1025 | case USB_REQ_SET_ADDRESS: | ||
1026 | if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) | ||
1027 | goto delegate; | ||
1028 | if (le16_to_cpu(req.wLength) != 0 || | ||
1029 | le16_to_cpu(req.wIndex) != 0) | ||
1030 | break; | ||
1031 | ci->address = (u8)le16_to_cpu(req.wValue); | ||
1032 | ci->setaddr = true; | ||
1033 | err = isr_setup_status_phase(ci); | ||
1034 | break; | ||
1035 | case USB_REQ_SET_FEATURE: | ||
1036 | if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && | ||
1037 | le16_to_cpu(req.wValue) == | ||
1038 | USB_ENDPOINT_HALT) { | ||
1039 | if (req.wLength != 0) | ||
1040 | break; | ||
1041 | num = le16_to_cpu(req.wIndex); | ||
1042 | dir = num & USB_ENDPOINT_DIR_MASK; | ||
1043 | num &= USB_ENDPOINT_NUMBER_MASK; | ||
1044 | if (dir) /* TX */ | ||
1045 | num += ci->hw_ep_max / 2; | ||
1046 | |||
1047 | spin_unlock(&ci->lock); | ||
1048 | err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep); | ||
1049 | spin_lock(&ci->lock); | ||
1050 | if (!err) | ||
1051 | isr_setup_status_phase(ci); | ||
1052 | } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { | ||
1053 | if (req.wLength != 0) | ||
1054 | break; | ||
1055 | switch (le16_to_cpu(req.wValue)) { | ||
1056 | case USB_DEVICE_REMOTE_WAKEUP: | ||
1057 | ci->remote_wakeup = 1; | ||
1058 | err = isr_setup_status_phase(ci); | ||
1059 | break; | ||
1060 | case USB_DEVICE_TEST_MODE: | ||
1061 | tmode = le16_to_cpu(req.wIndex) >> 8; | ||
1062 | switch (tmode) { | ||
1063 | case TEST_J: | ||
1064 | case TEST_K: | ||
1065 | case TEST_SE0_NAK: | ||
1066 | case TEST_PACKET: | ||
1067 | case TEST_FORCE_EN: | ||
1068 | ci->test_mode = tmode; | ||
1069 | err = isr_setup_status_phase( | ||
1070 | ci); | ||
1071 | break; | ||
1072 | default: | ||
1073 | break; | ||
1074 | } | ||
1075 | default: | ||
1076 | goto delegate; | ||
1077 | } | ||
1078 | } else { | ||
1079 | goto delegate; | ||
1080 | } | ||
1081 | break; | ||
1082 | default: | ||
1083 | delegate: | ||
1084 | if (req.wLength == 0) /* no data phase */ | ||
1085 | ci->ep0_dir = TX; | ||
1086 | |||
1087 | spin_unlock(&ci->lock); | ||
1088 | err = ci->driver->setup(&ci->gadget, &req); | ||
1089 | spin_lock(&ci->lock); | ||
1090 | break; | ||
1091 | } | ||
1092 | |||
1093 | if (err < 0) { | ||
1094 | spin_unlock(&ci->lock); | ||
1095 | if (usb_ep_set_halt(&hwep->ep)) | ||
1096 | dev_err(ci->dev, "error: ep_set_halt\n"); | ||
1097 | spin_lock(&ci->lock); | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | /** | ||
965 | * isr_tr_complete_handler: transaction complete interrupt handler | 1102 | * isr_tr_complete_handler: transaction complete interrupt handler |
966 | * @ci: UDC descriptor | 1103 | * @ci: UDC descriptor |
967 | * | 1104 | * |
@@ -972,12 +1109,10 @@ __releases(ci->lock) | |||
972 | __acquires(ci->lock) | 1109 | __acquires(ci->lock) |
973 | { | 1110 | { |
974 | unsigned i; | 1111 | unsigned i; |
975 | u8 tmode = 0; | 1112 | int err; |
976 | 1113 | ||
977 | for (i = 0; i < ci->hw_ep_max; i++) { | 1114 | for (i = 0; i < ci->hw_ep_max; i++) { |
978 | struct ci_hw_ep *hwep = &ci->ci_hw_ep[i]; | 1115 | struct ci_hw_ep *hwep = &ci->ci_hw_ep[i]; |
979 | int type, num, dir, err = -EINVAL; | ||
980 | struct usb_ctrlrequest req; | ||
981 | 1116 | ||
982 | if (hwep->ep.desc == NULL) | 1117 | if (hwep->ep.desc == NULL) |
983 | continue; /* not configured */ | 1118 | continue; /* not configured */ |
@@ -997,148 +1132,10 @@ __acquires(ci->lock) | |||
997 | } | 1132 | } |
998 | } | 1133 | } |
999 | 1134 | ||
1000 | if (hwep->type != USB_ENDPOINT_XFER_CONTROL || | 1135 | /* Only handle setup packet below */ |
1001 | !hw_test_and_clear_setup_status(ci, i)) | 1136 | if (i == 0 && |
1002 | continue; | 1137 | hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(0))) |
1003 | 1138 | isr_setup_packet_handler(ci); | |
1004 | if (i != 0) { | ||
1005 | dev_warn(ci->dev, "ctrl traffic at endpoint %d\n", i); | ||
1006 | continue; | ||
1007 | } | ||
1008 | |||
1009 | /* | ||
1010 | * Flush data and handshake transactions of previous | ||
1011 | * setup packet. | ||
1012 | */ | ||
1013 | _ep_nuke(ci->ep0out); | ||
1014 | _ep_nuke(ci->ep0in); | ||
1015 | |||
1016 | /* read_setup_packet */ | ||
1017 | do { | ||
1018 | hw_test_and_set_setup_guard(ci); | ||
1019 | memcpy(&req, &hwep->qh.ptr->setup, sizeof(req)); | ||
1020 | } while (!hw_test_and_clear_setup_guard(ci)); | ||
1021 | |||
1022 | type = req.bRequestType; | ||
1023 | |||
1024 | ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX; | ||
1025 | |||
1026 | switch (req.bRequest) { | ||
1027 | case USB_REQ_CLEAR_FEATURE: | ||
1028 | if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && | ||
1029 | le16_to_cpu(req.wValue) == | ||
1030 | USB_ENDPOINT_HALT) { | ||
1031 | if (req.wLength != 0) | ||
1032 | break; | ||
1033 | num = le16_to_cpu(req.wIndex); | ||
1034 | dir = num & USB_ENDPOINT_DIR_MASK; | ||
1035 | num &= USB_ENDPOINT_NUMBER_MASK; | ||
1036 | if (dir) /* TX */ | ||
1037 | num += ci->hw_ep_max/2; | ||
1038 | if (!ci->ci_hw_ep[num].wedge) { | ||
1039 | spin_unlock(&ci->lock); | ||
1040 | err = usb_ep_clear_halt( | ||
1041 | &ci->ci_hw_ep[num].ep); | ||
1042 | spin_lock(&ci->lock); | ||
1043 | if (err) | ||
1044 | break; | ||
1045 | } | ||
1046 | err = isr_setup_status_phase(ci); | ||
1047 | } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && | ||
1048 | le16_to_cpu(req.wValue) == | ||
1049 | USB_DEVICE_REMOTE_WAKEUP) { | ||
1050 | if (req.wLength != 0) | ||
1051 | break; | ||
1052 | ci->remote_wakeup = 0; | ||
1053 | err = isr_setup_status_phase(ci); | ||
1054 | } else { | ||
1055 | goto delegate; | ||
1056 | } | ||
1057 | break; | ||
1058 | case USB_REQ_GET_STATUS: | ||
1059 | if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && | ||
1060 | type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && | ||
1061 | type != (USB_DIR_IN|USB_RECIP_INTERFACE)) | ||
1062 | goto delegate; | ||
1063 | if (le16_to_cpu(req.wLength) != 2 || | ||
1064 | le16_to_cpu(req.wValue) != 0) | ||
1065 | break; | ||
1066 | err = isr_get_status_response(ci, &req); | ||
1067 | break; | ||
1068 | case USB_REQ_SET_ADDRESS: | ||
1069 | if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) | ||
1070 | goto delegate; | ||
1071 | if (le16_to_cpu(req.wLength) != 0 || | ||
1072 | le16_to_cpu(req.wIndex) != 0) | ||
1073 | break; | ||
1074 | ci->address = (u8)le16_to_cpu(req.wValue); | ||
1075 | ci->setaddr = true; | ||
1076 | err = isr_setup_status_phase(ci); | ||
1077 | break; | ||
1078 | case USB_REQ_SET_FEATURE: | ||
1079 | if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && | ||
1080 | le16_to_cpu(req.wValue) == | ||
1081 | USB_ENDPOINT_HALT) { | ||
1082 | if (req.wLength != 0) | ||
1083 | break; | ||
1084 | num = le16_to_cpu(req.wIndex); | ||
1085 | dir = num & USB_ENDPOINT_DIR_MASK; | ||
1086 | num &= USB_ENDPOINT_NUMBER_MASK; | ||
1087 | if (dir) /* TX */ | ||
1088 | num += ci->hw_ep_max/2; | ||
1089 | |||
1090 | spin_unlock(&ci->lock); | ||
1091 | err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep); | ||
1092 | spin_lock(&ci->lock); | ||
1093 | if (!err) | ||
1094 | isr_setup_status_phase(ci); | ||
1095 | } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { | ||
1096 | if (req.wLength != 0) | ||
1097 | break; | ||
1098 | switch (le16_to_cpu(req.wValue)) { | ||
1099 | case USB_DEVICE_REMOTE_WAKEUP: | ||
1100 | ci->remote_wakeup = 1; | ||
1101 | err = isr_setup_status_phase(ci); | ||
1102 | break; | ||
1103 | case USB_DEVICE_TEST_MODE: | ||
1104 | tmode = le16_to_cpu(req.wIndex) >> 8; | ||
1105 | switch (tmode) { | ||
1106 | case TEST_J: | ||
1107 | case TEST_K: | ||
1108 | case TEST_SE0_NAK: | ||
1109 | case TEST_PACKET: | ||
1110 | case TEST_FORCE_EN: | ||
1111 | ci->test_mode = tmode; | ||
1112 | err = isr_setup_status_phase( | ||
1113 | ci); | ||
1114 | break; | ||
1115 | default: | ||
1116 | break; | ||
1117 | } | ||
1118 | default: | ||
1119 | goto delegate; | ||
1120 | } | ||
1121 | } else { | ||
1122 | goto delegate; | ||
1123 | } | ||
1124 | break; | ||
1125 | default: | ||
1126 | delegate: | ||
1127 | if (req.wLength == 0) /* no data phase */ | ||
1128 | ci->ep0_dir = TX; | ||
1129 | |||
1130 | spin_unlock(&ci->lock); | ||
1131 | err = ci->driver->setup(&ci->gadget, &req); | ||
1132 | spin_lock(&ci->lock); | ||
1133 | break; | ||
1134 | } | ||
1135 | |||
1136 | if (err < 0) { | ||
1137 | spin_unlock(&ci->lock); | ||
1138 | if (usb_ep_set_halt(&hwep->ep)) | ||
1139 | dev_err(ci->dev, "error: ep_set_halt\n"); | ||
1140 | spin_lock(&ci->lock); | ||
1141 | } | ||
1142 | } | 1139 | } |
1143 | } | 1140 | } |
1144 | 1141 | ||
@@ -1193,6 +1190,11 @@ static int ep_enable(struct usb_ep *ep, | |||
1193 | 1190 | ||
1194 | hwep->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */ | 1191 | hwep->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */ |
1195 | 1192 | ||
1193 | if (hwep->num != 0 && hwep->type == USB_ENDPOINT_XFER_CONTROL) { | ||
1194 | dev_err(hwep->ci->dev, "Set control xfer at non-ep0\n"); | ||
1195 | retval = -EINVAL; | ||
1196 | } | ||
1197 | |||
1196 | /* | 1198 | /* |
1197 | * Enable endpoints in the HW other than ep0 as ep0 | 1199 | * Enable endpoints in the HW other than ep0 as ep0 |
1198 | * is always enabled | 1200 | * is always enabled |
@@ -1837,12 +1839,6 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) | |||
1837 | 1839 | ||
1838 | dma_pool_destroy(ci->td_pool); | 1840 | dma_pool_destroy(ci->td_pool); |
1839 | dma_pool_destroy(ci->qh_pool); | 1841 | dma_pool_destroy(ci->qh_pool); |
1840 | |||
1841 | if (ci->transceiver) { | ||
1842 | otg_set_peripheral(ci->transceiver->otg, NULL); | ||
1843 | if (ci->global_phy) | ||
1844 | usb_put_phy(ci->transceiver); | ||
1845 | } | ||
1846 | } | 1842 | } |
1847 | 1843 | ||
1848 | static int udc_id_switch_for_device(struct ci_hdrc *ci) | 1844 | static int udc_id_switch_for_device(struct ci_hdrc *ci) |