diff options
Diffstat (limited to 'firmware/usbstack/usb_core.c')
-rw-r--r-- | firmware/usbstack/usb_core.c | 148 |
1 files changed, 127 insertions, 21 deletions
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 9ece4fc796..9afaf5c336 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "thread.h" | 22 | #include "thread.h" |
23 | #include "kernel.h" | 23 | #include "kernel.h" |
24 | #include "string.h" | 24 | #include "string.h" |
25 | #include "panic.h" | ||
25 | /*#define LOGF_ENABLE*/ | 26 | /*#define LOGF_ENABLE*/ |
26 | #include "logf.h" | 27 | #include "logf.h" |
27 | 28 | ||
@@ -262,6 +263,13 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] = | |||
262 | #endif | 263 | #endif |
263 | }; | 264 | }; |
264 | 265 | ||
266 | #ifdef USB_LEGACY_CONTROL_API | ||
267 | static struct usb_ctrlrequest active_request_buf; | ||
268 | static struct usb_ctrlrequest* active_request = NULL; | ||
269 | static void* control_write_data = NULL; | ||
270 | static bool control_write_data_done = false; | ||
271 | #endif | ||
272 | |||
265 | static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void* reqdata); | 273 | static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void* reqdata); |
266 | 274 | ||
267 | static unsigned char response_data[256] USB_DEVBSS_ATTR; | 275 | static unsigned char response_data[256] USB_DEVBSS_ATTR; |
@@ -940,26 +948,29 @@ void usb_core_bus_reset(void) | |||
940 | /* called by usb_drv_transfer_completed() */ | 948 | /* called by usb_drv_transfer_completed() */ |
941 | void usb_core_transfer_complete(int endpoint, int dir, int status, int length) | 949 | void usb_core_transfer_complete(int endpoint, int dir, int status, int length) |
942 | { | 950 | { |
943 | struct usb_transfer_completion_event_data *completion_event; | 951 | struct usb_transfer_completion_event_data* completion_event = |
944 | 952 | &ep_data[endpoint].completion_event[EP_DIR(dir)]; | |
945 | switch (endpoint) { | ||
946 | case EP_CONTROL: | ||
947 | /* already handled */ | ||
948 | break; | ||
949 | 953 | ||
950 | default: | 954 | completion_event->endpoint = endpoint; |
951 | completion_event = &ep_data[endpoint].completion_event[EP_DIR(dir)]; | 955 | completion_event->dir = dir; |
952 | 956 | completion_event->data[0] = NULL; | |
953 | completion_event->endpoint = endpoint; | 957 | completion_event->data[1] = NULL; |
954 | completion_event->dir = dir; | 958 | completion_event->status = status; |
955 | completion_event->data[0] = NULL; | 959 | completion_event->length = length; |
956 | completion_event->data[1] = NULL; | 960 | |
957 | completion_event->status = status; | 961 | #ifdef USB_LEGACY_CONTROL_API |
958 | completion_event->length = length; | 962 | if(endpoint == EP_CONTROL) { |
959 | /* All other endpoints. Let the thread deal with it */ | 963 | if(dir == USB_DIR_OUT && active_request && control_write_data_done) { |
960 | usb_signal_transfer_completion(completion_event); | 964 | completion_event->data[0] = active_request; |
961 | break; | 965 | if(control_write_data_done && dir == USB_DIR_OUT) |
966 | completion_event->data[1] = control_write_data; | ||
967 | } else { | ||
968 | return; | ||
969 | } | ||
962 | } | 970 | } |
971 | #endif | ||
972 | |||
973 | usb_signal_transfer_completion(completion_event); | ||
963 | } | 974 | } |
964 | 975 | ||
965 | void usb_core_handle_notify(long id, intptr_t data) | 976 | void usb_core_handle_notify(long id, intptr_t data) |
@@ -977,8 +988,7 @@ void usb_core_handle_notify(long id, intptr_t data) | |||
977 | } | 988 | } |
978 | } | 989 | } |
979 | 990 | ||
980 | /* called by usb_drv_int() */ | 991 | void usb_core_control_request(struct usb_ctrlrequest* req, void* reqdata) |
981 | void usb_core_legacy_control_request(struct usb_ctrlrequest* req) | ||
982 | { | 992 | { |
983 | struct usb_transfer_completion_event_data* completion_event = | 993 | struct usb_transfer_completion_event_data* completion_event = |
984 | &ep_data[EP_CONTROL].completion_event[EP_DIR(USB_DIR_IN)]; | 994 | &ep_data[EP_CONTROL].completion_event[EP_DIR(USB_DIR_IN)]; |
@@ -986,13 +996,109 @@ void usb_core_legacy_control_request(struct usb_ctrlrequest* req) | |||
986 | completion_event->endpoint = EP_CONTROL; | 996 | completion_event->endpoint = EP_CONTROL; |
987 | completion_event->dir = 0; | 997 | completion_event->dir = 0; |
988 | completion_event->data[0] = (void*)req; | 998 | completion_event->data[0] = (void*)req; |
989 | completion_event->data[1] = NULL; | 999 | completion_event->data[1] = reqdata; |
990 | completion_event->status = 0; | 1000 | completion_event->status = 0; |
991 | completion_event->length = 0; | 1001 | completion_event->length = 0; |
992 | logf("ctrl received %ld, req=0x%x", current_tick, req->bRequest); | 1002 | logf("ctrl received %ld, req=0x%x", current_tick, req->bRequest); |
993 | usb_signal_transfer_completion(completion_event); | 1003 | usb_signal_transfer_completion(completion_event); |
994 | } | 1004 | } |
995 | 1005 | ||
1006 | void usb_core_control_complete(int status) | ||
1007 | { | ||
1008 | /* We currently don't use this, it's here to make the API look good ;) | ||
1009 | * It makes sense to #define it away on normal builds. | ||
1010 | */ | ||
1011 | (void)status; | ||
1012 | logf("ctrl complete %ld, %d", current_tick, status); | ||
1013 | } | ||
1014 | |||
1015 | #ifdef USB_LEGACY_CONTROL_API | ||
1016 | /* Only needed if the driver does not support the new API yet */ | ||
1017 | void usb_core_legacy_control_request(struct usb_ctrlrequest* req) | ||
1018 | { | ||
1019 | memcpy(&active_request_buf, req, sizeof(*req)); | ||
1020 | active_request = &active_request_buf; | ||
1021 | control_write_data = NULL; | ||
1022 | control_write_data_done = false; | ||
1023 | |||
1024 | usb_core_control_request(req, NULL); | ||
1025 | } | ||
1026 | |||
1027 | void usb_drv_control_response(enum usb_control_response resp, | ||
1028 | void* data, int length) | ||
1029 | { | ||
1030 | if(!active_request) | ||
1031 | panicf("null ctrl req"); | ||
1032 | |||
1033 | if(active_request->wLength == 0) | ||
1034 | { | ||
1035 | active_request = NULL; | ||
1036 | |||
1037 | /* No-data request */ | ||
1038 | if(resp == USB_CONTROL_ACK) | ||
1039 | usb_drv_send(EP_CONTROL, data, length); | ||
1040 | else if(resp == USB_CONTROL_STALL) | ||
1041 | usb_drv_stall(EP_CONTROL, true, true); | ||
1042 | else | ||
1043 | panicf("RECEIVE on non-data req"); | ||
1044 | } | ||
1045 | else if(active_request->bRequestType & USB_DIR_IN) | ||
1046 | { | ||
1047 | /* Control read request */ | ||
1048 | if(resp == USB_CONTROL_ACK) | ||
1049 | { | ||
1050 | active_request = NULL; | ||
1051 | usb_drv_recv_nonblocking(EP_CONTROL, NULL, 0); | ||
1052 | usb_drv_send(EP_CONTROL, data, length); | ||
1053 | } | ||
1054 | else if(resp == USB_CONTROL_STALL) | ||
1055 | { | ||
1056 | active_request = NULL; | ||
1057 | usb_drv_stall(EP_CONTROL, true, true); | ||
1058 | } | ||
1059 | else | ||
1060 | { | ||
1061 | panicf("RECEIVE on ctrl read req"); | ||
1062 | } | ||
1063 | } | ||
1064 | else if(!control_write_data_done) | ||
1065 | { | ||
1066 | /* Control write request, data phase */ | ||
1067 | if(resp == USB_CONTROL_RECEIVE) | ||
1068 | { | ||
1069 | control_write_data = data; | ||
1070 | control_write_data_done = true; | ||
1071 | usb_drv_recv_nonblocking(EP_CONTROL, data, length); | ||
1072 | } | ||
1073 | else if(resp == USB_CONTROL_STALL) | ||
1074 | { | ||
1075 | /* We should stall the OUT endpoint here, but the old code did | ||
1076 | * not do so and some drivers may not handle it correctly. */ | ||
1077 | active_request = NULL; | ||
1078 | usb_drv_stall(EP_CONTROL, true, true); | ||
1079 | } | ||
1080 | else | ||
1081 | { | ||
1082 | panicf("ACK on ctrl write data"); | ||
1083 | } | ||
1084 | } | ||
1085 | else | ||
1086 | { | ||
1087 | active_request = NULL; | ||
1088 | control_write_data = NULL; | ||
1089 | control_write_data_done = false; | ||
1090 | |||
1091 | /* Control write request, status phase */ | ||
1092 | if(resp == USB_CONTROL_ACK) | ||
1093 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
1094 | else if(resp == USB_CONTROL_STALL) | ||
1095 | usb_drv_stall(EP_CONTROL, true, true); | ||
1096 | else | ||
1097 | panicf("RECEIVE on ctrl write status"); | ||
1098 | } | ||
1099 | } | ||
1100 | #endif | ||
1101 | |||
996 | void usb_core_notify_set_address(uint8_t addr) | 1102 | void usb_core_notify_set_address(uint8_t addr) |
997 | { | 1103 | { |
998 | logf("notify set addr received %ld", current_tick); | 1104 | logf("notify set addr received %ld", current_tick); |